Skip to content

Commit

Permalink
extractPixelColorUtility & more on interactive-execute-context
Browse files Browse the repository at this point in the history
  • Loading branch information
cancerberoSgx committed Nov 17, 2018
1 parent 85af9d3 commit 9e59e7a
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 20 deletions.
1 change: 1 addition & 0 deletions info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
white
50 changes: 36 additions & 14 deletions samples/interactive-execute-context/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import pMap from 'p-map';
import * as React from 'react';
import { style } from 'typestyle';
import { arrayToCli, asCommand, buildImageSrc, buildInputFile, cliToArray, Command, ExecutionContext, extractInfo, getBuiltInImages, getInputFilesFromHtmlInputElement, MagickFile, MagickInputFile } from 'wasm-imagemagick';
import {
arrayToCli, asCommand, buildImageSrc, buildInputFile, cliToArray, Command, ExecutionContext, extractInfo,
getBuiltInImages, getInputFilesFromHtmlInputElement, MagickFile, isImage, MagickInputFile, readFileAsText
} from 'wasm-imagemagick';
import { commandExamples, Example } from './commandExamples';
import { blobToString } from 'imagemagick-browser';

export interface AppProps {
context: ExecutionContext
Expand All @@ -23,6 +27,7 @@ export interface AppState {
stderr: string
exitCode: number
prettyJSON: boolean
isImageArray: boolean[]
}

export class App extends React.Component<AppProps, AppState> {
Expand All @@ -42,6 +47,7 @@ export class App extends React.Component<AppProps, AppState> {
stderr: '',
exitCode: 0,
prettyJSON: false,
isImageArray: []
}

protected styles = {
Expand Down Expand Up @@ -100,11 +106,18 @@ export class App extends React.Component<AppProps, AppState> {
<td>
<button data-image={f.name} onClick={this.removeImage.bind(this)}>remove</button>
</td>
<td>{(this.state.showImagesAndInfo || '') &&
<img alt={f.name} src={this.state.imgSrcs[i]}></img>}
<td>{
this.state.showImagesAndInfo && this.state.isImageArray[i] ?
<img alt={f.name} src={this.state.imgSrcs[i]}></img> :
this.state.showImagesAndInfo ?
<textarea className={this.styles.infoTextarea} value={this.state.imgSrcs[i]}></textarea> : ''
}
</td>
<td>{(this.state.showImagesAndInfo || '') &&
<textarea className={this.styles.infoTextarea} value={JSON.stringify(this.state.filesInfo[i][0].image, null, 2)}></textarea>}
<td>{(this.state.showImagesAndInfo && this.state.isImageArray[i]) ?
<textarea className={this.styles.infoTextarea} value={JSON.stringify(this.state.filesInfo[i][0].image, null, 2)}></textarea> :
this.state.showImagesAndInfo ?
<span>text file</span> :
''}
</td>
</tr>,
)}
Expand All @@ -130,10 +143,6 @@ export class App extends React.Component<AppProps, AppState> {
{commandExamples.map(t =>
<option>{t.name}</option>)}
</select>
{/* <select disabled={this.state.files.length === 0} onChange={this.selectExampleChange.bind(this)}>
{sampleCommandTemplates.map(t =>
<option>{t.name}</option>)}
</select> */}
</div>
</div>

Expand All @@ -145,7 +154,9 @@ export class App extends React.Component<AppProps, AppState> {
<p>Output Files (#{this.state.outputFiles.length}) </p>
{(this.state.outputFiles.length || '') && <ul>{this.state.outputFiles.map((f, i) =>
<li><div>{f.name}</div>
<img src={this.state.outputFileSrcs[i]}></img>
{this.state.isImageArray[this.state.files.findIndex(f2 => f2.name === f.name)] ?
<img src={this.state.outputFileSrcs[i]}></img> :
<textarea className={this.styles.infoTextarea} value={this.state.outputFileSrcs[i]}></textarea>}
</li>,
)}
</ul>}
Expand Down Expand Up @@ -233,10 +244,11 @@ export class App extends React.Component<AppProps, AppState> {

protected async updateImages() {
const files = await this.props.context.getAllFiles()
const imgSrcs = this.state.showImagesAndInfo ? await pMap(files, f => buildImageSrc(f, true)) : this.state.imgSrcs
const filesInfo = this.state.showImagesAndInfo ? await pMap(files, f => extractInfo(f)) : this.state.filesInfo
const outputFileSrcs = await pMap(this.state.outputFiles, f => buildImageSrc(f, true))
this.setState({ ...this.state, files, imgSrcs, outputFileSrcs, filesInfo })
const isImageArray = await pMap(files, isImage)
const imgSrcs = this.state.showImagesAndInfo ? await pMap(files, (f, i) => buildFileSrc(f, isImageArray[i])) : this.state.imgSrcs
const filesInfo = this.state.showImagesAndInfo ? await pMap(files, (f, i) => isImageArray[i] ? extractInfo(f) : undefined) : this.state.filesInfo
const outputFileSrcs = await pMap(this.state.outputFiles, (f, i) => buildFileSrc(f))
this.setState({ ...this.state, files, imgSrcs, outputFileSrcs, filesInfo, isImageArray })
}

protected async showImagesAndInfoChange(e: React.ChangeEvent<HTMLInputElement>) {
Expand All @@ -258,3 +270,13 @@ export class App extends React.Component<AppProps, AppState> {
}

}


async function buildFileSrc(file: MagickFile, isImage_?: boolean): Promise<string> {
if (typeof isImage_ === 'undefined' ? await isImage(file) : isImage_) {
return await buildImageSrc(file, true)
}
else {
return await readFileAsText(file)
}
}
21 changes: 21 additions & 0 deletions samples/interactive-execute-context/src/commandExamples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ export interface Example {
export const commandExamples: Example[] = [


{
name: 'identify simple',
description: `runs identify program to print to stdout image info`,
command: `identify rose:`.trim(),
},


{
name: 'extract pixel color',
description: `extract pixel color at 0,0 and save it to info.txt file`,
command: `convert logo: -format '%[pixel:p{0,0}]' info:info.txt `.trim(),
},

{
name: 'extract image information',
description: `extract image information in json format and store it in output file roseinfo.json`,
command: `convert rose: roseInfo.json `.trim(),
},



{
name: 'simple append',
description: `simple append+ command that joins two images`,
Expand Down
17 changes: 16 additions & 1 deletion spec/util/fileSpec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { blobToString, buildInputFile, Call, compare, extractInfo, getFileNameExtension, getFileName, asInputFile, asOutputFile } from '../../src'
import { blobToString, buildInputFile, Call, compare, extractInfo, getFileNameExtension, getFileName, asInputFile, asOutputFile, executeAndReturnOutputFile, isImage, readFileAsText, getPixelColor, getBuiltInImages, getBuiltInImage } from '../../src'

export default describe('util/file', () => {

Expand Down Expand Up @@ -57,6 +57,21 @@ export default describe('util/file', () => {
})
})

describe('readFileAsText and isImage, getPixelColor, getBuiltInImage', () => { // TODO: separate

it('basic test', async done => {
const file = await executeAndReturnOutputFile(`convert logo: -format '%[pixel:p{0,0}]' info:info.txt`)
expect(await isImage(file)).toBe(false)
expect(await readFileAsText(file)).toBe('white')
const file2 = await buildInputFile('fn.png')
expect(await isImage(file2)).toBe(true)
expect(await readFileAsText(file2)).toContain('PNG')

expect(await getPixelColor(await getBuiltInImage('logo:'), 0, 0)).toBe('white')
done()
})
})

describe('getFileNameExtension', () => {

function test(url, expected) {
Expand Down
36 changes: 32 additions & 4 deletions src/util/file.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MagickInputFile, MagickOutputFile, MagickFile } from '..'
import { execute } from '../execute';

function blobToUint8Array(blob: Blob): Promise<Uint8Array> {
return new Promise(resolve => {
Expand All @@ -22,6 +23,33 @@ export function blobToString(blb: Blob): Promise<string> {
})
}

export function isInputFile(file: MagickFile): file is MagickInputFile {
return !!(file as MagickInputFile).content
}
export function isOutputFile(file: MagickFile): file is MagickOutputFile {
return !!(file as MagickOutputFile).blob
}

function uint8ArrayToString(arr: Uint8Array, charset: string = 'utf-8'): string {
return new TextDecoder(charset).decode(arr)
}

/**
* Read files as string. Useful when files contains plain text like in the output file info.txt of `convert logo: -format '%[pixel:p{0,0}]' info:info.txt`
*/
export async function readFileAsText(file: MagickFile): Promise<string> {
if (isInputFile(file)) {
return uint8ArrayToString(file.content)
}
if (isOutputFile(file)) {
return await blobToString(file.blob)
}
}

export async function isImage(file: MagickFile): Promise<boolean> {
const {exitCode} = await execute({inputFiles: [await asInputFile(file)], commands: `identify ${file.name}`})
return exitCode===0
}
/**
* Builds a new {@link MagickInputFile} by fetching the content of given url and optionally naming the file using given name
* or extracting the file name from the url otherwise.
Expand Down Expand Up @@ -53,8 +81,8 @@ function inputFileToOutputFile(file: MagickInputFile, name: string = file.name):

export async function asInputFile(f: MagickFile, name: string = f.name): Promise<MagickInputFile> {
let inputFile: MagickInputFile
if ((f as MagickOutputFile).blob) {
inputFile = await outputFileToInputFile(f as MagickOutputFile)
if (isOutputFile(f)) {
inputFile = await outputFileToInputFile(f)
}
else {
inputFile = f as MagickInputFile
Expand All @@ -65,8 +93,8 @@ export async function asInputFile(f: MagickFile, name: string = f.name): Promise

export async function asOutputFile(f: MagickFile, name: string = f.name): Promise<MagickOutputFile> {
let outputFile: MagickOutputFile
if ((f as MagickInputFile).content) {
outputFile = inputFileToOutputFile(f as MagickInputFile)
if (isInputFile(f)) {
outputFile = inputFileToOutputFile(f)
}
else {
outputFile = f as MagickOutputFile
Expand Down
7 changes: 7 additions & 0 deletions src/util/image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { MagickFile, executeAndReturnOutputFile, asInputFile } from "../";
import { readFileAsText } from "./file";

export async function getPixelColor(img: MagickFile, x: number, y: number): Promise<string>{
const file = await executeAndReturnOutputFile({inputFiles: [await asInputFile(img)], commands: `convert ${img.name} -format '%[pixel:p{${x},${y}}]' info:info.txt`})
return await readFileAsText(file)
}
8 changes: 8 additions & 0 deletions src/util/imageBuiltIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ export async function getBuiltInImages(): Promise<MagickInputFile[]> {
}
return builtInImages
}

/**
* shortcut of {@link getBuiltInImages} to get a single image by name
*/
export async function getBuiltInImage(name: string): Promise<MagickInputFile> {
const images = await getBuiltInImages()
return images.find(f=>f.name===name)
}
3 changes: 2 additions & 1 deletion src/util/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './file'
export * from './cli'
export * from './file'
export * from './html'
export * from './image'
export * from './imageBuiltIn'
export * from './imageCompare'
export * from './imageExtractInfo'
Expand Down

0 comments on commit 9e59e7a

Please sign in to comment.