Skip to content

Commit

Permalink
execute docs
Browse files Browse the repository at this point in the history
  • Loading branch information
cancerberoSgx committed Nov 11, 2018
1 parent 94957e5 commit 15cd61d
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 45 deletions.
38 changes: 33 additions & 5 deletions spec/executeSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,23 @@ describe('execute', () => {

const { outputFiles } = await executeOne({
inputFiles: [img1],
commands: [['convert', 'holocaust.jpg', "-resize", "123x321!", 'resized.png']]
commands: [['convert', 'holocaust.jpg', '-resize', '123x321!', 'resized.png']]
})
info = await extractInfo(outputFiles[0])
expect(info[0].image.formatDescription.toLowerCase()).toBe('png')
expect(info[0].image.geometry.width).toBe(123)
expect(info[0].image.geometry.height).toBe(321)
done()
})

it('should support CLI like commands', async done => {
const img1 = await buildInputFile('holocaust.jpg')
const {outputFiles} = await executeOne({inputFiles: [img1], commands: ['convert holocaust.jpg -resize 444x76! output.gif']})
expect(outputFiles[0].name).toBe('output.gif')
let info = await extractInfo(outputFiles[0])
expect(info[0].image.formatDescription.toLowerCase()).toBe('gif')
expect(info[0].image.geometry.width).toBe(444)
expect(info[0].image.geometry.height).toBe(76)
done()
})
})
Expand All @@ -29,18 +39,36 @@ describe('execute', () => {
const result = await execute({
inputFiles: [await buildInputFile('fn.png', 'image1.png')],
commands: [
['convert', 'image1.png', "-rotate", "70", "image2.gif"],
// heads up: next command uses "image2.gif" which was the output of previous command:
["convert", "image2.gif", "-scale", '23%', 'image3.jpg'],
['convert', 'image1.png', '-rotate', '70', 'image2.gif'],
// heads up: next command uses 'image2.gif' which was the output of previous command:
['convert', 'image2.gif', '-scale', '23%', 'image3.jpg'],
]
})
const result2 = await executeOne({
inputFiles: [await buildInputFile('fn.png', 'image1.png')],
commands: [['convert', 'image1.png', "-rotate", "70", "-scale", '23%', "image2.gif"]]
commands: [['convert', 'image1.png', '-rotate', '70', '-scale', '23%', 'image2.gif']]
})
expect(await compare(result.outputFiles.find(f => f.name === 'image3.jpg'), result2.outputFiles[0])).toBe(true)
done()
})

it('supports CLI like commands', async done => {
const result = await execute({
inputFiles: [await buildInputFile('fn.png', 'image1.png')],
commands: [
'convert image1.png -rotate 70 image2.gif',
// heads up: next command uses 'image2.gif' which was the output of previous command:
'convert image2.gif -scale 23% image3.jpg',
]
})
const result2 = await executeOne({
inputFiles: [await buildInputFile('fn.png', 'image1.png')],
commands: ['convert image1.png -rotate 70 -scale 23% image2.gif']
})
expect(await compare(result.outputFiles.find(f => f.name === 'image3.jpg'), result2.outputFiles[0])).toBe(true)
done()
})
})

xit('event emitter', ()=>{})
})
28 changes: 25 additions & 3 deletions spec/util/htmlSpec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
import { buildInputFile, loadImageElement } from '../../src';
import { buildInputFile, loadImageElement, compare, execute } from '../../src';

describe('util/html', () => {

describe('loadImageElement', ()=>{

it('should display an input image in an html img element', async done => {
const fn = await buildInputFile('fn.png')
const img1 = await buildInputFile('fn.png')
const el = document.createElement('img')
document.body.appendChild(el)

expect(el.src).toBeFalsy()
await loadImageElement(fn, el)
await loadImageElement(img1, el)
expect(el.src).toBeTruthy()
expect('visually check in the browser').toBe('visually check in the browser')

const img2 = await buildInputFile(el.src, 'image2.png')

expect(await compare(img1, img2)).toBe(true)
done()
})

xit('should display an output image in an html img element', async done => {
// const result = execute({inputFiles: [await buildInputFile('fn.png')], commands :[ 'convert fn.png -rotate 90 out.git'])

// const el = document.createElement('img')
// document.body.appendChild(el)

// expect(el.src).toBeFalsy()
// await loadImageElement(img1, el)
// expect(el.src).toBeTruthy()
// expect('visually check in the browser').toBe('visually check in the browser')

// const img2 = await buildInputFile(el.src, 'image2.png')

// expect(await compare(img1, img2)).toBe(true)
done()
})
})
Expand Down
81 changes: 44 additions & 37 deletions src/execute.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import { MagickInputFile, MagickOutputFile } from './index';
import { Call } from './magickApi';
import { MagickInputFile, MagickOutputFile, outputFileToInputFile, Call, asCommand } from '.';
import pMap from 'p-map'

export type Command = (string|number)[]
export type Command = (string | number)[]

export interface ExecuteConfig {
inputFiles: MagickInputFile[]
commands: Command[]
/** commands could be array form like [['convert', 'foo.png', 'bar.gif']] or CLI form like ['convert foo.png bar.gif'] */
commands: Command[] | string[]
}
export interface ExecuteResult {
outputFiles: MagickOutputFile[]
}

/** execute first commad in given config */
/** execute first command in given config */
export async function executeOne(config: ExecuteConfig): Promise<ExecuteResult> {
const command = config.commands[0]
const command = asCommand(config.commands)[0]
let t0 = performance.now()
executeListeners.forEach(listener => listener.beforeExecute({ command , took: performance.now() - t0, id: t0 }))
const result = { outputFiles: await Call(config.inputFiles, command.map(c=>c+'')) }
executeListeners.forEach(listener => listener.afterExecute({ command , took: performance.now() - t0, id: t0 }))
// console.log('Executed: ' + JSON.stringify(command), 'Output files: ', result.outputFiles.map(f => f.name));
executeListeners.forEach(listener => listener.beforeExecute({ command, took: performance.now() - t0, id: t0 }))
const result = { outputFiles: await Call(config.inputFiles, command.map(c => c + '')) }
executeListeners.forEach(listener => listener.afterExecute({ command, took: performance.now() - t0, id: t0 }))
return result
}

// execute event emitter

export interface ExecuteEvent {
Expand All @@ -42,44 +43,50 @@ export function addExecuteListener(l: ExecuteListener) {
* Execute all commands in given config serially in order. Output files from a command become available as input files in next commands. The execution result will contain all generated outputFiles. If same file name is used later command output files will override previous ones. Example:
*
* ```ts
* const result = await execute({
* inputFiles: [image1],
* commands: [
* ['convert', 'image1.png', "-bordercolor", "#ffee44", "-background", "#eeff55", "+polaroid", "image2.png"],
* // heads up: next command uses "image2.png" which was the output of previous command:
* ["convert", "image2.png", "-fill", "#997711", "-tint", "55"],
* ]
* })
* ```
const {outputFiles} = await execute({
inputFiles: [await buildInputFile('fn.png', 'image1.png')],
commands: [
['convert', 'image1.png', "-bordercolor", "#ffee44", "-background", "#eeff55", "+polaroid", "image2.png"],
// heads up: next command uses "image2.png" which was the output of previous command:
["convert", "image2.png", "-fill", "#997711", "-tint", "55"],
]
})
```
*
* Alternatively it support CLI like command line instead of arrays:
*
* ```ts
const {outputFiles} = await execute({
inputFiles: [await buildInputFile('fn.png', 'image1.png')],
commands: [
'convert image1.png -rotate 70 image2.gif',
// heads up: next command uses 'image2.gif' which was the output of previous command:
'convert image2.gif -scale 23% image3.jpg',
]
})
```
*/

import pMap from 'p-map'
import { outputFileToInputFile } from './util/file';
// async function forEachSerial(arr: any[], f: (n: any)=>Promise<any>){
// await pMap(arr, async n=>{
// await f(n)
// }, {concurrency: 1})
// }
export async function execute(config: ExecuteConfig): Promise<ExecuteResult> {
const allOutputFiles: {[name: string]: MagickOutputFile} = {}
const allInputFiles : {[name: string]: MagickInputFile} = {}
config.inputFiles.forEach(f=>{
const allOutputFiles: { [name: string]: MagickOutputFile } = {}
const allInputFiles: { [name: string]: MagickInputFile } = {}
config.inputFiles.forEach(f => {
allInputFiles[f.name] = f
})
async function mapper(c: Command){
async function mapper(c: Command) {
const thisConfig = {
inputFiles: Object.keys(allInputFiles).map(name=>allInputFiles[name]),
inputFiles: Object.keys(allInputFiles).map(name => allInputFiles[name]),
commands: [c]
}
const result = await executeOne(thisConfig)
await pMap(result.outputFiles, async f=>{
allOutputFiles[f.name] = f
await pMap(result.outputFiles, async f => {
allOutputFiles[f.name] = f
const inputFile = await outputFileToInputFile(f)
allInputFiles[inputFile.name] = inputFile
allInputFiles[inputFile.name] = inputFile
})
}
await pMap(config.commands, mapper, {concurrency: 1})
const commands = asCommand(config.commands)
await pMap(commands, mapper, { concurrency: 1 })
return {
outputFiles: Object.keys(allOutputFiles).map(name=>allOutputFiles[name])
outputFiles: Object.keys(allOutputFiles).map(name => allOutputFiles[name])
}
}
14 changes: 14 additions & 0 deletions src/util/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,18 @@ export function cliToArray(s: string): Command {
.map(s => s === `\\(` ? `(` : s === `\\)` ? `)` : s)

return command
}


export function asCommand(c: Command[] | string[]): Command[] {
if (!c[0]) { return [] }
if(typeof c[0] === 'string'){
return (c as string[]) .map((subCommand: string) => cliToArray(subCommand))
console.log('if1', c);

}
console.log('if2', c);
return c as Command[]


}

0 comments on commit 15cd61d

Please sign in to comment.