Repository: aheckmann/gm Branch: master Commit: 6e43846ef7e3 Files: 206 Total size: 229.9 KB Directory structure: gitextract_x_d7l3ph/ ├── .github/ │ └── workflows/ │ └── node.js.yml ├── .gitignore ├── .npmignore ├── History.md ├── README.md ├── examples/ │ ├── append.js │ ├── background.js │ ├── bitdepth.js │ ├── blur.js │ ├── changeFormat.js │ ├── charcoal.js │ ├── chop.js │ ├── colorize.js │ ├── colors.js │ ├── comment.js │ ├── compare.js │ ├── contrast.js │ ├── crop.js │ ├── cycle.js │ ├── despeckle.js │ ├── dither.js │ ├── drawing.js │ ├── edge.js │ ├── emboss.js │ ├── enhance.js │ ├── equalize.js │ ├── extent.js │ ├── flatten.js │ ├── flip.js │ ├── flop.js │ ├── gamma.js │ ├── getters.js │ ├── gravity.js │ ├── implode.js │ ├── label.js │ ├── limit.js │ ├── lower.js │ ├── magnify.js │ ├── median.js │ ├── minify.js │ ├── modulate.js │ ├── monochrome.js │ ├── morph.js │ ├── negative.js │ ├── new.js │ ├── noise1.js │ ├── noise2.js │ ├── paint.js │ ├── quality.js │ ├── raise.js │ ├── region.js │ ├── resample.js │ ├── resize.js │ ├── roll.js │ ├── rotate.js │ ├── scale.js │ ├── sepia.js │ ├── sharpen.js │ ├── size.js │ ├── solarize.js │ ├── source_buffer.js │ ├── spread.js │ ├── swirl.js │ ├── thumb.js │ ├── thumbExact.js │ └── thumbnail.js ├── index.js ├── lib/ │ ├── args.js │ ├── command.js │ ├── compare.js │ ├── composite.js │ ├── convenience/ │ │ ├── autoOrient.js │ │ ├── morph.js │ │ ├── sepia.js │ │ └── thumb.js │ ├── convenience.js │ ├── drawing.js │ ├── getters.js │ ├── montage.js │ ├── options.js │ └── utils.js ├── package.json └── test/ ├── 109.js ├── 118.js ├── 393.js ├── 417.js ├── 422.js ├── 429.js ├── 68.js ├── 70.js ├── 78.js ├── alpha.js ├── append.js ├── arc.js ├── autoOrient.js ├── autoOrientAll.js ├── autoOrientAndThumb.js ├── autoOrientStream.js ├── background.js ├── bezier.js ├── bitdepth.js ├── blur.js ├── changeFormat.js ├── charcoal.js ├── chop.js ├── circle.js ├── colorize.js ├── colors.js ├── comment.js ├── compare.js ├── composite.js ├── contrast.js ├── crop.js ├── cycle.js ├── densityGm.js ├── despeckle.js ├── dispose.js ├── dither.js ├── edge.js ├── ellipse.js ├── emboss.js ├── enhance.js ├── equalize.js ├── extent.js ├── flatten.js ├── flip.js ├── flop.js ├── fromBuffer.js ├── gamma.js ├── geometry.js ├── getterColor.js ├── getterDepth.js ├── getterFilesize.js ├── getterFormat.js ├── getterFormatGIF.js ├── getterIdentify.js ├── getterIptc.js ├── getterMultipleIptc.js ├── getterRes.js ├── getterSize.js ├── gh-17.js ├── gifFrame.js ├── gifFrameIdentify.js ├── gifFrameStream.js ├── gravity.js ├── implode.js ├── index.js ├── inputIs.js ├── interlace.js ├── label.js ├── limit.js ├── line.js ├── lower.js ├── magnify.js ├── median.js ├── minify.js ├── minifyIM.js ├── modulate.js ├── monochrome.js ├── montage.js ├── morph-more.js ├── morph.js ├── negative.js ├── new.js ├── newImage.js ├── noise1.js ├── noise2.js ├── options.js ├── paint.js ├── polygon.js ├── polyline.js ├── quality.js ├── raise.js ├── rectangle.js ├── region.js ├── repagePlus.js ├── resample.js ├── resize.js ├── resizeAndAutoOrientFromBuffer.js ├── resizeBuffer.js ├── resizeWrong.js ├── roll.js ├── rotate.js ├── scale.js ├── selectFrame.js ├── sepia.js ├── setFormat.js ├── sharpen.js ├── solarize.js ├── spread.js ├── streamIn.js ├── streamInGetter.js ├── streamInOut.js ├── streamOut.js ├── streamOutFormat.js ├── strip.js ├── subclass.js ├── swirl.js ├── text.js ├── thumb.js ├── thumbnail.js ├── timeout.js ├── toBuffer.js ├── toBufferFormat.js ├── utils.js └── webp.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/node.js.yml ================================================ # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: Node.js CI on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build: runs-on: ${{ matrix.os }} env: DEBUG: "gm*" strategy: matrix: os: [windows-latest, ubuntu-latest] node-version: [14.x, 16.x, 18.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - name: Install GraphicsMagic and Imagemagick on Ubuntu if: contains(matrix.os, 'ubuntu') run: sudo apt-get install -y imagemagick graphicsmagick - name: Install GraphicsMagic and Imagemagick on Windows if: contains(matrix.os, 'windows') run: choco install -y imagemagick graphicsmagick - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm i - name: Run tests on Windows if: contains(matrix.os, 'windows') shell: cmd run: | call refreshenv npm test - name: Run tests on Ubuntu if: contains(matrix.os, 'ubuntu') run: npm test ================================================ FILE: .gitignore ================================================ .DS_Store node_modules package-lock.json examples/imgs/* !examples/imgs/original.jpg !examples/imgs/original.png !examples/imgs/original.gif !examples/imgs/originalSideways.jpg !examples/imgs/morpher.jpg !examples/imgs/photo.JPG !examples/imgs/orientation/*\d.jpg !examples/imgs/orientation/*.correct.jpg *.sw* .idea ================================================ FILE: .npmignore ================================================ test/ examples/ ================================================ FILE: History.md ================================================ 1.25.1 / 2025-02-24 * deps: bump cross-spawn [talyuk](https://github.com/talyuk) 1.25.0 / 2022-09-21 * fixed: windows support #846, #774, #594, #524, #528, #559, #652, #682 [piotr-cz](https://github.com/piotr-cz) * docs; improvements from #821 [agokhale](https://github.com/agokhale) * docs; improvements #801 [aarongarciah](https://github.com/aarongarciah) 1.24.0 / 2022-09-18 * fixed: infering format of buffered or streamed ico files #429 freund17 * fixed; preserve color info duing autoOrient() #714, #844 reco * tests; switch to Github Actions * docs; fix links #834 delesseps * docs; clarify install directions #689 PatrykMiszczak * refactor; clean up compare.js #788 LongTengDao 1.23.1 / 2017-12-27 * fixed: use debug > 2.6.9 because of security issue #685 danez * tests; add nsp check * tests; get tests passing on OSX 1.23.0 / 2016-08-03 * fixed; webpack support #547 sean-shirazi * fixed; windows support - use cross-spawn to spawn processes #537 bdukes * added; allow thumbnail to accept the same options as resize #527 Sebmaster * added; dispose support #487 dlwr * docs; add example of loading image from URL #544 wahengchang * docs; Fix a link in README.md #532 clbn * travis; update travis versions #551 amilajack 1.22.0 / 2016-04-07 * fixed; identity parser: support multi-value keys by creating an array #508 #509 [emaniacs](https://github.com/emaniacs) * fixed; error handling if gm is not installed #499 [aeo3](https://github.com/aeo3) * fixed; highlightColor typo in compare #504 [DanielHudson](https://github.com/DanielHudson) * docs; Fix typo #475 [rodrigoalviani](https://github.com/rodrigoalviani) 1.21.1 / 2015-10-26 * fixed: Fixed #465 hard coded gm binary, also fixed issues with compare and fixed tests so they will fail on subsequent runs when they should do [rwky](https://github.com/rwky) 1.21.0 / 2015-10-26 **contains security fix** * fixed: gm.compare fails to escape arguments properly (Reported by Brendan Scarvell) [rwky](https://github.com/rwky) 1.20.0 / 2015-09-23 * changed: Reverted "Add format inference from filename for buffers/streams" due to errors #448 1.19.0 / 2015-09-16 * changed: Added error to notify about image magick not supporting minify [encima](https://github.com/encima) * changed: Refactored orientation getter to use faster identify call [lbeschastny](https://github.com/lbeschastny) * added: resizeExact function [DanMMX](https://github.com/DanMMX) * added: thumbExact function [DanMMX](https://github.com/DanMMX) * added: Add format inference from filename for buffers/streams [adurrive](https://github.com/adurrive) * fixed: Hex values when passed to compare aren't quoted automatically [DanMMX](https://github.com/DanMMX) * fixed: identify returning last frame size instead of the larges on animated gifs [preynal](https://github.com/preynal) * docs: Updated docs [laurilehmijoki](https://github.com/laurilehmijoki) 1.18.1 / 2015-05-18 * changed: Added io.js support [rwky](https://github.com/rwky) 1.18.0 / 2015-05-18 * changed: Removed support for node 0.8 and added support for 0.12 [rwky](https://github.com/rwky) * changed: Listen to stdin error event for spawn errors [kapouer](https://github.com/kapouer) * changed: Improved error handling when gm isn't installed [FreshXOpenSource](https://github.com/FreshXOpenSource) * changed: Allow append method to use an array of arguments [emohacker](https://github.com/emohacker) * changed: appPath option now specifies full path to gm binary John Borkowski * changed: Ignore warning messages for identify [asrail](https://github.com/asrail) * added: Montage method [donaldpcook](https://github.com/donaldpcook) * added: Progressive option to thumb [mohebifar](https://github.com/mohebifar) * added: Native gm auto-orient for use with gm >= 1.3.18 [bog](https://github.com/bog) * added: Timeout support by passing the timeout option in milliseconds [marcbachmann](https://github.com/marcbachmann) * fixed: density when using ImageMagick [syzer](https://github.com/syzer) * fixed: resize behaviour for falsy values [adius](https://github.com/adius) 1.17.0 / 2014-10-28 ================== * changed: extended compare callback also returns the file names #297 [mastix](https://github.com/mastix) * changed: pass spawn crash to callback #306 [medikoo](https://github.com/medikoo) * changed: geometry supports arbitary string as first argument #330 [jdiez17](https://github.com/jdiez17) * added: support for repage+ option #275 [desigens](https://github.com/desigens) * added: added the dissolve command #300 [microadm](https://github.com/microadam) * added: composite method #332 [jdiez17](https://github.com/jdiez17) * fixed: cannot set tolerance to 0 #302 [rwky](https://github.com/rwky) * fixed: handle empty buffers #330 [alcidesv](https://github.com/alcidesv) 1.16.0 / 2014-05-09 ================== * fixed; dropped "+" when 0 passed as vertical roll amt #267 [dwtkns](https://github.com/dwtkns) * added; highlight-style support #272 [fdecampredon](https://github.com/fdecampredon) 1.15.0 / 2014-05-03 =================== * changed; gm.compare logic to always run the mse comparison as expected #258 [Vokkim](https://github.com/Vokkim) * added; `tolerance` to gm.compare options object #258 [Vokkim](https://github.com/Vokkim) * added; option to set ImageMagick application path explicitly #250 (akreitals) * fixed; gm.compare: support values like 9.51582e-05 #260 [normanrz](https://github.com/normanrz) * README: add call for maintainers 1.14.2 / 2013-12-24 =================== * fixed; background is now a setting #246 (PEM--) 1.14.1 / 2013-12-09 =================== * fixed; identify -verbose colon behavior #240 ludow 1.14.0 / 2013-12-04 =================== * added; compare method for imagemagick (longlho) 1.13.3 / 2013-10-22 =================== * fixed; escape diffOptions.file in compare (dwabyick) 1.13.2 / 2013-10-18 =================== * fixed; density is a setting not an operator 1.13.1 / 2013-09-15 =================== * added; boolean for % crop 1.13.0 / 2013-09-07 =================== * added; morph more than two images (overra) 1.12.2 / 2013-08-29 =================== * fixed; fallback to through in node 0.8 1.12.1 / 2013-08-29 (unpublished) =================== * refactor; replace through with stream.PassThrough 1.12.0 / 2013-08-27 =================== * added; diff image output file (chenglou) 1.11.1 / 2013-08-17 =================== * added; proto.selectFrame(#) * fixed; getters should not ignore frame selection 1.11.0 / 2013-07-23 =================== * added; optional formatting string for gm().identify(format, callback) (tornillo) * removed; error messages when gm/im binary is not installed 1.10.0 / 2013-06-27 =================== * refactor; use native `-auto-orient` for imagemagick 1.9.2 / 2013-06-12 ================== * refactor; move `streamToBuffer` to a separate module * fixed; .stream(format) without a callback 1.9.1 / 2013-05-07 ================== * fixed; gm().resize(width) always only resizes width * fixed; gm('img.gif').format() returns the format of the first frame 1.9.0 / 2013-04-21 ================== * added; node v0.10 support * removed; node < v0.8 support - `Buffer.concat()` * tests; all tests now run on Travis * added; gm().stream() returns a stream when no callback is present * added; gm().toBuffer(callback) * fixed; gm().size() only returns the size of the first frame of a GIF 1.8.2 / 2013-03-07 ================== * include source path in identify data #126 [soupdiver](https://github.com/soupdiver) 1.8.1 / 2012-12-21 ================== * Avoid losing already set arguments on identify #105 #113 #109 [JNissi](https://github.com/JNissi) * tests; add autoOrient + thumb() test * tests; add test case for #113 * tests; added test for #109 * tests; add resize on buffer test 1.8.0 / 2012-12-14 ================== * added; geometry support to scale() #98 * removed; incorrect/broken dissolve() method (never worked) * fixed; handle child_proc error when using Buffer input #109 * fixed; use of Buffers with identify() #109 * fixed; no longer include -size arg with resize() #98 * fixed; remove -size arg from extent() #103 * fixed; magnify support * fixed; autoOrient to work with all types of exif orientations [dambalah](https://github.com/dambalah) #108 * tests; npm test runs unit only (now compatible with travis) * tests; fix magnify test on imagemagick * tests; added for cmd line args 1.7.0 / 2012-12-06 ================== * added; gm.compare support * added; passing Buffers directly [danmilon](https://github.com/danmilon) 1.6.1 / 2012-11-13 ================== * fixed regression; only pass additional params on error #96 1.6.0 / 2012-11-10 ================== * changed; rename internal buffer to _buffer #88 [kof](https://github.com/kof) * changed; optimized identify getters (format, depth, size, color, filesize). #83 please read this for details: https://github.com/aheckmann/gm/commit/8fcf3f8f84a02cc2001da874cbebb89bf7084409 * added; visionmedia/debug support * added; `gm convert -thumbnail` support. _differs from thumb()._ [danmilon](https://github.com/danmilon) * fixed; -rotate 0 support #90 * fixed; multi-execution of same gm instance arguments corruption * fixed; gracefully handle parser errors #94 [eldilibra](https://github.com/eldilibra) 1.5.1 / 2012-10-02 ================== * fixed; passing multiple paths to append() #77 1.5.0 / 2012-09-15 ================== * fixed; callback scope * fixed; append() usage #77 1.4.2 / 2012-08-17 ================== * fixed; identify parsing for ImageMagick exif data (#58) * fixed; when in imageMagick mode, complain about missing imageMagick [bcherry](https://github.com/bcherry) (#73) * added; tests 1.4.1 / 2012-07-31 ================== * fixed; scenes() args * fixed; accept the left-to-right arg of append() * added; _subCommand ## v1.4 - 07/28/2012 * added; adjoin() [Math-] * added; affine() [Math-] * added; append() [Math-] * added; authenticate() [Math-] * added; average() [Math-] * added; backdrop() [Math-] * added; blackThreshold() [Math-] * added; bluePrimary() [Math-] * added; border() [Math-] * added; borderColor() [Math-] * added; box() [Math-] * added; channel() [Math-] * added; clip() [Math-] * added; coalesce() [Math-] * added; colorMap() [Math-] * added; compose() [Math-] * added; compress() [Math-] * added; convolve() [Math-] * added; createDirectories() [Math-] * added; deconstruct() [Math-] * added; delay() [Math-] * added; define() [Math-] * added; displace() [Math-] * added; display() [Math-] * added; dispose() [Math-] * added; disolve() [Math-] * added; encoding() [Math-] * added; endian() [Math-] * added; file() [Math-] * added; flatten() [Math-] * added; foreground() [Math-] * added; frame() [Math-] * added; fuzz() [Math-] * added; gaussian() [Math-] * added; geometry() [Math-] * added; greenPrimary() [Math-] * added; highlightColor() [Math-] * added; highlightStyle() [Math-] * added; iconGeometry() [Math-] * added; intent() [Math-] * added; lat() [Math-] * added; level() [Math-] * added; list() [Math-] * added; log() [Math-] * added; map() [Math-] * added; matte() [Math-] * added; matteColor() [Math-] * added; mask() [Math-] * added; maximumError() [Math-] * added; mode() [Math-] * added; monitor() [Math-] * added; mosaic() [Math-] * added; motionBlur() [Math-] * added; name() [Math-] * added; noop() [Math-] * added; normalize() [Math-] * added; opaque() [Math-] * added; operator() [Math-] * added; orderedDither() [Math-] * added; outputDirectory() [Math-] * added; page() [Math-] * added; pause() [Math-] * added; pen() [Math-] * added; ping() [Math-] * added; pointSize() [Math-] * added; preview() [Math-] * added; process() [Math-] * added; profile() [Math-] * added; progress() [Math-] * added; rawSize() [Math-] * added; randomThreshold() [Math-] * added; recolor() [Math-] * added; redPrimary() [Math-] * added; remote() [Math-] * added; render() [Math-] * added; repage() [Math-] * added; sample() [Math-] * added; samplingFactor() [Math-] * added; scene() [Math-] * added; scenes() [Math-] * added; screen() [Math-] * added; segment() [Math-] * added; set() [Math-] * added; shade() [Math-] * added; shadow() [Math-] * added; sharedMemory() [Math-] * added; shave() [Math-] * added; shear() [Math-] * added; silent() [Math-] * added; snaps() [Math-] * added; stagano() [Math-] * added; stereo() [Math-] * added; textFont() [Math-] * added; texture() [Math-] * added; threshold() [Math-] * added; tile() [Math-] * added; transform() [Math-] * added; transparent() [Math-] * added; treeDepth() [Math-] * added; update() [Math-] * added; units() [Math-] * added; unsharp() [Math-] * added; usePixmap() [Math-] * added; view() [Math-] * added; virtualPixel() [Math-] * added; visual() [Math-] * added; watermark() [Math-] * added; wave() [Math-] * added; whitePoint() [Math-] * added; whiteThreshold() [Math-] * added; window() [Math-] * added; windowGroup() [Math-] ## v1.3.2 - 06/22/2012 * added; node >= 0.7/0.8 compat ## v1.3.1 - 06/06/2012 * fixed; thumb() alignment and cropping [thomaschaaf] * added; hint when graphicsmagick is not installed (#62) * fixed; minify() (#59) ## v1.3.0 - 04/11/2012 * added; flatten support [jwarchol] * added; background support [jwarchol] * fixed; identify parser error [chriso] ## v1.2.0 - 03/30/2012 * added; extent and gravity support [jwarchol] ## v1.1.0 - 03/15/2012 * added; filter() support [travisbeck] * added; density() [travisbeck] * fixed; permit either width or height in resize [dambalah] * updated; docs ## v1.0.5 - 02/15/2012 * added; strip() support [Math-] * added; interlace() support [Math-] * added; setFormat() support [Math-] * fixed; regexps for image types [Math-] ## v1.0.4 - 02/09/2012 * expose utils ## v1.0.3 - 01/27/2012 * removed; console.log ## v1.0.2 - 01/24/2012 * added; debugging info on parser errors * fixed; exports.version ## v1.0.1 - 01/12/2012 * fixed; use of reserved keyword `super` for node v0.5+ ## v1.0.0 - 01/12/2012 * added; autoOrient support [kainosnoema] (#21) * added; orientation support [kainosnoema] (#21) * fixed; identify parser now properly JSON formats all data output by `gm identify` such as IPTC, GPS, Make, etc (#20) * added; support for running as imagemagick (#23, #29) * added; subclassing support; useful for setting default constructor options like one constructor for ImageMagick, the other for GM * added; more tests * changed; remove redundant `orientation`, `resolution`, and `filesize` from `this.data` in `indentify()`. Use their uppercase equivalents. ## v0.6.0 - 12/14/2011 * added; stream support [kainosnoema] (#22) ## v0.5.0 - 07/07/2011 * added; gm#trim() support [lepokle] * added; gm#inputIs() support * fixed; 'geometry does not contain image' error: gh-17 ## v0.4.3 - 05/17/2011 * added; bunch of tests * fixed; polygon, polyline, bezier drawing bug ## v0.4.2 - 05/10/2011 * added; resize options support ## v0.4.1 - 04/28/2011 * shell args are now escaped (thanks @visionmedia) * added; gm.in() * added; gm.out() * various refactoring ## v0.4.0 - 9/21/2010 * removed deprecated `new` method * added drawing docs ## v0.3.2 - 9/06/2010 * new images are now created using same gm() constructor ## v0.3.1 - 9/06/2010 * can now create images from scratch * add type method ## v0.3.0 - 8/26/2010 * add drawing api ## v0.2.2 - 8/22/2010 * add quality option to thumb() * add teropa to contributors * added support for colorspace() ## v0.2.1 - 7/31/2010 * fixed naming conflict. depth() manipulation method renamed bitdepth() * added better docs ## v0.2.0 - 7/29/2010 new methods - swirl - spread - solarize - sharpen - roll - sepia - region - raise - lower - paint - noise - negative - morph - median - antialias - limit - label - implode - gamma - enhance - equalize - emboss - edge - dither - monochrome - despeckle - depth - cycle - contrast - comment - colors added more default args to several methods added more examples ## v0.1.2 - 7/28/2010 * refactor project into separate modules ## v0.1.1 - 7/27/2010 * add modulate method * add colorize method * add charcoal method * add chop method * bug fix in write without a callback ## v0.1.0 - 6/27/2010 * no longer supporting mogrify * add image data getter methods * size * format * color * res * depth * filesize * identify * add new convert methods * scale * resample * rotate * flip * flop * crop * magnify * minify * quality * blur * thumb ## v0.0.1 - 6/11/2010 Initial release ================================================ FILE: README.md ================================================ # 2025-02-24 This project is not maintained Instead of using this project, execute the `gm` or `magick` binaries using [`cross-spawn`](https://www.npmjs.com/package/cross-spawn) directly. Nearly [15 years ago](https://github.com/aheckmann/gm/commit/defc7360d70d87f7a13da4f6e2ef0104594776b9) I started this project as part of my start up which I sold later that year (2010). Having not used this project in over a decade and with no contributors for years, it's time to officially sunset `gm`. No further Issues will be addressed. No Pull Requests will be merged. No new commits or npm releases will be made. --- 😍 _Massive **thank you** to [everyone](https://github.com/aheckmann/gm/graphs/contributors) who contributed to this project over the years._ 😍 --- ## I want to continue using gm. What do I do? All past `gm` releases published to the npm registry will continue to be available for install. However, you should **prioritize moving off of this project to an alternative** because the risk of unpatched vulnerabilities in this project will continue to _increase_ over time. No new commits will land and no new releases will be published. The most obvious alternative to `gm` I see is installing [cross-spawn](https://www.npmjs.com/package/cross-spawn) and executing the GraphicsMagick or ImageMagick binaries directly, after all, that's pretty much all this project did. There may be other `gm` alternatives on npm but I don't what they are offhand so you'll need to search for something suitable yourself. --- # gm [![Build Status](https://travis-ci.org/aheckmann/gm.png?branch=master)](https://travis-ci.org/aheckmann/gm) [![NPM Version](https://img.shields.io/npm/v/gm.svg?style=flat)](https://www.npmjs.org/package/gm) GraphicsMagick and ImageMagick for node ## Bug Reports When reporting bugs please include the version of graphicsmagick/imagemagick you're using (gm -version/convert -version) as well as the version of this module and copies of any images you're having problems with. ## Getting started First download and install [GraphicsMagick](http://www.graphicsmagick.org/) or [ImageMagick](http://www.imagemagick.org/). In Mac OS X, you can simply use [Homebrew](http://mxcl.github.io/homebrew/) and do: brew install imagemagick brew install graphicsmagick then either use npm: npm install gm or clone the repo: git clone git://github.com/aheckmann/gm.git ## Use ImageMagick instead of gm Subclass `gm` to enable [ImageMagick 7+](https://imagemagick.org/script/porting.php) ```js const fs = require('fs') const gm = require('gm').subClass({ imageMagick: '7+' }); ``` Or, to enable ImageMagick legacy mode (for ImageMagick version < 7) ```js const fs = require('fs') const gm = require('gm').subClass({ imageMagick: true }); ``` ## Specify the executable path Optionally specify the path to the executable. ```js const fs = require('fs') const gm = require('gm').subClass({ appPath: String.raw`C:\Program Files\ImageMagick-7.1.0-Q16-HDRI\magick.exe` }); ``` ## Basic Usage ```js var fs = require('fs') , gm = require('gm'); // resize and remove EXIF profile data gm('/path/to/my/img.jpg') .resize(240, 240) .noProfile() .write('/path/to/resize.png', function (err) { if (!err) console.log('done'); }); // some files would not be resized appropriately // http://stackoverflow.com/questions/5870466/imagemagick-incorrect-dimensions // you have two options: // use the '!' flag to ignore aspect ratio gm('/path/to/my/img.jpg') .resize(240, 240, '!') .write('/path/to/resize.png', function (err) { if (!err) console.log('done'); }); // use the .resizeExact with only width and/or height arguments gm('/path/to/my/img.jpg') .resizeExact(240, 240) .write('/path/to/resize.png', function (err) { if (!err) console.log('done'); }); // obtain the size of an image gm('/path/to/my/img.jpg') .size(function (err, size) { if (!err) console.log(size.width > size.height ? 'wider' : 'taller than you'); }); // output all available image properties gm('/path/to/img.png') .identify(function (err, data) { if (!err) console.log(data) }); // pull out the first frame of an animated gif and save as png gm('/path/to/animated.gif[0]') .write('/path/to/firstframe.png', function (err) { if (err) console.log('aaw, shucks'); }); // auto-orient an image gm('/path/to/img.jpg') .autoOrient() .write('/path/to/oriented.jpg', function (err) { if (err) ... }) // crazytown gm('/path/to/my/img.jpg') .flip() .magnify() .rotate('green', 45) .blur(7, 3) .crop(300, 300, 150, 130) .edge(3) .write('/path/to/crazy.jpg', function (err) { if (!err) console.log('crazytown has arrived'); }) // annotate an image gm('/path/to/my/img.jpg') .stroke("#ffffff") .drawCircle(10, 10, 20, 10) .font("Helvetica.ttf", 12) .drawText(30, 20, "GMagick!") .write("/path/to/drawing.png", function (err) { if (!err) console.log('done'); }); // creating an image gm(200, 400, "#ddff99f3") .drawText(10, 50, "from scratch") .write("/path/to/brandNewImg.jpg", function (err) { // ... }); ``` ## Streams ```js // passing a stream var readStream = fs.createReadStream('/path/to/my/img.jpg'); gm(readStream, 'img.jpg') .write('/path/to/reformat.png', function (err) { if (!err) console.log('done'); }); // passing a downloadable image by url var request = require('request'); var url = "www.abc.com/pic.jpg" gm(request(url)) .write('/path/to/reformat.png', function (err) { if (!err) console.log('done'); }); // can also stream output to a ReadableStream // (can be piped to a local file or remote server) gm('/path/to/my/img.jpg') .resize('200', '200') .stream(function (err, stdout, stderr) { var writeStream = fs.createWriteStream('/path/to/my/resized.jpg'); stdout.pipe(writeStream); }); // without a callback, .stream() returns a stream // this is just a convenience wrapper for above. var writeStream = fs.createWriteStream('/path/to/my/resized.jpg'); gm('/path/to/my/img.jpg') .resize('200', '200') .stream() .pipe(writeStream); // pass a format or filename to stream() and // gm will provide image data in that format gm('/path/to/my/img.jpg') .stream('png', function (err, stdout, stderr) { var writeStream = fs.createWriteStream('/path/to/my/reformatted.png'); stdout.pipe(writeStream); }); // or without the callback var writeStream = fs.createWriteStream('/path/to/my/reformatted.png'); gm('/path/to/my/img.jpg') .stream('png') .pipe(writeStream); // combine the two for true streaming image processing var readStream = fs.createReadStream('/path/to/my/img.jpg'); gm(readStream) .resize('200', '200') .stream(function (err, stdout, stderr) { var writeStream = fs.createWriteStream('/path/to/my/resized.jpg'); stdout.pipe(writeStream); }); // GOTCHA: // when working with input streams and any 'identify' // operation (size, format, etc), you must pass "{bufferStream: true}" if // you also need to convert (write() or stream()) the image afterwards // NOTE: this buffers the readStream in memory! var readStream = fs.createReadStream('/path/to/my/img.jpg'); gm(readStream) .size({bufferStream: true}, function(err, size) { this.resize(size.width / 2, size.height / 2) this.write('/path/to/resized.jpg', function (err) { if (!err) console.log('done'); }); }); ``` ## Buffers ```js // A buffer can be passed instead of a filepath as well var buf = require('fs').readFileSync('/path/to/image.jpg'); gm(buf, 'image.jpg') .noise('laplacian') .write('/path/to/out.jpg', function (err) { if (err) return handle(err); console.log('Created an image from a Buffer!'); }); /* A buffer can also be returned instead of a stream The first argument to toBuffer is optional, it specifies the image format */ gm('img.jpg') .resize(100, 100) .toBuffer('PNG',function (err, buffer) { if (err) return handle(err); console.log('done!'); }) ``` ## Custom Arguments If `gm` does not supply you with a method you need or does not work as you'd like, you can simply use `gm().in()` or `gm().out()` to set your own arguments. - `gm().command()` - Custom command such as `identify` or `convert` - `gm().in()` - Custom input arguments - `gm().out()` - Custom output arguments The command will be formatted in the following order: 1. `command` - ie `convert` 2. `in` - the input arguments 3. `source` - stdin or an image file 4. `out` - the output arguments 5. `output` - stdout or the image file to write to For example, suppose you want the following command: ```bash gm "convert" "label:Offline" "PNG:-" ``` However, using `gm().label()` may not work as intended for you: ```js gm() .label('Offline') .stream(); ``` would yield: ```bash gm "convert" "-label" "\"Offline\"" "PNG:-" ``` Instead, you can use `gm().out()`: ```js gm() .out('label:Offline') .stream(); ``` which correctly yields: ```bash gm "convert" "label:Offline" "PNG:-" ``` ### Custom Identify Format String When identifying an image, you may want to use a custom formatting string instead of using `-verbose`, which is quite slow. You can use your own [formatting string](http://www.imagemagick.org/script/escape.php) when using `gm().identify(format, callback)`. For example, ```js gm('img.png').format(function (err, format) { }) // is equivalent to gm('img.png').identify('%m', function (err, format) { }) ``` since `%m` is the format option for getting the image file format. ## Platform differences Please document and refer to any [platform or ImageMagick/GraphicsMagick issues/differences here](https://github.com/aheckmann/gm/wiki/GraphicsMagick-and-ImageMagick-versions). ## Examples: Check out the [examples](http://github.com/aheckmann/gm/tree/master/examples/) directory to play around. Also take a look at the [extending gm](http://wiki.github.com/aheckmann/gm/extending-gm) page to see how to customize gm to your own needs. ## Constructor: There are a few ways you can use the `gm` image constructor. - 1) `gm(path)` When you pass a string as the first argument it is interpreted as the path to an image you intend to manipulate. - 2) `gm(stream || buffer, [filename])` You may also pass a ReadableStream or Buffer as the first argument, with an optional file name for format inference. - 3) `gm(width, height, [color])` When you pass two integer arguments, gm will create a new image on the fly with the provided dimensions and an optional background color. And you can still chain just like you do with pre-existing images too. See [here](http://github.com/aheckmann/gm/blob/master/examples/new.js) for an example. The links below refer to an older version of gm but everything should still work, if anyone feels like updating them please make a PR ## Methods - getters - [size](http://aheckmann.github.io/gm/docs.html#getters) - returns the size (WxH) of the image - [orientation](http://aheckmann.github.io/gm/docs.html#getters) - returns the EXIF orientation of the image - [format](http://aheckmann.github.io/gm/docs.html#getters) - returns the image format (gif, jpeg, png, etc) - [depth](http://aheckmann.github.io/gm/docs.html#getters) - returns the image color depth - [color](http://aheckmann.github.io/gm/docs.html#getters) - returns the number of colors - [res](http://aheckmann.github.io/gm/docs.html#getters) - returns the image resolution - [filesize](http://aheckmann.github.io/gm/docs.html#getters) - returns image filesize - [identify](http://aheckmann.github.io/gm/docs.html#getters) - returns all image data available. Takes an optional format string. - manipulation - [adjoin](http://aheckmann.github.io/gm/docs.html#adjoin) - [affine](http://aheckmann.github.io/gm/docs.html#affine) - [antialias](http://aheckmann.github.io/gm/docs.html#antialias) - [append](http://aheckmann.github.io/gm/docs.html#append) - [authenticate](http://aheckmann.github.io/gm/docs.html#authenticate) - [autoOrient](http://aheckmann.github.io/gm/docs.html#autoOrient) - [average](http://aheckmann.github.io/gm/docs.html#average) - [backdrop](http://aheckmann.github.io/gm/docs.html#backdrop) - [bitdepth](http://aheckmann.github.io/gm/docs.html#bitdepth) - [blackThreshold](http://aheckmann.github.io/gm/docs.html#blackThreshold) - [bluePrimary](http://aheckmann.github.io/gm/docs.html#bluePrimary) - [blur](http://aheckmann.github.io/gm/docs.html#blur) - [border](http://aheckmann.github.io/gm/docs.html#border) - [borderColor](http://aheckmann.github.io/gm/docs.html#borderColor) - [box](http://aheckmann.github.io/gm/docs.html#box) - [channel](http://aheckmann.github.io/gm/docs.html#channel) - [charcoal](http://aheckmann.github.io/gm/docs.html#charcoal) - [chop](http://aheckmann.github.io/gm/docs.html#chop) - [clip](http://aheckmann.github.io/gm/docs.html#clip) - [coalesce](http://aheckmann.github.io/gm/docs.html#coalesce) - [colors](http://aheckmann.github.io/gm/docs.html#colors) - [colorize](http://aheckmann.github.io/gm/docs.html#colorize) - [colorMap](http://aheckmann.github.io/gm/docs.html#colorMap) - [colorspace](http://aheckmann.github.io/gm/docs.html#colorspace) - [comment](http://aheckmann.github.io/gm/docs.html#comment) - [compose](http://aheckmann.github.io/gm/docs.html#compose) - [compress](http://aheckmann.github.io/gm/docs.html#compress) - [contrast](http://aheckmann.github.io/gm/docs.html#contrast) - [convolve](http://aheckmann.github.io/gm/docs.html#convolve) - [createDirectories](http://aheckmann.github.io/gm/docs.html#createDirectories) - [crop](http://aheckmann.github.io/gm/docs.html#crop) - [cycle](http://aheckmann.github.io/gm/docs.html#cycle) - [deconstruct](http://aheckmann.github.io/gm/docs.html#deconstruct) - [delay](http://aheckmann.github.io/gm/docs.html#delay) - [define](http://aheckmann.github.io/gm/docs.html#define) - [density](http://aheckmann.github.io/gm/docs.html#density) - [despeckle](http://aheckmann.github.io/gm/docs.html#despeckle) - [dither](http://aheckmann.github.io/gm/docs.html#dither) - [displace](http://aheckmann.github.io/gm/docs.html#dither) - [display](http://aheckmann.github.io/gm/docs.html#display) - [dispose](http://aheckmann.github.io/gm/docs.html#dispose) - [dissolve](http://aheckmann.github.io/gm/docs.html#dissolve) - [edge](http://aheckmann.github.io/gm/docs.html#edge) - [emboss](http://aheckmann.github.io/gm/docs.html#emboss) - [encoding](http://aheckmann.github.io/gm/docs.html#encoding) - [enhance](http://aheckmann.github.io/gm/docs.html#enhance) - [endian](http://aheckmann.github.io/gm/docs.html#endian) - [equalize](http://aheckmann.github.io/gm/docs.html#equalize) - [extent](http://aheckmann.github.io/gm/docs.html#extent) - [file](http://aheckmann.github.io/gm/docs.html#file) - [filter](http://aheckmann.github.io/gm/docs.html#filter) - [flatten](http://aheckmann.github.io/gm/docs.html#flatten) - [flip](http://aheckmann.github.io/gm/docs.html#flip) - [flop](http://aheckmann.github.io/gm/docs.html#flop) - [foreground](http://aheckmann.github.io/gm/docs.html#foreground) - [frame](http://aheckmann.github.io/gm/docs.html#frame) - [fuzz](http://aheckmann.github.io/gm/docs.html#fuzz) - [gamma](http://aheckmann.github.io/gm/docs.html#gamma) - [gaussian](http://aheckmann.github.io/gm/docs.html#gaussian) - [geometry](http://aheckmann.github.io/gm/docs.html#geometry) - [gravity](http://aheckmann.github.io/gm/docs.html#gravity) - [greenPrimary](http://aheckmann.github.io/gm/docs.html#greenPrimary) - [highlightColor](http://aheckmann.github.io/gm/docs.html#highlightColor) - [highlightStyle](http://aheckmann.github.io/gm/docs.html#highlightStyle) - [iconGeometry](http://aheckmann.github.io/gm/docs.html#iconGeometry) - [implode](http://aheckmann.github.io/gm/docs.html#implode) - [intent](http://aheckmann.github.io/gm/docs.html#intent) - [interlace](http://aheckmann.github.io/gm/docs.html#interlace) - [label](http://aheckmann.github.io/gm/docs.html#label) - [lat](http://aheckmann.github.io/gm/docs.html#lat) - [level](http://aheckmann.github.io/gm/docs.html#level) - [list](http://aheckmann.github.io/gm/docs.html#list) - [limit](http://aheckmann.github.io/gm/docs.html#limit) - [log](http://aheckmann.github.io/gm/docs.html#log) - [loop](http://aheckmann.github.io/gm/docs.html#loop) - [lower](http://aheckmann.github.io/gm/docs.html#lower) - [magnify](http://aheckmann.github.io/gm/docs.html#magnify) - [map](http://aheckmann.github.io/gm/docs.html#map) - [matte](http://aheckmann.github.io/gm/docs.html#matte) - [matteColor](http://aheckmann.github.io/gm/docs.html#matteColor) - [mask](http://aheckmann.github.io/gm/docs.html#mask) - [maximumError](http://aheckmann.github.io/gm/docs.html#maximumError) - [median](http://aheckmann.github.io/gm/docs.html#median) - [minify](http://aheckmann.github.io/gm/docs.html#minify) - [mode](http://aheckmann.github.io/gm/docs.html#mode) - [modulate](http://aheckmann.github.io/gm/docs.html#modulate) - [monitor](http://aheckmann.github.io/gm/docs.html#monitor) - [monochrome](http://aheckmann.github.io/gm/docs.html#monochrome) - [morph](http://aheckmann.github.io/gm/docs.html#morph) - [mosaic](http://aheckmann.github.io/gm/docs.html#mosaic) - [motionBlur](http://aheckmann.github.io/gm/docs.html#motionBlur) - [name](http://aheckmann.github.io/gm/docs.html#name) - [negative](http://aheckmann.github.io/gm/docs.html#negative) - [noise](http://aheckmann.github.io/gm/docs.html#noise) - [noop](http://aheckmann.github.io/gm/docs.html#noop) - [normalize](http://aheckmann.github.io/gm/docs.html#normalize) - [noProfile](http://aheckmann.github.io/gm/docs.html#profile) - [opaque](http://aheckmann.github.io/gm/docs.html#opaque) - [operator](http://aheckmann.github.io/gm/docs.html#operator) - [orderedDither](http://aheckmann.github.io/gm/docs.html#orderedDither) - [outputDirectory](http://aheckmann.github.io/gm/docs.html#outputDirectory) - [paint](http://aheckmann.github.io/gm/docs.html#paint) - [page](http://aheckmann.github.io/gm/docs.html#page) - [pause](http://aheckmann.github.io/gm/docs.html#pause) - [pen](http://aheckmann.github.io/gm/docs.html#pen) - [ping](http://aheckmann.github.io/gm/docs.html#ping) - [pointSize](http://aheckmann.github.io/gm/docs.html#pointSize) - [preview](http://aheckmann.github.io/gm/docs.html#preview) - [process](http://aheckmann.github.io/gm/docs.html#process) - [profile](http://aheckmann.github.io/gm/docs.html#profile) - [progress](http://aheckmann.github.io/gm/docs.html#progress) - [quality](http://aheckmann.github.io/gm/docs.html#quality) - [raise](http://aheckmann.github.io/gm/docs.html#raise) - [rawSize](http://aheckmann.github.io/gm/docs.html#rawSize) - [randomThreshold](http://aheckmann.github.io/gm/docs.html#randomThreshold) - [recolor](http://aheckmann.github.io/gm/docs.html#recolor) - [redPrimary](http://aheckmann.github.io/gm/docs.html#redPrimary) - [region](http://aheckmann.github.io/gm/docs.html#region) - [remote](http://aheckmann.github.io/gm/docs.html#remote) - [render](http://aheckmann.github.io/gm/docs.html#render) - [repage](http://aheckmann.github.io/gm/docs.html#repage) - [resample](http://aheckmann.github.io/gm/docs.html#resample) - [resize](http://aheckmann.github.io/gm/docs.html#resize) - [roll](http://aheckmann.github.io/gm/docs.html#roll) - [rotate](http://aheckmann.github.io/gm/docs.html#rotate) - [sample](http://aheckmann.github.io/gm/docs.html#sample) - [samplingFactor](http://aheckmann.github.io/gm/docs.html#samplingFactor) - [scale](http://aheckmann.github.io/gm/docs.html#scale) - [scene](http://aheckmann.github.io/gm/docs.html#scene) - [scenes](http://aheckmann.github.io/gm/docs.html#scenes) - [screen](http://aheckmann.github.io/gm/docs.html#screen) - [segment](http://aheckmann.github.io/gm/docs.html#segment) - [sepia](http://aheckmann.github.io/gm/docs.html#sepia) - [set](http://aheckmann.github.io/gm/docs.html#set) - [setFormat](http://aheckmann.github.io/gm/docs.html#setformat) - [shade](http://aheckmann.github.io/gm/docs.html#shade) - [shadow](http://aheckmann.github.io/gm/docs.html#shadow) - [sharedMemory](http://aheckmann.github.io/gm/docs.html#sharedMemory) - [sharpen](http://aheckmann.github.io/gm/docs.html#sharpen) - [shave](http://aheckmann.github.io/gm/docs.html#shave) - [shear](http://aheckmann.github.io/gm/docs.html#shear) - [silent](http://aheckmann.github.io/gm/docs.html#silent) - [solarize](http://aheckmann.github.io/gm/docs.html#solarize) - [snaps](http://aheckmann.github.io/gm/docs.html#snaps) - [stegano](http://aheckmann.github.io/gm/docs.html#stegano) - [stereo](http://aheckmann.github.io/gm/docs.html#stereo) - [strip](http://aheckmann.github.io/gm/docs.html#strip) _imagemagick only_ - [spread](http://aheckmann.github.io/gm/docs.html#spread) - [swirl](http://aheckmann.github.io/gm/docs.html#swirl) - [textFont](http://aheckmann.github.io/gm/docs.html#textFont) - [texture](http://aheckmann.github.io/gm/docs.html#texture) - [threshold](http://aheckmann.github.io/gm/docs.html#threshold) - [thumb](http://aheckmann.github.io/gm/docs.html#thumb) - [tile](http://aheckmann.github.io/gm/docs.html#tile) - [transform](http://aheckmann.github.io/gm/docs.html#transform) - [transparent](http://aheckmann.github.io/gm/docs.html#transparent) - [treeDepth](http://aheckmann.github.io/gm/docs.html#treeDepth) - [trim](http://aheckmann.github.io/gm/docs.html#trim) - [type](http://aheckmann.github.io/gm/docs.html#type) - [update](http://aheckmann.github.io/gm/docs.html#update) - [units](http://aheckmann.github.io/gm/docs.html#units) - [unsharp](http://aheckmann.github.io/gm/docs.html#unsharp) - [usePixmap](http://aheckmann.github.io/gm/docs.html#usePixmap) - [view](http://aheckmann.github.io/gm/docs.html#view) - [virtualPixel](http://aheckmann.github.io/gm/docs.html#virtualPixel) - [visual](http://aheckmann.github.io/gm/docs.html#visual) - [watermark](http://aheckmann.github.io/gm/docs.html#watermark) - [wave](http://aheckmann.github.io/gm/docs.html#wave) - [whitePoint](http://aheckmann.github.io/gm/docs.html#whitePoint) - [whiteThreshold](http://aheckmann.github.io/gm/docs.html#whiteThreshold) - [window](http://aheckmann.github.io/gm/docs.html#window) - [windowGroup](http://aheckmann.github.io/gm/docs.html#windowGroup) - drawing primitives - [draw](http://aheckmann.github.io/gm/docs.html#draw) - [drawArc](http://aheckmann.github.io/gm/docs.html#drawArc) - [drawBezier](http://aheckmann.github.io/gm/docs.html#drawBezier) - [drawCircle](http://aheckmann.github.io/gm/docs.html#drawCircle) - [drawEllipse](http://aheckmann.github.io/gm/docs.html#drawEllipse) - [drawLine](http://aheckmann.github.io/gm/docs.html#drawLine) - [drawPoint](http://aheckmann.github.io/gm/docs.html#drawPoint) - [drawPolygon](http://aheckmann.github.io/gm/docs.html#drawPolygon) - [drawPolyline](http://aheckmann.github.io/gm/docs.html#drawPolyline) - [drawRectangle](http://aheckmann.github.io/gm/docs.html#drawRectangle) - [drawText](http://aheckmann.github.io/gm/docs.html#drawText) - [fill](http://aheckmann.github.io/gm/docs.html#fill) - [font](http://aheckmann.github.io/gm/docs.html#font) - [fontSize](http://aheckmann.github.io/gm/docs.html#fontSize) - [stroke](http://aheckmann.github.io/gm/docs.html#stroke) - [strokeWidth](http://aheckmann.github.io/gm/docs.html#strokeWidth) - [setDraw](http://aheckmann.github.io/gm/docs.html#setDraw) - image output - **write** - writes the processed image data to the specified filename - **stream** - provides a `ReadableStream` with the processed image data - **toBuffer** - returns the image as a `Buffer` instead of a stream ## compare Graphicsmagicks `compare` command is exposed through `gm.compare()`. This allows us to determine if two images can be considered "equal". Currently `gm.compare` only accepts file paths. gm.compare(path1, path2 [, options], callback) ```js gm.compare('/path/to/image1.jpg', '/path/to/another.png', function (err, isEqual, equality, raw, path1, path2) { if (err) return handle(err); // if the images were considered equal, `isEqual` will be true, otherwise, false. console.log('The images were equal: %s', isEqual); // to see the total equality returned by graphicsmagick we can inspect the `equality` argument. console.log('Actual equality: %d', equality); // inspect the raw output console.log(raw); // print file paths console.log(path1, path2); }) ``` You may wish to pass a custom tolerance threshold to increase or decrease the default level of `0.4`. ```js gm.compare('/path/to/image1.jpg', '/path/to/another.png', 1.2, function (err, isEqual) { ... }) ``` To output a diff image, pass a configuration object to define the diff options and tolerance. ```js var options = { file: '/path/to/diff.png', highlightColor: 'yellow', tolerance: 0.02 } gm.compare('/path/to/image1.jpg', '/path/to/another.png', options, function (err, isEqual, equality, raw) { ... }) ``` ## composite GraphicsMagick supports compositing one image on top of another. This is exposed through `gm.composite()`. Its first argument is an image path with the changes to the base image, and an optional mask image. Currently, `gm.composite()` only accepts file paths. gm.composite(other [, mask]) ```js gm('/path/to/image.jpg') .composite('/path/to/second_image.jpg') .geometry('+100+150') .write('/path/to/composite.png', function(err) { if(!err) console.log("Written composite image."); }); ``` ## montage GraphicsMagick supports montage for combining images side by side. This is exposed through `gm.montage()`. Its only argument is an image path with the changes to the base image. Currently, `gm.montage()` only accepts file paths. gm.montage(other) ```js gm('/path/to/image.jpg') .montage('/path/to/second_image.jpg') .geometry('+100+150') .write('/path/to/montage.png', function(err) { if(!err) console.log("Written montage image."); }); ``` ## Contributors [https://github.com/aheckmann/gm/contributors](https://github.com/aheckmann/gm/contributors) ## Inspiration http://github.com/quiiver/magickal-node ## Plugins [https://github.com/aheckmann/gm/wiki](https://github.com/aheckmann/gm/wiki) ## Tests `npm test` To run a single test: ``` npm test -- alpha.js ``` ## License (The MIT License) Copyright (c) 2010 [Aaron Heckmann](aaron.heckmann+github@gmail.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: examples/append.js ================================================ var gm = require('../') , dir = __dirname + '/imgs' , imgs = 'lost.png original.jpg'.split(' ').map(function (img) { return dir + '/' + img }) , out = dir + '/append.jpg' gm(imgs[0]) .append(imgs[1]) .append() .background('#222') .write(out, function (err) { if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) require('child_process').exec('open ' + out) }); ================================================ FILE: examples/background.js ================================================ var gm = require('../') , dir = __dirname + '/imgs' gm(dir + "/original.jpg") .crop(140,100) .background("#FF0000") .extent(340,300) .write(dir + '/background.jpg', function (err) { if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) }); ================================================ FILE: examples/bitdepth.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .bitdepth(2) .write(dir + '/bitdepth.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/blur.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .blur(19, 10) .write(dir + '/blur.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/changeFormat.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .write(dir + '/original.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/charcoal.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .charcoal(1) .write(dir + '/charcoal.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/chop.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .chop(54, 1, 307, 1) .write(dir + "/chop.jpg", function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/colorize.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .colorize(80, 0, 30) .write(dir + '/colorize.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/colors.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .colors(16) .write(dir + '/colors.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/comment.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .comment("%m:%f %wx%h") .write(dir + '/comment.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/compare.js ================================================ var gm = require('../') , dir = __dirname + '/imgs' , imgs = 'bitdepth.png original.jpg'.split(' ').map(function (img) { return dir + '/' + img }) , out = dir + '/compare.jpg' gm.compare(imgs[0], imgs[1], { highlightColor: "#fff", file: out }, function (err) { if (err) return console.dir(arguments) console.log('The images are equal: %s', arguments[1]); console.log('Actual equality: %d', arguments[2]); console.log(this.outname + " created :: " + arguments[3]); require('child_process').exec('open ' + out); }); ================================================ FILE: examples/contrast.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .contrast(2) .write(dir + '/contrast.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/crop.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .crop(200, 155, 300, 0) .write(dir + "/crop.jpg", function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/cycle.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .cycle(4) .write(dir + '/cycle.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/despeckle.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .despeckle() .write(dir + '/despeckle.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/dither.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .monochrome() .dither() .write(dir + '/dither.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/drawing.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .blur(8, 4) .stroke("red", 7) .fill("#ffffffbb") .drawLine(20, 10, 50, 40) .fill("#2c2") .stroke("blue", 1) .drawRectangle(40, 10, 50, 20) .drawRectangle(60, 10, 70, 20, 3) .drawArc(80, 10, 90, 20, 0, 180) .drawEllipse(105, 15, 3, 5) .drawCircle(125, 15, 120, 15) .drawPolyline([140, 10], [143, 13], [145, 13], [147, 15], [145, 17], [143, 19]) .drawPolygon([160, 10], [163, 13], [165, 13], [167, 15], [165, 17], [163, 19]) .drawBezier([180, 10], [183, 13], [185, 13], [187, 15], [185, 17], [183, 19]) .fontSize(68) .stroke("#efe", 2) .fill("#888") .drawText(-20, 98, "graphics magick") .write(dir + '/drawing.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/edge.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .edge(2) .write(dir + '/edge.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/emboss.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .emboss(2) .write(dir + '/emboss.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/enhance.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .enhance() .write(dir + '/enhance.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/equalize.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .equalize() .write(dir + '/equalize.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/extent.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .resize(200,100) .extent(300, 300) .write(dir + '/extent.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/flatten.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/layers.psd') .flatten() .write(dir + "/unlayered.jpg", function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/flip.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .flip() .write(dir + '/flip.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/flop.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .flop() .write(dir + '/flop.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/gamma.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .gamma(1.7, 2.3, 1.3) .write(dir + '/gamma.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/getters.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' var methods = [ "size" , "identify" , "format" , "depth" , "color" , "res" , "filesize" ] var image = gm(dir + '/original.png') methods.forEach(function(method){ image[method](function(err, result){ console.log(method + " result:") console.dir(result) }) }) ================================================ FILE: examples/gravity.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .resize(200,100) .gravity("South") // Be sure to use gravity BEFORE extent .extent(300, 300) .write(dir + '/gravity.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/implode.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .implode(0.8) .write(dir + '/implode.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/label.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .label("%m:%f %wx%h") .write(dir + '/label.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/limit.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .limit("memory", "32MB") .limit("map", "64MB") .write(dir + '/limit.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/lower.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .lower(10, 14) .write(dir + '/lower.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/magnify.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .magnify() .write(dir + '/magnify.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/median.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .median(4) .write(dir + '/median.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/minify.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .minify() .write(dir + '/minify.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/modulate.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .modulate(120, 100, 80) .write(dir + '/modulate.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/monochrome.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .monochrome() .write(dir + '/monochrome.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/morph.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .morph(dir + '/morpher.jpg', dir + '/morph.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/negative.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .negative() .write(dir + '/negative.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/new.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(525, 110, "#00ff55aa") .fontSize(68) .stroke("#efe", 2) .fill("#555") .drawText(20, 72, "graphics") .fill("#fa0") .drawText(274, 72, " magick") .write(dir + '/new.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/noise1.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .noise(0.3) .write(dir + '/noise1.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/noise2.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .noise("laplacian") .write(dir + '/noise2.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/paint.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .paint(2) .write(dir + '/paint.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/quality.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .quality(5) .write(dir + '/quality.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/raise.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .raise(10, 14) .write(dir + '/raise.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/region.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') // region must come before other affected arguments .region(130, 170, 307, 00).charcoal(1) .write(dir + '/region.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/resample.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .resample(420, 120) .write(dir + '/resample.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/resize.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .resize(58, 50, '%') .write(dir + '/resize.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/roll.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .roll(40,-100) .quality(100) .write(dir + '/roll.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/rotate.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .rotate('red', -30) .write(dir + '/rotate.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/scale.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .resize(58, 20) .write(dir + '/scale.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/sepia.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .sepia() .write(dir + '/sepia.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: examples/sharpen.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .sharpen(19, 10) .write(dir + '/sharpen.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/size.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' var methods = [ "size" ] var image = gm(dir + '/original.png') methods.forEach(function(method){ image[method](function(err, result){ console.log(method + " result:") console.dir(result) }) }) ================================================ FILE: examples/solarize.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .solarize(68.9) .write(dir + '/solarize.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/source_buffer.js ================================================ var gm = require('../') , fs = require('fs') , dir = __dirname + '/../examples/imgs' var buf = fs.readFileSync(dir + '/original.jpg'); gm(buf) .noise('laplacian') .write(dir + '/fromBuffer.png', function (err) { if (err) return console.dir(arguments); console.log(this.outname + ' created :: ' + arguments[3]); }); ================================================ FILE: examples/spread.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .spread(10) .write(dir + '/spread.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/swirl.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.png') .swirl(90) // degrees .write(dir + '/swirl.png', function(err){ if (err) return console.dir(arguments) console.log(this.outname + ' created :: ' + arguments[3]) } ) ================================================ FILE: examples/thumb.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .thumb(150, 50, dir + '/thumb.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) }); ================================================ FILE: examples/thumbExact.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .thumbExact(150, 50, dir + '/thumb.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) }); ================================================ FILE: examples/thumbnail.js ================================================ var gm = require('../') , dir = __dirname + '/imgs' gm(dir + '/original.jpg') .thumbnail(150, 150) .write(dir + '/thumbnail.jpg', function(err){ if (err) return console.dir(arguments) console.log(this.outname + " created :: " + arguments[3]) } ) ================================================ FILE: index.js ================================================ /** * Module dependencies. */ var Stream = require('stream').Stream; var EventEmitter = require('events').EventEmitter; var util = require('util'); util.inherits(gm, EventEmitter); /** * Constructor. * * @param {String|Number} path - path to img source or ReadableStream or width of img to create * @param {Number} [height] - optional filename of ReadableStream or height of img to create * @param {String} [color] - optional hex background color of created img */ function gm (source, height, color) { var width; if (!(this instanceof gm)) { return new gm(source, height, color); } EventEmitter.call(this); this._options = {}; this.options(this.__proto__._options); this.data = {}; this._in = []; this._out = []; this._outputFormat = null; this._subCommand = 'convert'; if (source instanceof Stream) { this.sourceStream = source; source = height || 'unknown.jpg'; } else if (Buffer.isBuffer(source)) { this.sourceBuffer = source; source = height || 'unknown.jpg'; } else if (height) { // new images width = source; source = ""; this.in("-size", width + "x" + height); if (color) { this.in("xc:"+ color); } } if (typeof source === "string") { // then source is a path // parse out gif frame brackets from filename // since stream doesn't use source path // eg. "filename.gif[0]" var frames = source.match(/(\[.+\])$/); if (frames) { this.sourceFrames = source.substr(frames.index, frames[0].length); source = source.substr(0, frames.index); } } this.source = source; this.addSrcFormatter(function (src) { // must be first source formatter var inputFromStdin = this.sourceStream || this.sourceBuffer; var ret = inputFromStdin ? '-' : this.source; const fileNameProvied = typeof height === 'string'; if (inputFromStdin && fileNameProvied && /\.ico$/i.test(this.source)) { ret = `ico:-`; } if (ret && this.sourceFrames) ret += this.sourceFrames; src.length = 0; src[0] = ret; }); } /** * Subclasses the gm constructor with custom options. * * @param {options} options * @return {gm} the subclasses gm constructor */ var parent = gm; gm.subClass = function subClass (options) { function gm (source, height, color) { if (!(this instanceof parent)) { return new gm(source, height, color); } parent.call(this, source, height, color); } gm.prototype.__proto__ = parent.prototype; gm.prototype._options = {}; gm.prototype.options(options); return gm; } /** * Augment the prototype. */ require("./lib/options")(gm.prototype); require("./lib/getters")(gm); require("./lib/args")(gm.prototype); require("./lib/drawing")(gm.prototype); require("./lib/convenience")(gm.prototype); require("./lib/command")(gm.prototype); require("./lib/compare")(gm.prototype); require("./lib/composite")(gm.prototype); require("./lib/montage")(gm.prototype); /** * Expose. */ module.exports = exports = gm; module.exports.utils = require('./lib/utils'); module.exports.compare = require('./lib/compare')(); module.exports.version = require('./package.json').version; ================================================ FILE: lib/args.js ================================================ /** * Dependencies */ var argsToArray = require('./utils').argsToArray; var isUtil = require('./utils').isUtil; /** * Extend proto */ module.exports = function (proto) { // change the specified frame. // See #202. proto.selectFrame = function (frame) { if (typeof frame === 'number') this.sourceFrames = '[' + frame + ']'; return this; } // define the sub-command to use, http://www.graphicsmagick.org/utilities.html proto.command = proto.subCommand = function subCommand (name){ this._subCommand = name; return this; } // http://www.graphicsmagick.org/GraphicsMagick.html#details-adjoin proto.adjoin = function adjoin () { return this.out("-adjoin"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-affine proto.affine = function affine (matrix) { return this.out("-affine", matrix); } proto.alpha = function alpha (type) { if (!this._options.imageMagick) return new Error('Method -alpha is not supported by GraphicsMagick'); return this.out('-alpha', type); } /** * Appends images to the list of "source" images. * * We may also specify either top-to-bottom or left-to-right * behavior of the appending by passing a boolean argument. * * Examples: * * img = gm(src); * * // +append means left-to-right * img.append(img1, img2) gm convert src img1 img2 -append * img.append(img, true) gm convert src img +append * img.append(img, false) gm convert src img -append * img.append(img) gm convert src img -append * img.append(img).append() gm convert src img -append * img.append(img).append(true) gm convert src img +append * img.append(img).append(true) gm convert src img +append * img.append(img).background('#222) gm convert src img -background #222 +append * img.append([img1,img2...],true) * @param {String} or {Array} [img] * @param {Boolean} [ltr] * @see http://www.graphicsmagick.org/GraphicsMagick.html#details-append */ proto.append = function append (img, ltr) { if (!this._append) { this._append = []; this.addSrcFormatter(function (src) { this.out(this._append.ltr ? '+append' : '-append'); src.push.apply(src, this._append); }); } if (0 === arguments.length) { this._append.ltr = false; return this; } for (var i = 0; i < arguments.length; ++i) { var arg = arguments[i]; switch (isUtil(arg)) { case 'Boolean': this._append.ltr = arg; break; case 'String': this._append.push(arg); break; case 'Array': for(var j=0,len=arg.length;jx, ImageMagick requires geometry = (this._options.imageMagick) ? w + options : w + 'x' + options; } else if (hIsValid) { geometry = 'x' + h + options } else { return this } return this.out("-thumbnail", geometry); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-tile proto.tile = function tile (filename) { return this.out("-tile", filename); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-title proto.title = function title (string) { return this.out("-title", string); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-transform proto.transform = function transform (color) { return this.out("-transform", color); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-transparent proto.transparent = function transparent (color) { return this.out("-transparent", color); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-treedepth proto.treeDepth = function treeDepth (value) { return this.out("-treedepth", value); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-update proto.update = function update (seconds) { return this.out("-update", seconds); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-units proto.units = function units (type) { return this.out("-units", type); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-unsharp proto.unsharp = function unsharp (radius, sigma, amount, threshold) { var arg=radius; if (typeof sigma != 'undefined') arg+='x'+sigma; if (typeof amount != 'undefined') arg+='+'+amount; if (typeof threshold != 'undefined') arg+='+'+threshold; return this.out("-unsharp", arg); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-use-pixmap proto.usePixmap = function usePixmap () { return this.out("-use-pixmap"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-view proto.view = function view (string) { return this.out("-view", string); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-virtual-pixel proto.virtualPixel = function virtualPixel (method) { return this.out("-virtual-pixel", method); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-visual proto.visual = function visual (type) { return this.out("-visual", type); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-watermark proto.watermark = function watermark (brightness, saturation) { return this.out("-watermark", brightness+'x'+saturation); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-wave proto.wave = function wave (amplitude, wavelength) { return this.out("-wave", amplitude+'x'+wavelength); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-white-point proto.whitePoint = function whitePoint (x, y) { return this.out("-white-point", x+'x'+y); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-white-threshold proto.whiteThreshold = function whiteThreshold (red, green, blue, opacity) { return this.out("-white-threshold", argsToArray(red, green, blue, opacity).join(',')); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-window proto.window = function window (id) { return this.out("-window", id); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-window-group proto.windowGroup = function windowGroup () { return this.out("-window-group"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-strip (graphicsMagick >= 1.3.15) proto.strip = function strip () { if (this._options.imageMagick) return this.out("-strip"); return this.noProfile().out("+comment");//Equivalent to "-strip" for all versions of graphicsMagick } // http://www.graphicsmagick.org/GraphicsMagick.html#details-interlace proto.interlace = function interlace (type) { return this.out("-interlace", type || "None"); } // force output format proto.setFormat = function setFormat (format) { if (format) this._outputFormat = format; return this; } // http://www.graphicsmagick.org/GraphicsMagick.html#details-resize proto.resize = function resize (w, h, options) { options = options || ""; var geometry, wIsValid = Boolean(w || w === 0), hIsValid = Boolean(h || h === 0); if (wIsValid && hIsValid) { geometry = w + "x" + h + options } else if (wIsValid) { // GraphicsMagick requires x, ImageMagick requires geometry = (this._options.imageMagick) ? w + options : w + 'x' + options; } else if (hIsValid) { geometry = 'x' + h + options } else { return this } return this.out("-resize", geometry); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-resize with '!' option proto.resizeExact = function resize (w, h) { var options = "!"; return proto.resize.apply(this, [w, h, options]); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-scale proto.scale = function scale (w, h, options) { options = options || ""; var geometry; if (w && h) { geometry = w + "x" + h + options } else if (w && !h) { geometry = (this._options.imageMagick) ? w + options : w + 'x' + options; } else if (!w && h) { geometry = 'x' + h + options } return this.out("-scale", geometry); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-filter proto.filter = function filter (val) { return this.out("-filter", val); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-density proto.density = function density (w, h) { if (w && !h && this._options.imageMagick) { // GraphicsMagick requires xy, ImageMagick may take dpi // recommended 300dpi for higher quality return this.in("-density", w); } return this.in("-density", w +"x"+ h); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-profile proto.noProfile = function noProfile () { this.out('+profile', '"*"'); return this; } // http://www.graphicsmagick.org/GraphicsMagick.html#details-resample proto.resample = function resample (w, h) { return this.out("-resample", w+"x"+h); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-rotate proto.rotate = function rotate (color, deg) { return this.out("-background", color, "-rotate", String(deg || 0)); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-flip proto.flip = function flip () { return this.out("-flip"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-flop proto.flop = function flop () { return this.out("-flop"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-crop proto.crop = function crop (w, h, x, y, percent) { if (this.inputIs('jpg')) { // avoid error "geometry does not contain image (unable to crop image)" - gh-17 var index = this._in.indexOf('-size'); if (~index) { this._in.splice(index, 2); } } return this.out("-crop", w + "x" + h + "+" + (x || 0) + "+" + (y || 0) + (percent ? '%' : '')); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-magnify proto.magnify = function magnify (factor) { return this.in("-magnify"); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.minify = function minify () { return this.in("-minify") } // http://www.graphicsmagick.org/GraphicsMagick.html#details-quality proto.quality = function quality (val) { return this.in("-quality", val || 75); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-blur proto.blur = function blur (radius, sigma) { return this.out("-blur", radius + (sigma ? "x"+sigma : "")); } // http://www.graphicsmagick.org/convert.html proto.charcoal = function charcoal (factor) { return this.out("-charcoal", factor || 2); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-modulate proto.modulate = function modulate (b, s, h) { return this.out("-modulate", [b,s,h].join(",")); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-antialias // note: antialiasing is enabled by default proto.antialias = function antialias (disable) { return false === disable ? this.out("+antialias") : this; } // http://www.graphicsmagick.org/GraphicsMagick.html#details-depth proto.bitdepth = function bitdepth (val) { return this.out("-depth", val); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-colors proto.colors = function colors (val) { return this.out("-colors", val || 128); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-colorspace proto.colorspace = function colorspace (val) { return this.out("-colorspace", val); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-comment proto.comment = comment("-comment"); // http://www.graphicsmagick.org/GraphicsMagick.html#details-contrast proto.contrast = function contrast (mult) { var arg = (parseInt(mult, 10) || 0) > 0 ? "+contrast" : "-contrast"; mult = Math.abs(mult) || 1; while (mult--) { this.out(arg); } return this; } // http://www.graphicsmagick.org/GraphicsMagick.html#details-cycle proto.cycle = function cycle (amount) { return this.out("-cycle", amount || 2); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.despeckle = function despeckle () { return this.out("-despeckle"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-dither // note: either colors() or monochrome() must be used for this // to take effect. proto.dither = function dither (on) { var sign = false === on ? "+" : "-"; return this.out(sign + "dither"); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.monochrome = function monochrome () { return this.out("-monochrome"); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.edge = function edge (radius) { return this.out("-edge", radius || 1); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.emboss = function emboss (radius) { return this.out("-emboss", radius || 1); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.enhance = function enhance () { return this.out("-enhance"); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.equalize = function equalize () { return this.out("-equalize"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-gamma proto.gamma = function gamma (r, g, b) { return this.out("-gamma", [r,g,b].join()); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.implode = function implode (factor) { return this.out("-implode", factor || 1); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-comment proto.label = comment("-label"); var limits = [ "disk", "file", "map", "memory", "pixels", "threads"]; // http://www.graphicsmagick.org/GraphicsMagick.html#details-limit proto.limit = function limit (type, val) { type = type.toLowerCase(); if (!~limits.indexOf(type)) { return this; } return this.out("-limit", type, val); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.median = function median (radius) { return this.out("-median", radius || 1); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-negate proto.negative = function negative (grayscale) { var sign = grayscale ? "+" : "-"; return this.out(sign + "negate"); } var noises = [ "uniform" , "gaussian" , "multiplicative" , "impulse" , "laplacian" , "poisson" ]; // http://www.graphicsmagick.org/GraphicsMagick.html#details-noise proto.noise = function noise (radius) { radius = (String(radius)).toLowerCase(); var sign = ~noises.indexOf(radius) ? "+" : "-"; return this.out(sign + "noise", radius); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-paint proto.paint = function paint (radius) { return this.out("-paint", radius); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-raise proto.raise = function raise (w, h) { return this.out("-raise", (w||0)+"x"+(h||0)); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-raise proto.lower = function lower (w, h) { return this.out("+raise", (w||0)+"x"+(h||0)); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-region proto.region = function region (w, h, x, y) { w = w || 0; h = h || 0; x = x || 0; y = y || 0; return this.out("-region", w + "x" + h + "+" + x + "+" + y); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-roll proto.roll = function roll (x, y) { x = ((x = parseInt(x, 10) || 0) >= 0 ? "+" : "") + x; y = ((y = parseInt(y, 10) || 0) >= 0 ? "+" : "") + y; return this.out("-roll", x+y); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-sharpen proto.sharpen = function sharpen (radius, sigma) { sigma = sigma ? "x" + sigma : ""; return this.out("-sharpen", radius + sigma); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-solarize proto.solarize = function solarize (factor) { return this.out("-solarize", (factor || 1)+"%"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-spread proto.spread = function spread (amount) { return this.out("-spread", amount || 5); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-swirl proto.swirl = function swirl (degrees) { return this.out("-swirl", degrees || 180); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-type proto.type = function type (type) { return this.in("-type", type); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-trim proto.trim = function trim () { return this.out("-trim"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-extent proto.extent = function extent (w, h, options) { options = options || ""; var geometry; if (w && h) { geometry = w + "x" + h + options } else if (w && !h) { geometry = (this._options.imageMagick) ? w + options : w + 'x' + options; } else if (!w && h) { geometry = 'x' + h + options } return this.out("-extent", geometry); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-gravity // Be sure to use gravity BEFORE extent proto.gravity = function gravity (type) { if (!type || !~gravity.types.indexOf(type)) { type = "NorthWest"; // Documented default. } return this.out("-gravity", type); } proto.gravity.types = [ "NorthWest" , "North" , "NorthEast" , "West" , "Center" , "East" , "SouthWest" , "South" , "SouthEast" ]; // http://www.graphicsmagick.org/GraphicsMagick.html#details-flatten proto.flatten = function flatten () { return this.out("-flatten"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-background proto.background = function background (color) { return this.in("-background", color); } }; /** * Generates a handler for comments/labels. */ function comment (arg) { return function (format) { format = String(format); format = "@" == format.charAt(0) ? format.substring(1) : format; return this.out(arg, '"' + format + '"'); } } ================================================ FILE: lib/command.js ================================================ /** * Module dependencies. */ var spawn = require('cross-spawn'); var utils = require('./utils'); var debug = require('debug')('gm'); var series = require('array-series'); var PassThrough = require('stream').PassThrough; /** * Error messaging. */ var noBufferConcat = 'gm v1.9.0+ required node v0.8+. Please update your version of node, downgrade gm < 1.9, or do not use `bufferStream`.'; /** * Extend proto */ module.exports = function (proto) { function args (prop) { return function args () { var len = arguments.length; var a = []; var i = 0; for (; i < len; ++i) { a.push(arguments[i]); } this[prop] = this[prop].concat(a); return this; } } function streamToUnemptyBuffer(stream, callback) { var done = false var buffers = [] stream.on('data', function (data) { buffers.push(data) }) stream.on('end', function () { if (done) return done = true let result = Buffer.concat(buffers) buffers = null if (result.length === 0) { const err = new Error("Stream yields empty buffer"); callback(err, null); } else { callback(null, result); } }) stream.on('error', function (err) { done = true buffers = null callback(err) }) } proto.in = args('_in'); proto.out = args('_out'); proto._preprocessor = []; proto.preprocessor = args('_preprocessor'); /** * Execute the command and write the image to the specified file name. * * @param {String} name * @param {Function} callback * @return {Object} gm */ proto.write = function write (name, callback) { if (!callback) callback = name, name = null; if ("function" !== typeof callback) { throw new TypeError("gm().write() expects a callback function") } if (!name) { return callback(TypeError("gm().write() expects a filename when writing new files")); } this.outname = name; var self = this; this._preprocess(function (err) { if (err) return callback(err); self._spawn(self.args(), true, callback); }); } /** * Execute the command and return stdin and stderr * ReadableStreams providing the image data. * If no callback is passed, a "through" stream will be returned, * and stdout will be piped through, otherwise the error will be passed. * * @param {String} format (optional) * @param {Function} callback (optional) * @return {Stream} */ proto.stream = function stream (format, callback) { if (!callback && typeof format === 'function') { callback = format; format = null; } var throughStream; if ("function" !== typeof callback) { throughStream = new PassThrough(); callback = function (err, stdout, stderr) { if (err) throughStream.emit('error', err); else stdout.pipe(throughStream); } } if (format) { format = format.split('.').pop(); this.outname = format + ":-"; } var self = this; this._preprocess(function (err) { if (err) return callback(err); return self._spawn(self.args(), false, callback); }); return throughStream || this; } /** * Convenience function for `proto.stream`. * Simply returns the buffer instead of the stream. * * @param {String} format (optional) * @param {Function} callback * @return {null} */ proto.toBuffer = function toBuffer (format, callback) { if (!callback) callback = format, format = null; if ("function" !== typeof callback) { throw new Error('gm().toBuffer() expects a callback.'); } return this.stream(format, function (err, stdout) { if (err) return callback(err); streamToUnemptyBuffer(stdout, callback); }) } /** * Run any preProcessor functions in series. Used by autoOrient. * * @param {Function} callback * @return {Object} gm */ proto._preprocess = function _preprocess (callback) { series(this._preprocessor, this, callback); } /** * Execute the command, buffer input and output, return stdout and stderr buffers. * * @param {String} bin * @param {Array} args * @param {Function} callback * @return {Object} gm */ proto._exec = function _exec (args, callback) { return this._spawn(args, true, callback); } /** * Execute the command with stdin, returning stdout and stderr streams or buffers. * @param {String} bin * @param {Array} args * @param {ReadableStream} stream * @param {Boolean} shouldBuffer * @param {Function} callback, signature (err, stdout, stderr) -> * * @return {Object} gm * @TODO refactor this mess */ proto._spawn = function _spawn (args, bufferOutput, callback) { var appPath = this._options.appPath || ''; var bin // Resolve executable switch (this._options.imageMagick) { // legacy behavior case true: bin = args.shift(); break; // ImgeMagick >= 7 case '7+': bin = 'magick' break; // GraphicsMagick default: bin = 'gm'; break; } // Prepend app path bin = appPath + bin var cmd = bin + ' ' + args.map(utils.escape).join(' ') , self = this , proc, err , timeout = parseInt(this._options.timeout) , disposers = this._options.disposers , timeoutId; debug(cmd); //imageMagick does not support minify (https://github.com/aheckmann/gm/issues/385) if(args.indexOf("-minify") > -1 && this._options.imageMagick){ return cb(new Error("imageMagick does not support minify, use -scale or -sample. Alternatively, use graphicsMagick")); } try { proc = spawn(bin, args); } catch (e) { return cb(e); } proc.stdin.once('error', cb); proc.on('error', function(err){ if (err.code === 'ENOENT') { cb(new Error('Could not execute GraphicsMagick/ImageMagick: '+cmd+" this most likely means the gm/convert binaries can't be found")); } else { cb(err); } }); if (timeout) { timeoutId = setTimeout(function(){ dispose('gm() resulted in a timeout.'); }, timeout); } if (disposers) { disposers.forEach(function(disposer) { disposer.events.forEach(function(event) { disposer.emitter.on(event, dispose); }); }); } if (self.sourceBuffer) { proc.stdin.write(this.sourceBuffer); proc.stdin.end(); } else if (self.sourceStream) { if (!self.sourceStream.readable) { return cb(new Error("gm().stream() or gm().write() with a non-readable stream.")); } self.sourceStream.pipe(proc.stdin); // bufferStream // We convert the input source from a stream to a buffer. if (self.bufferStream && !this._buffering) { if (!Buffer.concat) { throw new Error(noBufferConcat); } // Incase there are multiple processes in parallel, // we only need one self._buffering = true; streamToUnemptyBuffer(self.sourceStream, function (err, buffer) { self.sourceBuffer = buffer; self.sourceStream = null; // The stream is now dead }) } } // for _exec operations (identify() mostly), we also // need to buffer the output stream before returning if (bufferOutput) { var stdout = '' , stderr = '' , onOut , onErr , onExit proc.stdout.on('data', onOut = function (data) { stdout += data; }); proc.stderr.on('data', onErr = function (data) { stderr += data; }); proc.on('close', onExit = function (code, signal) { let err; if (code !== 0 || signal !== null) { err = new Error('Command failed: ' + stderr); err.code = code; err.signal = signal; }; cb(err, stdout, stderr, cmd); stdout = stderr = onOut = onErr = onExit = null; }); } else { cb(null, proc.stdout, proc.stderr, cmd); } return self; function cb (err, stdout, stderr, cmd) { if (cb.called) return; if (timeoutId) clearTimeout(timeoutId); cb.called = 1; if (args[0] !== 'identify' && bin !== 'identify') { self._in = []; self._out = []; } callback.call(self, err, stdout, stderr, cmd); } function dispose (msg) { const message = msg ? msg : 'gm() was disposed'; const err = new Error(message); cb(err); if (proc.exitCode === null) { proc.stdin.pause(); proc.kill(); } } } /** * Returns arguments to be used in the command. * * @return {Array} */ proto.args = function args () { var outname = this.outname || "-"; if (this._outputFormat) outname = this._outputFormat + ':' + outname; return [].concat( this._subCommand , this._in , this.src() , this._out , outname ).filter(Boolean); // remove falsey } /** * Adds an img source formatter. * * `formatters` are passed an array of images which will be * used as 'input' images for the command. Useful for methods * like `.append()` where multiple source images may be used. * * @param {Function} formatter * @return {gm} this */ proto.addSrcFormatter = function addSrcFormatter (formatter) { if ('function' != typeof formatter) throw new TypeError('sourceFormatter must be a function'); this._sourceFormatters || (this._sourceFormatters = []); this._sourceFormatters.push(formatter); return this; } /** * Applies all _sourceFormatters * * @return {Array} */ proto.src = function src () { var arr = []; for (var i = 0; i < this._sourceFormatters.length; ++i) { this._sourceFormatters[i].call(this, arr); } return arr; } /** * Image types. */ var types = { 'jpg': /\.jpe?g$/i , 'png' : /\.png$/i , 'gif' : /\.gif$/i , 'tiff': /\.tif?f$/i , 'bmp' : /(?:\.bmp|\.dib)$/i , 'webp': /\.webp$/i }; types.jpeg = types.jpg; types.tif = types.tiff; types.dib = types.bmp; /** * Determine the type of source image. * * @param {String} type * @return {Boolean} * @example * if (this.inputIs('png')) ... */ proto.inputIs = function inputIs (type) { if (!type) return false; var rgx = types[type]; if (!rgx) { if ('.' !== type[0]) type = '.' + type; rgx = new RegExp('\\' + type + '$', 'i'); } return rgx.test(this.source); } /** * add disposer (like 'close' of http.IncomingMessage) in order to dispose gm() with any event * * @param {EventEmitter} emitter * @param {Array} events * @return {Object} gm * @example * command.addDisposer(req, ['close', 'end', 'finish']); */ proto.addDisposer = function addDisposer (emitter, events) { if (!this._options.disposers) { this._options.disposers = []; } this._options.disposers.push({ emitter: emitter, events: events }); return this; }; } ================================================ FILE: lib/compare.js ================================================ // compare var spawn = require('cross-spawn'); var debug = require('debug')('gm'); var utils = require('./utils'); /** * Compare two images uses graphicsmagicks `compare` command. * * gm.compare(img1, img2, 0.4, function (err, equal, equality) { * if (err) return handle(err); * console.log('The images are equal: %s', equal); * console.log('There equality was %d', equality); * }); * * @param {String} orig Path to an image. * @param {String} compareTo Path to another image to compare to `orig`. * @param {Number|Object} [options] Options object or the amount of difference to tolerate before failing - defaults to 0.4 * @param {Function} cb(err, Boolean, equality, rawOutput) */ module.exports = exports = function (proto) { function compare(orig, compareTo, options, cb) { var isImageMagick = this._options && this._options.imageMagick; var appPath = this._options && this._options.appPath || ''; var args = ['-metric', 'mse', orig, compareTo]; // Resove executable let bin; switch (isImageMagick) { case true: bin = 'compare'; break; case '7+': bin = 'magick' args.unshift('compare'); break; default: bin = 'gm' args.unshift('compare'); break } // Prepend app path bin = appPath + bin var tolerance = 0.4; // outputting the diff image if (typeof options === 'object') { if (options.highlightColor && options.highlightColor.indexOf('"') < 0) { options.highlightColor = '"' + options.highlightColor + '"'; } if (options.file) { if (typeof options.file !== 'string') { throw new TypeError('The path for the diff output is invalid'); } // graphicsmagick defaults to red if (options.highlightColor) { args.push('-highlight-color'); args.push(options.highlightColor); } if (options.highlightStyle) { args.push('-highlight-style') args.push(options.highlightStyle) } // For IM, filename is the last argument. For GM it's `-file ` if (!isImageMagick) { args.push('-file'); } args.push(options.file); } if (typeof options.tolerance != 'undefined') { if (typeof options.tolerance !== 'number') { throw new TypeError('The tolerance value should be a number'); } tolerance = options.tolerance; } } else { // For ImageMagick diff file is required but we don't care about it, so null it out if (isImageMagick) { args.push('null:'); } if (typeof options == 'function') { cb = options; // tolerance value not provided, flip the cb place } else { tolerance = options } } var cmd = bin + ' ' + args.map(utils.escape).join(' ') debug(cmd); var proc = spawn(bin, args); var stdout = ''; var stderr = ''; proc.stdout.on('data',function(data) { stdout+=data }); proc.stderr.on('data',function(data) { stderr+=data }); proc.on('close', function (code) { // ImageMagick returns err code 2 if err, 0 if similar, 1 if dissimilar if (isImageMagick) { if (code === 0) { return cb(null, 0 <= tolerance, 0, stdout); } else if (code === 1) { stdout = stderr; } else { return cb(stderr); } } else { if(code !== 0) { return cb(stderr); } } // Since ImageMagick similar gives err code 0 and no stdout, there's really no matching // Otherwise, output format for IM is `12.00 (0.123)` and for GM it's `Total: 0.123` var regex = isImageMagick ? /\((\d+\.?[\d\-\+e]*)\)/m : /Total: (\d+\.?\d*)/m; var match = regex.exec(stdout); if (!match) { return cb(new Error('Unable to parse output.\nGot ' + stdout)); } var equality = parseFloat(match[1]); cb(null, equality <= tolerance, equality, stdout, orig, compareTo); }); } if (proto) { proto.compare = compare; } return compare; }; ================================================ FILE: lib/composite.js ================================================ // composite /** * Composite images together using the `composite` command in graphicsmagick. * * gm('/path/to/image.jpg') * .composite('/path/to/second_image.jpg') * .geometry('+100+150') * .write('/path/to/composite.png', function(err) { * if(!err) console.log("Written composite image."); * }); * * @param {String} other Path to the image that contains the changes. * @param {String} [mask] Path to the image with opacity informtion. Grayscale. */ module.exports = exports = function(proto) { proto.composite = function(other, mask) { this.in(other); // If the mask is defined, add it to the output. if(typeof mask !== "undefined") this.out(mask); this.subCommand("composite"); return this; } } ================================================ FILE: lib/convenience/autoOrient.js ================================================ /** * Extend proto. */ module.exports = function (proto) { var exifTransforms = { topleft: '' , topright: ['-flop'] , bottomright: ['-rotate', 180] , bottomleft: ['-flip'] , lefttop: ['-flip', '-rotate', 90] , righttop: ['-rotate', 90] , rightbottom: ['-flop', '-rotate', 90] , leftbottom: ['-rotate', 270] } proto.autoOrient = function autoOrient () { // Always strip EXIF data since we can't // change/edit it. // imagemagick has a native -auto-orient option // so does graphicsmagick, but in 1.3.18. // nativeAutoOrient option enables this if you know you have >= 1.3.18 if (this._options.nativeAutoOrient || this._options.imageMagick) { this.out('-auto-orient'); return this; } this.preprocessor(function (callback) { this.orientation({bufferStream: true}, function (err, orientation) { if (err) return callback(err); var transforms = exifTransforms[orientation.toLowerCase()]; if (transforms) { // remove any existing transforms that might conflict var index = this._out.indexOf(transforms[0]); if (~index) { this._out.splice(index, transforms.length); } // repage to fix coordinates this._out.unshift.apply(this._out, transforms.concat('-page', '+0+0')); } callback(); }); }); return this; } } ================================================ FILE: lib/convenience/morph.js ================================================ /** * Module dependencies. */ var fs = require('fs'); var parallel = require('array-parallel'); /** * Extend proto. */ module.exports = function (proto) { /** * Do nothing. */ function noop () {} // http://www.graphicsmagick.org/GraphicsMagick.html#details-morph proto.morph = function morph (other, outname, callback) { if (!outname) { throw new Error("an output filename is required"); } callback = (callback || noop).bind(this) var self = this; if (Array.isArray(other)) { other.forEach(function (img) { self.out(img); }); self.out("-morph", other.length); } else { self.out(other, "-morph", 1); } self.write(outname, function (err, stdout, stderr, cmd) { if (err) return callback(err, stdout, stderr, cmd); // Apparently some platforms create the following temporary files. // Check if the output file exists, if it doesn't, then // work with temporary files. fs.exists(outname, function (exists) { if (exists) return callback(null, stdout, stderr, cmd); parallel([ fs.unlink.bind(fs, outname + '.0'), fs.unlink.bind(fs, outname + '.2'), fs.rename.bind(fs, outname + '.1', outname) ], function (err) { callback(err, stdout, stderr, cmd); }) }) }); return self; } } ================================================ FILE: lib/convenience/sepia.js ================================================ /** * Extend proto. */ module.exports = function (proto) { proto.sepia = function sepia () { return this.modulate(115, 0, 100).colorize(7, 21, 50); } } ================================================ FILE: lib/convenience/thumb.js ================================================ /** * Extend proto. */ module.exports = function (proto) { proto.thumb = function thumb (w, h, name, quality, align, progressive, callback, opts) { var self = this, args = Array.prototype.slice.call(arguments); opts = args.pop(); if (typeof opts === 'function') { callback = opts; opts = ''; } else { callback = args.pop(); } w = args.shift(); h = args.shift(); name = args.shift(); quality = args.shift() || 63; align = args.shift() || 'topleft'; var interlace = args.shift() ? 'Line' : 'None'; self.size(function (err, size) { if (err) { return callback.apply(self, arguments); } w = parseInt(w, 10); h = parseInt(h, 10); var w1, h1; var xoffset = 0; var yoffset = 0; if (size.width < size.height) { w1 = w; h1 = Math.floor(size.height * (w/size.width)); if (h1 < h) { w1 = Math.floor(w1 * (((h-h1)/h) + 1)); h1 = h; } } else if (size.width > size.height) { h1 = h; w1 = Math.floor(size.width * (h/size.height)); if (w1 < w) { h1 = Math.floor(h1 * (((w-w1)/w) + 1)); w1 = w; } } else if (size.width == size.height) { var bigger = (w>h?w:h); w1 = bigger; h1 = bigger; } if (align == 'center') { if (w < w1) { xoffset = (w1-w)/2; } if (h < h1) { yoffset = (h1-h)/2; } } self .quality(quality) .in("-size", w1+"x"+h1) .scale(w1, h1, opts) .crop(w, h, xoffset, yoffset) .interlace(interlace) .noProfile() .write(name, function () { callback.apply(self, arguments); }); }); return self; }; proto.thumbExact = function () { var self = this, args = Array.prototype.slice.call(arguments); args.push('!'); self.thumb.apply(self, args); }; }; ================================================ FILE: lib/convenience.js ================================================ /** * Extend proto */ module.exports = function (proto) { require("./convenience/thumb")(proto); require("./convenience/morph")(proto); require("./convenience/sepia")(proto); require("./convenience/autoOrient")(proto); } ================================================ FILE: lib/drawing.js ================================================ /** * Module dependencies. */ var escape = require('./utils').escape; /** * Extend proto. */ module.exports = function (proto) { // http://www.graphicsmagick.org/GraphicsMagick.html#details-fill proto.fill = function fill (color) { return this.out("-fill", color || "none"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-stroke proto.stroke = function stroke (color, width) { if (width) { this.strokeWidth(width); } return this.out("-stroke", color || "none"); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-strokewidth proto.strokeWidth = function strokeWidth (width) { return this.out("-strokewidth", width); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-font proto.font = function font (font, size) { if (size) { this.fontSize(size); } return this.out("-font", font); } // http://www.graphicsmagick.org/GraphicsMagick.html proto.fontSize = function fontSize (size) { return this.out("-pointsize", size); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.draw = function draw (args) { return this.out("-draw", [].slice.call(arguments).join(" ")); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawPoint = function drawPoint (x, y) { return this.draw("point", x +","+ y); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawLine = function drawLine (x0, y0, x1, y1) { return this.draw("line", x0+","+y0, x1+","+y1); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawRectangle = function drawRectangle (x0, y0, x1, y1, wc, hc) { var shape = "rectangle" , lastarg; if ("undefined" !== typeof wc) { shape = "roundRectangle"; if ("undefined" === typeof hc) { hc = wc; } lastarg = wc+","+hc; } return this.draw(shape, x0+","+y0, x1+","+y1, lastarg); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawArc = function drawArc (x0, y0, x1, y1, a0, a1) { return this.draw("arc", x0+","+y0, x1+","+y1, a0+","+a1); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawEllipse = function drawEllipse (x0, y0, rx, ry, a0, a1) { if (a0 == undefined) a0 = 0; if (a1 == undefined) a1 = 360; return this.draw("ellipse", x0+","+y0, rx+","+ry, a0+","+a1); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawCircle = function drawCircle (x0, y0, x1, y1) { return this.draw("circle", x0+","+y0, x1+","+y1); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawPolyline = function drawPolyline () { return this.draw("polyline", formatPoints(arguments)); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawPolygon = function drawPolygon () { return this.draw("polygon", formatPoints(arguments)); } // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawBezier = function drawBezier () { return this.draw("bezier", formatPoints(arguments)); } proto._gravities = [ "northwest" , "north" , "northeast" , "west" , "center" , "east" , "southwest" , "south" , "southeast"]; // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.drawText = function drawText (x0, y0, text, gravity) { var gravity = String(gravity || "").toLowerCase() , arg = ["text " + x0 + "," + y0 + " " + escape(text)]; if (~this._gravities.indexOf(gravity)) { arg.unshift("gravity", gravity); } return this.draw.apply(this, arg); } proto._drawProps = ["color", "matte"]; // http://www.graphicsmagick.org/GraphicsMagick.html#details-draw proto.setDraw = function setDraw (prop, x, y, method) { prop = String(prop || "").toLowerCase(); if (!~this._drawProps.indexOf(prop)) { return this; } return this.draw(prop, x+","+y, method); } } function formatPoints (points) { var len = points.length , result = [] , i = 0; for (; i < len; ++i) { result.push(points[i].join(",")); } return result; } ================================================ FILE: lib/getters.js ================================================ /** * Extend proto. */ module.exports = function (gm) { var proto = gm.prototype; /** * `identify` states */ const IDENTIFYING = 1; const IDENTIFIED = 2; /** * Map getter functions to output names. * * - format: specifying the -format argument (see man gm) * - verbose: use -verbose instead of -format (only if necessary b/c its slow) * - helper: use the conversion helper */ var map = { 'format': { key: 'format', format: '%m ', helper: 'Format' } , 'depth': { key: 'depth', format: '%q' } , 'filesize': { key: 'Filesize', format: '%b' } , 'size': { key: 'size', format: '%wx%h ', helper: 'Geometry' } , 'color': { key: 'color', format: '%k', helper: 'Colors' } , 'orientation': { key: 'Orientation', format: '%[EXIF:Orientation]', helper: 'Orientation' } , 'res': { key: 'Resolution', verbose: true } } /** * Getter functions */ Object.keys(map).forEach(function (getter) { proto[getter] = function (opts, callback) { if (!callback) callback = opts, opts = {}; if (!callback) return this; var val = map[getter] , key = val.key , self = this; if (self.data[key]) { callback.call(self, null, self.data[key]); return self; } self.on(getter, callback); self.bufferStream = !!opts.bufferStream; if (val.verbose) { self.identify(opts, function (err, stdout, stderr, cmd) { if (err) { self.emit(getter, err, self.data[key], stdout, stderr, cmd); } else { self.emit(getter, err, self.data[key]); } }); return self; } var args = makeArgs(self, val); self._exec(args, function (err, stdout, stderr, cmd) { if (err) { self.emit(getter, err, self.data[key], stdout, stderr, cmd); return; } var result = (stdout||'').trim(); if (val.helper in helper) { helper[val.helper](self.data, result); } else { self.data[key] = result; } self.emit(getter, err, self.data[key]); }); return self; } }); /** * identify command * * Overwrites all internal data with the parsed output * which is more accurate than the fast shortcut * getters. */ proto.identify = function identify (opts, callback) { // identify with pattern if (typeof(opts) === 'string') { opts = { format: opts } } if (!callback) callback = opts, opts = {}; if (!callback) return this; if (opts && opts.format) return identifyPattern.call(this, opts, callback); var self = this; if (IDENTIFIED === self._identifyState) { callback.call(self, null, self.data); return self; } self.on('identify', callback); if (IDENTIFYING === self._identifyState) { return self; } self._identifyState = IDENTIFYING; self.bufferStream = !!opts.bufferStream; var args = makeArgs(self, { verbose: true }); self._exec(args, function (err, stdout, stderr, cmd) { if (err) { self.emit('identify', err, self.data, stdout, stderr, cmd); return; } err = parse(stdout, self); if (err) { self.emit('identify', err, self.data, stdout, stderr, cmd); return; } self.data.path = self.source; self.emit('identify', null, self.data); self._identifyState = IDENTIFIED; }); return self; } /** * identify with pattern * * Execute `identify -format` with custom pattern */ function identifyPattern (opts, callback) { var self = this; self.bufferStream = !!opts.bufferStream; var args = makeArgs(self, opts); self._exec(args, function (err, stdout, stderr, cmd) { if (err) { return callback.call(self, err, undefined, stdout, stderr, cmd); } callback.call(self, err, (stdout||'').trim()); }); return self; } /** * Parses `identify` responses. * * @param {String} stdout * @param {Gm} self * @return {Error} [optionally] */ function parse (stdout, self) { // normalize var parts = (stdout||"").trim().replace(/\r\n|\r/g, "\n").split("\n"); // skip the first line (its just the filename) parts.shift(); try { var len = parts.length , rgx1 = /^( *)(.+?): (.*)$/ // key: val , rgx2 = /^( *)(.+?):$/ // key: begin nested object , out = { indent: {} } , level = null , lastkey , i = 0 , res , o for (; i < len; ++i) { res = rgx1.exec(parts[i]) || rgx2.exec(parts[i]); if (!res) continue; var indent = res[1].length , key = res[2] ? res[2].trim() : ''; if ('Image' == key || 'Warning' == key) continue; var val = res[3] ? res[3].trim() : null; // first iteration? if (null === level) { level = indent; o = out.root = out.indent[level] = self.data; } else if (indent < level) { // outdent if (!(indent in out.indent)) { continue; } o = out.indent[indent]; } else if (indent > level) { // dropping into a nested object out.indent[level] = o; // weird format, key/val pair with nested children. discard the val o = o[lastkey] = {}; } level = indent; if (val) { // if previous key was exist and we got the same key // cast it to an array. if(o.hasOwnProperty(key)){ // cast it to an array and dont forget the previous value if(!Array.isArray(o[key])){ var tmp = o[key]; o[key] = [tmp]; } // set value o[key].push(val); } else { o[key] = val; } if (key in helper) { helper[key](o, val); } } lastkey = key; } } catch (err) { err.message = err.message + "\n\n Identify stdout:\n " + stdout; return err; } } /** * Create an argument array for the identify command. * * @param {gm} self * @param {Object} val * @return {Array} */ function makeArgs (self, val) { var args = [ 'identify' , '-ping' ]; if (val.format) { args.push('-format', val.format); } if (val.verbose) { args.push('-verbose'); } args = args.concat(self.src()); return args; } /** * Map exif orientation codes to orientation names. */ var orientations = { '1': 'TopLeft' , '2': 'TopRight' , '3': 'BottomRight' , '4': 'BottomLeft' , '5': 'LeftTop' , '6': 'RightTop' , '7': 'RightBottom' , '8': 'LeftBottom' } /** * identify -verbose helpers */ var helper = gm.identifyHelpers = {}; helper.Geometry = function Geometry (o, val) { // We only want the size of the first frame. // Each frame is separated by a space. var split = val.split(" ").shift().split("x"); var width = parseInt(split[0], 10); var height = parseInt(split[1], 10); if (o.size && o.size.width && o.size.height) { if (width > o.size.width) o.size.width = width; if (height > o.size.height) o.size.height = height; } else { o.size = { width: width, height: height } } }; helper.Format = function Format (o, val) { o.format = val.split(" ")[0]; }; helper.Depth = function Depth (o, val) { o.depth = parseInt(val, 10); }; helper.Colors = function Colors (o, val) { o.color = parseInt(val, 10); }; helper.Orientation = function Orientation (o, val) { if (val in orientations) { o['Profile-EXIF'] || (o['Profile-EXIF'] = {}); o['Profile-EXIF'].Orientation = val; o.Orientation = orientations[val]; } else { o.Orientation = val || 'Unknown'; } }; } ================================================ FILE: lib/montage.js ================================================ // montage /** * Montage images next to each other using the `montage` command in graphicsmagick. * * gm('/path/to/image.jpg') * .montage('/path/to/second_image.jpg') * .geometry('+100+150') * .write('/path/to/montage.png', function(err) { * if(!err) console.log("Written montage image."); * }); * * @param {String} other Path to the image that contains the changes. */ module.exports = exports = function(proto) { proto.montage = function(other) { this.in(other); this.subCommand("montage"); return this; } } ================================================ FILE: lib/options.js ================================================ module.exports = exports = function (proto) { proto._options = {}; proto.options = function setOptions (options) { var keys = Object.keys(options) , i = keys.length , key while (i--) { key = keys[i]; this._options[key] = options[key]; } return this; } } ================================================ FILE: lib/utils.js ================================================ /** * Escape the given shell `arg`. * * @param {String} arg * @return {String} * @api public */ exports.escape = function escape (arg) { return '"' + String(arg).trim().replace(/"/g, '\\"') + '"'; }; exports.unescape = function escape (arg) { return String(arg).trim().replace(/"/g, ""); }; exports.argsToArray = function (args) { var arr = []; for (var i = 0; i <= arguments.length; i++) { if ('undefined' != typeof arguments[i]) arr.push(arguments[i]); } return arr; }; exports.isUtil = function (v) { var ty = 'object'; switch (Object.prototype.toString.call(v)) { case '[object String]': ty = 'String'; break; case '[object Array]': ty = 'Array'; break; case '[object Boolean]': ty = 'Boolean'; break; } return ty; } ================================================ FILE: package.json ================================================ { "name": "gm", "description": "GraphicsMagick and ImageMagick for node.js", "version": "1.25.1", "author": "Aaron Heckmann ", "keywords": [ "graphics", "magick", "image", "graphicsmagick", "imagemagick", "gm", "convert", "identify", "compare" ], "engines": { "node": ">=14" }, "bugs": { "url": "http://github.com/aheckmann/gm/issues" }, "licenses": [ { "type": "MIT", "url": "http://www.opensource.org/licenses/mit-license.php" } ], "main": "./index", "scripts": { "security": "npm audit", "test": "npm run security && npm run test-integration", "test-integration": "node test/ --integration", "test-unit": "node test/" }, "repository": { "type": "git", "url": "https://github.com/aheckmann/gm.git" }, "license": "MIT", "devDependencies": { "async": "~0.9.0" }, "dependencies": { "array-parallel": "~0.1.3", "array-series": "~0.1.5", "cross-spawn": "^7.0.5", "debug": "^3.1.0" } } ================================================ FILE: test/109.js ================================================ const fs = require('fs'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const original = path.join(dir, 'original.jpg'); const buf = fs.readFileSync(original); const m = gm(buf, 'original.jpg').options({ imageMagick }); m.identify(function (err, _) { finish(err); }); } ================================================ FILE: test/118.js ================================================ /* * If only the width is specified for a resize operation, * GraphicsMagick requires the format * -resize 10x * while ImageMagick requires the format * -resize 10 * */ const assert = require('assert') const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var src = path.join(dir, 'originalSideways.jpg'); var dst = path.join(dir, 'originalSideways10x.jpg'); gm(src).options({ imageMagick }).resize(10).write(dst, function(err) { gm(dst).options({ imageMagick }).size(function(err, size) { if (err) return finish(err); assert.equal(10, size.width); finish(); }); }); } ================================================ FILE: test/393.js ================================================ const assert = require('assert'); const fs = require('fs'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var imagePath = path.join(__dirname, 'fixtures', 'nyancat.gif'); var inputStream = fs.createReadStream(imagePath); gm(inputStream).options({ imageMagick }).identify({ bufferStream: true }, function(err, value) { if (err) return finish(err); var size = value.size; assert.equal(400, size.width); assert.equal(400, size.height); finish(); }); } ================================================ FILE: test/417.js ================================================ const assert = require('assert') const fs = require('fs'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const originalPathName = path.join(dir, 'original.jpg'); const thumbPathName = path.join(dir, 'thumb.png'); gm(originalPathName).options({ imageMagick }).thumb(150, 40, thumbPathName, function thumb (err) { gm(thumbPathName).options({ imageMagick }).size(function (err, size) { if (err) return finish(err); assert.equal(142, size.width); assert.equal(40, size.height); gm(originalPathName).options({ imageMagick }).thumbExact(150, 40, thumbPathName, function thumb (err) { gm(thumbPathName).options({ imageMagick }).size(function (err, size) { assert.equal(150, size.width); assert.equal(40, size.height); finish(err); }); }); }); }); } ================================================ FILE: test/422.js ================================================ const fs = require('fs'); const path = require('path'); module.exports = function (gm, dir, finish, GM, imageMagick) { // Same image const originalPathName = path.join(dir, 'original.jpg'); gm.compare(originalPathName, originalPathName, function(err, same, diff) { if (err) return finish(err); if (!same) { const msg = `Compare should be the same! "${same}" "${diff}"`; return finish(new Error(msg)); } // Compare almost similar images for which ImageMagick // returns an exponent-style floating point number const compare1PathName = path.join(__dirname, 'fixtures', 'compare_1.png'); const compare2PathName = path.join(__dirname, 'fixtures', 'compare_2.png'); gm.compare(compare1PathName, compare2PathName, function(err, same, diff) { if (err) return finish(err); if (!same) { const msg = `Compare should be the same! "${same}" "${diff}"`; return finish(new Error(msg)); } const noisePathName = path.join(dir, 'noise3.png'); // Create a new noisy image gm.noise(0.3).write(noisePathName, function (err) { if (err) return finish(err); var options = { highlightColor: '#fff', file: path.join(dir, 'diff.png'), tolerance: 0.001 }; const originalPathName = path.join(dir, 'original.jpg'); // Compare these images and write to a file. gm.compare(originalPathName, noisePathName, options, function(err) { if (err) return finish(err); fs.access(options.file, fs.constants.F_OK, function(err) { if (err) { finish(new Error('Diff file does not exist.')); } else { fs.unlink(options.file, finish); } }); }); }); }); }); }; ================================================ FILE: test/429.js ================================================ const fs = require('fs'); const path = require('path'); module.exports = function (gm, dir, finish, GM, imageMagick) { if (!GM.integration) return finish(); const ico = path.join(__dirname, 'fixtures', 'test.ico'); const buffer = fs.readFileSync(ico); const stream = fs.createReadStream(ico); GM(ico).options({ imageMagick }).size(function (err) { if (err) { err.message = 'Failed using ico filename. ' + err.message; return finish(err); } GM(buffer, 'img.ico').options({ imageMagick }).size(function (err) { if (err) { err.message = 'Failed using ico buffer. ' + err.message; return finish(err); } GM(stream, 'img.ico').options({ imageMagick }).size({bufferStream: true}, function (err) { if (err) { err.message = 'Failed using ico stream. ' + err.message; return finish(err); } finish(); }); }); }); } ================================================ FILE: test/68.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) var assert = require('assert') var url = require('url') var http = require('http') module.exports = function (_, dir, finish, gm) { return finish(); // use this test when gm is not installed. // it demonstrates that err is often passed as null (timing) // to detect the stream error that the gm command is not installed, // you must test the stderr output manually for "execvp(): No such file or directory" function done (err){ if (err) return finish(done.ran = err); if (done.ran) return; finish(); } http.get(url.parse('http://www.google.com/images/srpr/logo3w.png'), function (resp) { gm(resp, 'logo3w.png').stream(function (err, stdout, stderr) { return finish(); if (err) { console.error('Error processing image', err) } else { stdout.on('data', function (chunk) { console.log('Chunk recieved', chunk.toString()) }) stdout.on('end', function () { console.log('Stream ended') }) stderr.on('data', function (chunk) { console.log('err Chunk recieved', chunk.toString()) }) stderr.on('end', function () { console.log('err Stream ended') }) } }) }) .on('error', function (err) { console.error('Error fetching image', err) }) } ================================================ FILE: test/70.js ================================================ const assert = require('assert') const path = require('path'); var times = 16; var loading = path.join(__dirname, 'fixtures', 'loading.gif'); var favicon = path.join(__dirname, 'fixtures', 'favicon.png'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var pending = times/2; var res = {}; res[loading] = {}; res[favicon] = {}; function done (err){ if (err) return finish(done.ran = err); if (done.ran) return; if (--pending) return; finish(); } new Array(times).join('x').split('x').forEach(function (_, i) { ;[loading, favicon].forEach(function (img) { gm(img).options({imageMagick}).size(function (err, size) { if (err) return done(err); 'width height'.split(' ').forEach(function (prop) { if (!(prop in res[img])) { res[img][prop] = size[prop]; } else { assert.equal(res[img][prop], size[prop]); } }); done(err); }); }); }); } ================================================ FILE: test/78.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var name = imageMagick ? '78-IM' : '78'; var out = path.join(dir, name); _.resize(600, 450, '!').write(out + '.png', function (err) { if (err) return finish(err); var img = gm(out + '.png').options({ imageMagick }); img .crop(70, 70, 100, 100) .resize(50, 50) .write(out + '-2.jpg', function (err) { if (err) return finish(err); finish(); }) }); } ================================================ FILE: test/alpha.js ================================================ const assert = require('assert'); const Async = require('async'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var alphaTypes = [ "Activate", "On", "Deactivate", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Background" ]; const edgePath = path.join(dir, 'original.png'); const failPath = path.join(dir, 'alpha_fail.png'); // alpha not supported by GM so only test IM if (!imageMagick) { assert.throws(function() { gm(edgePath) .alpha(alphaTypes.pop()) .write(failPath); }); finish(); } else { Async.eachSeries(alphaTypes, function(alphaType, cb) { var m = gm(edgePath).options({imageMagick}).alpha( alphaType ); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-alpha', args[2]); assert.equal(alphaType, args[3]); const writePath = path.join(dir, `alpha_${alphaType}.png`); m.write(writePath, cb); }, finish); } } ================================================ FILE: test/append.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { const out = path.resolve(dir, 'append.jpg'); const lostPath = path.join(dir, 'lost.png'); const originalPath = path.join(dir, 'original.jpg'); try { require('fs').unlinkSync(out); } catch (_) {} var m = gm(lostPath) .options({imageMagick}) .append(originalPath, originalPath) .append() .background('#222') var args = m.args(); assert.equal('convert', args[0]); assert.equal('-background',args[1]); assert.equal('#222',args[2]); assert.ok(/lost\.png$/.test(args[3])); assert.ok(/original\.jpg$/,args[4]); assert.ok(/original\.jpg$/,args[5]); assert.equal('-append',args[6]); assert.equal('-',args[7]); if (!gm.integration) { return horizontal({ dir, finish, gm, originalPath, lostPath, imageMagick }); } m.write(out, function (err) { if (err) return finish(err); gm(out) .options({imageMagick}) .size(function (err, size) { if (err) return finish(err); assert.equal(460, size.width); assert.equal(435, size.height); horizontal({ dir, finish, gm, originalPath, lostPath, imageMagick }); }) }); } function horizontal ({ dir, finish, gm, originalPath, lostPath, imageMagick }) { var out = path.resolve(dir, 'appendHorizontal.jpg'); var m = gm(originalPath).append(lostPath, true).options({imageMagick}); var args = m.args(); assert.equal('convert', args[0]); assert.ok(/original\.jpg$/.test(args[1])); assert.ok(/lost\.png$/.test(args[2])); assert.equal('+append',args[3]); assert.equal('-',args[4]); if (!gm.integration) { return finish(); } m.write(out, function (err) { if (err) return finish(err); gm(out).options({imageMagick}).size(function (err, size) { if (err) return finish(err); assert.equal(697, size.width); assert.equal(155, size.height); finish(); }) }); } ================================================ FILE: test/arc.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 3) .fill("#ffffffbb") .drawArc(80, 10, 90, 20, 0, 180) var args = m.args(); assert.equal('convert', args[0]); assert.equal('-blur', args[2]); assert.equal('8x4', args[3]); assert.equal('-strokewidth', args[4]); assert.equal(3, args[5]); assert.equal('-stroke', args[6]); assert.equal('red', args[7]); assert.equal('-fill', args[8]); assert.equal('#ffffffbb', args[9]); assert.equal('-draw', args[10]); assert.equal('arc 80,10 90,20 0,180', args[11]); if (!GM.integration) return finish(); const arcPath = path.join(dir, 'arc.png'); m.write(arcPath, function arc (err) { finish(err); }); } ================================================ FILE: test/autoOrient.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const sidewaysPath = path.join(dir, 'originalSideways.jpg'); gm(sidewaysPath) .options({imageMagick}) .identify(function (err, o) { if (err) return finish(err); const geo = imageMagick ? '155x460+0+0' : '155x460'; assert.equal(geo, o.Geometry); // this image is sideways, but may be auto-oriented by modern OS's // try opening it in a browser to see its true orientation gm(sidewaysPath) .options({imageMagick}) .autoOrient() .stream(function (err, stream) { if (err) return finish(err); gm(stream) .options({imageMagick}) .identify(function (err, data) { if (err) return finish(err); const geo2 = imageMagick ? '460x155+0+0' : '460x155'; assert.equal(geo2, data.Geometry); finish(err); }) }) }); } ================================================ FILE: test/autoOrientAll.js ================================================ const assert = require('assert'); const fs = require('fs'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var beforeValues = { 'Landscape_1.jpg': ['TopLeft', 1, '600x450'], 'Landscape_2.jpg': ['TopRight', 2, '600x450'], 'Landscape_3.jpg': ['BottomRight', 3, '600x450'], 'Landscape_4.jpg': ['BottomLeft', 4, '600x450'], 'Landscape_5.jpg': ['LeftTop', 5, '450x600'], 'Landscape_6.jpg': ['RightTop', 6, '450x600'], 'Landscape_7.jpg': ['RightBottom', 7, '450x600'], 'Landscape_8.jpg': ['LeftBottom', 8, '450x600'], 'Portrait_1.jpg': ['TopLeft', 1, '450x600'], 'Portrait_2.jpg': ['TopRight', 2, '450x600'], 'Portrait_3.jpg': ['BottomRight', 3, '450x600'], 'Portrait_4.jpg': ['BottomLeft', 4, '450x600'], 'Portrait_5.jpg': ['LeftTop', 5, '600x450'], 'Portrait_6.jpg': ['RightTop', 6, '600x450'], 'Portrait_7.jpg': ['RightBottom', 7, '600x450'], 'Portrait_8.jpg': ['LeftBottom', 8, '600x450'] }; var afterValues = { 'Landscape_1.jpg': '600x450', 'Landscape_2.jpg': '600x450', 'Landscape_3.jpg': '600x450', 'Landscape_4.jpg': '600x450', 'Landscape_5.jpg': '600x450', 'Landscape_6.jpg': '600x450', 'Landscape_7.jpg': '600x450', 'Landscape_8.jpg': '600x450', 'Portrait_1.jpg': '450x600', 'Portrait_2.jpg': '450x600', 'Portrait_3.jpg': '450x600', 'Portrait_4.jpg': '450x600', 'Portrait_5.jpg': '450x600', 'Portrait_6.jpg': '450x600', 'Portrait_7.jpg': '450x600', 'Portrait_8.jpg': '450x600' }; const orientationDir = path.join(dir, 'orientation'); fs.readdir(orientationDir, function(err, files) { if (err) return finish(err); var originalFiles = files.filter(function(file) { return beforeValues[file] && afterValues[file]; }); function next () { test(originalFiles.pop()); } return next(); function test (filename) { if (!filename) return finish(); const fileToAutoOrient = path.join(orientationDir, filename); const newFilename = fileToAutoOrient + '.oriented.jpg'; const constant = fileToAutoOrient + '.correct.jpg'; gm(fileToAutoOrient).options({imageMagick}).orientation(function (err, o) { if (err) return finish(err); assert.equal(beforeValues[filename][0], o); assert.equal(beforeValues[filename][1], this.data['Profile-EXIF'].Orientation, 'No Profile-EXIF data found'); // this image is sideways, but may be auto-oriented by modern OS's // try opening it in a browser to see its true orientation gm(fileToAutoOrient) .options({ imageMagick }) .autoOrient() .write(newFilename, function autoOrient (err) { if (err) return finish(err); // fs race condition setTimeout(function () { gm(newFilename).options({ imageMagick }).identify(function (err) { if (err) return finish(err); const afterValue = imageMagick ? `${afterValues[filename]}+0+0` : afterValues[filename]; assert.equal(afterValue, this.data.Geometry, `Bad-Geometry for ${filename}. Got "${this.data.Geometry}"`); gm().options({imageMagick}).compare(newFilename, constant, 0.1, function (err, equal) { if (err) return finish(err); assert.ok(equal); next(); }) }); }, 200); }); }); } }); }; ================================================ FILE: test/autoOrientAndThumb.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); var original = path.join(dir, 'orientation', 'Portrait_7.jpg'); var result = path.join(dir, 'autoOrientAndThumb.png'); size(original, imageMagick, function (err, origSize) { if (err) return finish(err); assert.ok(origSize.width < 610); assert.ok(origSize.height < 460); gm(original) .options({imageMagick}) .autoOrient() .thumb(100, 100, result, function (err) { if (err) return finish(err); size(result, imageMagick, function (err, newSize) { if (err) return finish(err); assert.ok(newSize.width < 80); assert.ok(newSize.height < 110); finish(); }); }); }); function size (file, imageMagick, cb) { gm(file).options({imageMagick}).identify(function (err, data) { if (err) return cb(err); cb(err, data.size); }); } } ================================================ FILE: test/autoOrientStream.js ================================================ // gm - Copyright Aaron Heckmann (MIT Licensed) // This is a copy of `autoOrient.js` using streams const assert = require('assert') const fs = require('fs') const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const filename = path.join(dir, 'autoOrientStream.jpg'); const sidewaysPathName = path.join(dir, 'originalSideways.jpg'); gm(fs.createReadStream(sidewaysPathName)).options({imageMagick}).identify(function (err) { if (err) return finish(err); const geo = imageMagick ? '155x460+0+0' : '155x460'; assert.equal(geo, this.data.Geometry); // this image is sideways, but may be auto-oriented by modern OS's // try opening it in a browser to see its true orientation gm(fs.createReadStream(sidewaysPathName)) .options({imageMagick}) .autoOrient() .write(filename, function autoOrient (err) { if (err) return finish(err); // fs race condition setTimeout(function () { gm(filename).options({imageMagick}).identify(function (err) { if (err) return finish(err); const geo2 = imageMagick ? '460x155+0+0' : '460x155'; assert.equal(geo2, this.data.Geometry); finish(err); }); }, 200); }); }); } ================================================ FILE: test/background.js ================================================ const assert =require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .crop(140,100) .background("#FF0000") .extent(340,300) var args = m.args(); assert.equal('convert', args[0]); assert.equal('-background', args[1]); assert.equal('#FF0000', args[2]); assert.equal('-crop', args[4]); assert.equal('140x100+0+0', args[5]); assert.equal('-extent', args[6]); assert.equal('340x300', args[7]); if (!GM.integration) return finish(); const backgroundPathName = path.join(dir, 'background.jpg'); m.write(backgroundPathName, function (err) { finish(err); }); } ================================================ FILE: test/bezier.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 3) .fill("#ffffffbb") .drawBezier([0, 10], [183, 163], [183, 10], [0, 10]) var args = m.args(); assert.equal('convert', args[0]); assert.equal('-blur', args[2]); assert.equal('8x4', args[3]); assert.equal('-strokewidth', args[4]); assert.equal(3, args[5]); assert.equal('-stroke', args[6]); assert.equal('red', args[7]); assert.equal('-fill', args[8]); assert.equal('#ffffffbb', args[9]); assert.equal('-draw', args[10]); assert.equal('bezier 0,10,183,163,183,10,0,10', args[11]); if (!GM.integration) return finish(); m .write(path.join(dir, 'bezier.png'), function bezier (err) { finish(err); }); } ================================================ FILE: test/bitdepth.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .bitdepth(2); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-depth', args[2]); assert.equal(2, args[3]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'bitdepth.png'); m.write(outpath, function bitdepth (err) { finish(err); }); } ================================================ FILE: test/blur.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(18, 10); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-blur', args[2]); assert.equal('18x10', args[3]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'blur.png'); m.write(outpath, function blur (err) { finish(err); }); } ================================================ FILE: test/changeFormat.js ================================================ const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); const outpath = path.join(dir, 'changedformat.png'); gm.write(outpath, function changeformat (err) { finish(err); }); } ================================================ FILE: test/charcoal.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .charcoal(1); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-charcoal', args[2]); assert.equal(1, args[3]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'charcoal.png'); m.write(outpath, function charcoal (err) { finish(err); }); } ================================================ FILE: test/chop.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .chop(54, 1, 307, 1); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-chop', args[1]); assert.equal('54x1+307+1', args[2]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'chop.png'); m.write(outpath, function chop (err) { finish(err); }); } ================================================ FILE: test/circle.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 1) .fill("#ffffffbb") .drawCircle(125, 45, 120, 5); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-blur', args[2]); assert.equal('8x4', args[3]); assert.equal('-strokewidth', args[4]); assert.equal(1, args[5]); assert.equal('-stroke', args[6]); assert.equal('red', args[7]); assert.equal('-fill', args[8]); assert.equal('#ffffffbb', args[9]); assert.equal('-draw', args[10]); assert.equal('circle 125,45 120,5', args[11]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'circle.png'); m.write(outpath, function circle (err) { finish(err); }); } ================================================ FILE: test/colorize.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .colorize(80, 0, 30) var args = m.args(); assert.equal('convert', args[0]); assert.equal('-colorize', args[2]); assert.equal('80,0,30', args[3]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'colorize.png'); m.write(outpath, function colorize (err) { finish(err); }); } ================================================ FILE: test/colors.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .colors(16); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-colors', args[2]); assert.equal(16, args[3]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'colors.png'); m.write(outpath, function colors (err) { finish(err); }); } ================================================ FILE: test/comment.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .comment("%m:%f %wx%h"); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-comment', args[2]); assert.equal('"%m:%f %wx%h"', args[3]); if (!GM.integration) return finish(); const outpath = path.join(dir, 'comment.png'); m.write(outpath, function comment (err) { finish(err); }); } ================================================ FILE: test/compare.js ================================================ const path = require('path'); const fs = require('fs'); module.exports = function (gm, dir, finish) { // Same image const originalJPGFilePath = path.join(dir, 'original.jpg'); const originalPNGFilePath = path.join(dir, 'original.png'); gm.compare(originalJPGFilePath, originalPNGFilePath, function(err, same) { if (err) return finish(err); if (!same) return finish(new Error('Compare should be the same!')); // Compare almost similar images for which ImageMagick // returns a exponent-style floating point number const compare1Path = path.join(__dirname, 'fixtures', 'compare_1.png'); const compare2Path = path.join(__dirname, 'fixtures', 'compare_2.png'); gm.compare(compare1Path, compare2Path, function(err, same, diff) { if (err) return finish(err); if (!same) return finish(new Error('Compare should be the same!')); // Create a new noisy image const noisePath = path.join(dir, 'noise3.png'); gm.noise(0.3).write(noisePath, function (err) { if (err) return finish(err); const options = { highlightColor: 'yellow', file: path.join(dir, `compare-test-${Date.now()}.png`), tolerance: 0.001 }; // Compare these images and write to a file. gm.compare(originalJPGFilePath, noisePath, options, function(err) { if (err) return finish(err); fs.access(options.file, fs.constants.F_OK, function(err) { if (err) { finish(new Error('Diff file does not exist.')); } else { fs.unlink(options.file, () => finish()); } }); }); }); }); }); }; ================================================ FILE: test/composite.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { const sourcePath = path.join(__dirname, 'fixtures', 'compare_1.png'); gm.source = sourcePath; const faviconPath = path.join(__dirname, 'fixtures', 'favicon.png'); const a = gm.composite(faviconPath) const args = a.args(); assert.equal('composite', args[0]); assert.equal(faviconPath, args[1]); assert.equal(sourcePath, args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'composite.png'); a.write(destPath, function(err) { finish(err); }); } ================================================ FILE: test/contrast.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { const m = gm.contrast(2); const args = m.args(); assert.equal('convert', args[0]); assert.equal('+contrast', args[2]); assert.equal('+contrast', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'contrast.png'); m.write(destPath, function contrast (err) { finish(err); }); } ================================================ FILE: test/crop.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM, imageMagick) { const m = gm.crop(200, 155, 300, 0); const args = m.args(); assert.equal('convert', args[0]); assert.equal('-crop', args[2]); assert.equal('200x155+300+0', args[3]); const imagePath = path.join(dir, 'image.png'); const m2 = GM(imagePath).options({ imageMagick }).crop(200, 155, 300, 0, true); const args2 = m2.args(); assert.equal('200x155+300+0%', args2[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'crop.png'); m.write(destPath, function crop (err) { finish(err); }); } ================================================ FILE: test/cycle.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { const m = gm.cycle(4); const args = m.args(); assert.equal('convert', args[0]); assert.equal('-cycle', args[2]); assert.equal(4, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'cycle.png'); m.write(destPath, function cycle (err) { finish(err); }); } ================================================ FILE: test/densityGm.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM, imageMagick) { var NUMBER = 100; var NUMBER2 = 200; var g = gm.density(NUMBER, NUMBER2); var gArgs = g.args(); assert.equal('convert', gArgs[0]); assert.equal('-density', gArgs[1]); assert.equal(NUMBER + 'x' + NUMBER2, gArgs[2]); if (imageMagick) { // graphicsmagick does not support density with two arguments var imArgs = GM().options({imageMagick}).density(NUMBER).args(); assert.equal('convert', imArgs[0]); assert.equal('-density', imArgs[1]); assert.equal(NUMBER, imArgs[2]); } if (!GM.integration) return finish(); const destPath = path.join(dir, 'density.png'); g.write(destPath, function density (err) { finish(err); }); }; ================================================ FILE: test/despeckle.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm.despeckle(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-despeckle', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'despeckle.png'); m.write(destPath, function despeckle (err) { finish(err); }); } ================================================ FILE: test/dispose.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (img, dir, finish, gm, imageMagick) { var EventEmitter = require('events').EventEmitter; EventEmitter.prototype._maxListeners = 100; assert.equal(undefined, gm.prototype._options.disposers); assert.equal(undefined, img._options.disposers); var emitter = new EventEmitter(); var disposer = { emitter: emitter, events: ['pleaseDispose', 'readyToDispose'] }; var g = gm('test').options({ disposers: [ disposer ], imageMagick }); assert.deepEqual([disposer], g._options.disposers); var sub = gm.subClass({ disposers: [ disposer ], imageMagick }); assert.deepEqual([disposer], sub.prototype._options.disposers); if (!gm.integration) { return finish(); } const photoPath = path.join(dir, 'photo.JPG'); const disposePath = path.join(dir, 'dispose.png'); gm(photoPath).options({ disposers: [ disposer ], imageMagick }) .thumb(1000, 1000, disposePath, function (err) { assert.ok(err, "Expecting a disposed error"); }); emitter.emit('pleaseDispose'); noDispose(); function noDispose() { gm(photoPath).options({ disposers: [ disposer ], imageMagick }) .thumb(1000, 1000, disposePath, function (err) { finish(err); }); emitter.emit('disposeOK'); } } ================================================ FILE: test/dither.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (gm._options.imageMagick) return finish(); var g = gm.monochrome().dither(); var args = g.args(); assert.equal('convert', args[0]); assert.equal('-monochrome', args[2]); assert.equal('-dither', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'dither.png'); g.write(destPath, function dither (err) { finish(err); }); } ================================================ FILE: test/edge.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .edge(2); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-edge', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'edge.png'); m.write(destPath, function edge (err) { finish(err); }); } ================================================ FILE: test/ellipse.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("blue", 1) .drawEllipse(155, 80, 130, 50); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-blur', args[2]); assert.equal('8x4', args[3]); assert.equal('-strokewidth', args[4]); assert.equal(1, args[5]); assert.equal('-stroke', args[6]); assert.equal('blue', args[7]); assert.equal('-draw', args[8]); assert.equal('ellipse 155,80 130,50 0,360', args[9]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'ellipse.png'); m.write(destPath, function ellipse (err) { finish(err); }); } ================================================ FILE: test/emboss.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .emboss(2); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-emboss', args[2]); assert.equal(2, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'emboss.png'); m.write(destPath, function emboss (err) { finish(err); }); } ================================================ FILE: test/enhance.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .enhance(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-enhance', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'enhance.png'); m.write(destPath, function enhance (err) { finish(err); }); } ================================================ FILE: test/equalize.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .equalize(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-equalize', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'equalize.png'); m.write(destPath, function equalize (err) { finish(err); }); } ================================================ FILE: test/extent.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .scale(200, 100) .extent(300,300) var args = m.args(); assert.equal('convert', args[0]); assert.equal('-scale', args[2]); assert.equal('200x100', args[3]); assert.equal('-extent', args[4]); assert.equal('300x300', args[5]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'extent.png'); m.write(destPath, function resize (err) { finish(err); }); } ================================================ FILE: test/flatten.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { // graphicsmagick considers PSD broken // http://www.graphicsmagick.org/NEWS.html#may-30-2016 if (!imageMagick) { return finish(); } const layersPath = path.join(dir, 'layers.psd'); var m = gm(layersPath) .options({ imageMagick }) .flatten(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-flatten', args[2]); if (!gm.integration) return finish(); const destPath = path.join(dir, 'unlayered.jpg'); m.write(destPath, function (err) { finish(err); }); } ================================================ FILE: test/flip.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .flip(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-flip', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'flip.png'); m.write(destPath, function flip (err) { finish(err); }); } ================================================ FILE: test/flop.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .flop(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-flop', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'flop.png'); m.write(destPath, function flop (err) { finish(err); }); } ================================================ FILE: test/fromBuffer.js ================================================ const assert = require('assert'); const path = require('path'); const fs = require('fs') module.exports = function (_, dir, finish, gm, imageMagick) { const original = path.join(dir, 'original.jpg'); const result = path.join(dir, 'fromBuffer.png'); var buf = fs.readFileSync(original); var m = gm(buf).options({imageMagick}).rotate('red', 30); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-', args[1]); assert.equal('-background', args[2]); assert.equal('red', args[3]); assert.equal('-rotate', args[4]); assert.equal(30, args[5]); if (!gm.integration) return finish(); m.write(result, function crop (err) { if (err) return finish(err); // tolerance defaults to 0.4 m.compare(original, result, function (err, equal) { if (err) return finish(err); assert.ok(equal); // accepts tolerance argument m.compare(original, result, 0.1, function (err, equal, equality, raw) { if (err) return finish(err); assert.ok(!equal); assert.ok(equality > 0.1); assert.ok(raw); finish(); }) }) }); } ================================================ FILE: test/gamma.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .gamma(1.7, 2.3, 1.3); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-gamma', args[2]); assert.equal('1.7,2.3,1.3', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'gamma.png'); m.write(destPath, function gamma (err) { finish(err); }); } ================================================ FILE: test/geometry.js ================================================ var assert = require('assert') module.exports = function (_, __, finish, GM, imageMagick) { var a = GM("dummy").options({imageMagick}).geometry("asdf"); // Custom geometry command var args = a.args(); assert.equal('-geometry', args[2]); assert.equal('asdf', args[3]); var b = GM("dummy").options({imageMagick}).geometry("", 100); var args = b.args(); assert.equal('-geometry', args[2]); assert.equal('x100', args[3]); // Keep-aspect-ratio command return finish(); } ================================================ FILE: test/getterColor.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const destPath = path.join(dir, 'blue.gif'); gm(destPath).options({imageMagick}).color(function (err, color) { if (err) return finish(err); assert.equal(1, color) assert.equal(this.data.color, color) finish(); }); } ================================================ FILE: test/getterDepth.js ================================================ var assert = require('assert') module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); gm .depth(function getterdepth (err, depth) { if (err) return finish(err); if (this._options.imageMagick) { assert.equal(16, depth); assert.equal(16, this.data.depth); } else { assert.equal(8, depth); assert.equal(8, this.data.depth); } finish(); }); } ================================================ FILE: test/getterFilesize.js ================================================ var assert = require('assert') module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); gm .filesize(function getterfilesize (err, size) { if (err) return finish(err); if (this._options.imageMagick) { assert.equal('7792B', size, size); } else { assert.ok(/7.6K[i]{0,1}/.test(size)); } assert.equal(size, this.data.Filesize) // make sure we are reading from the data cache and not // hitting the fs again. this.identify = function () { assert.ok(false, 'Did not read from cache'); } this.filesize(function (err, size) { if (err) return finish(err); if (this._options.imageMagick) { assert.equal('7792B', size, size); } else { assert.ok(/7.6K[i]{0,1}/.test(size)); } assert.equal(size, this.data.Filesize) finish(); }); }); } ================================================ FILE: test/getterFormat.js ================================================ var assert = require('assert'); module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); gm .format(function getterformat (err, format) { if (err) return finish(err); assert.equal(format, 'JPEG'); assert.equal(gm.data.format, 'JPEG'); finish(); }); } ================================================ FILE: test/getterFormatGIF.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const destPath = path.join(dir, 'original.gif'); gm(destPath).options({imageMagick}) .format(function (err, type) { if (err) return finish(err); assert.equal(type, 'GIF'); assert.equal(this.data.format, 'GIF'); finish(); }) } ================================================ FILE: test/getterIdentify.js ================================================ const assert = require('assert'); const path = require('path'); const os = require('os') var isLinux = os.platform() === 'linux' // Be more lax with the errors if we're on linux var errorFactor = isLinux ? 10 : 1.1 module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const photoPath = path.join(dir, 'photo.JPG'); var test = gm(photoPath).options({ imageMagick }); test.identify(function (err) { if (err) return finish(err); var d = this.data; if (imageMagick) { assert.equal(d.Orientation, 'TopLeft'); assert.equal(d['Geometry'], '430x488+0+0'); assert.equal(d['Print size'], '5.97222x6.77778'); assert.ok(d['Channel depth'].Red || d['Channel depth'].red); assert.ok(d['Channel depth'].Green || d['Channel depth'].green); assert.ok(/0\s+\(0\)/.test(d['Channel statistics'].Red.min)); var sd = d['Channel statistics'].Red['standard deviation'].split(' ') var sd1 = parseFloat(sd[0]) var sd2 = parseFloat(sd[1].slice(1, -1)) assert.ok(sd1 && Math.abs(sd1 - 71.7079) < .01 * errorFactor) assert.ok(sd2 && Math.abs(sd2 - 0.281208) < .001 * errorFactor) var imageStat = parseFloat(d['Image statistics'].Overall.kurtosis) assert.ok(imageStat); if (!isLinux) { // This is undefined in Linux assert.equal(d['Rendering intent'], 'Perceptual'); } assert.equal(d.Properties['exif:DateTimeDigitized'], '2011:07:01 11:23:16'); assert.equal(d.Format, 'JPEG (Joint Photographic Experts Group JFIF format)'); } else { assert.equal(d.Orientation, 'TopLeft'); assert.equal(d['JPEG-Quality'], 96); assert.ok(/(0.2812)/.test(d['Channel Statistics'].Red['Standard Deviation'])); var ex = d['Profile-EXIF']; assert.equal(ex.Make, 'Apple'); assert.equal(ex.Model, 'iPad 2'); assert.equal(ex['GPS Info'], 558); assert.equal(ex['GPS Longitude'], '80/1,4970/100,0/1'); assert.equal(ex['GPS Time Stamp'], '15/1,23/1,945/1'); assert.equal(d.Format, 'JPEG (Joint Photographic Experts Group JFIF format)'); assert.equal(d['Geometry'], '430x488'); } gif(function () { pattern(); }); }); function gif (callback) { const bluePath = path.join(dir, 'blue.gif'); var test = gm(bluePath).options({ imageMagick }); test.identify(function (err) { if (err) return finish(err); if (imageMagick) { if (!isLinux) { assert.equal(1, this.data.color); } assert.ok(/blue/.test(this.data.Colormap['0'])); assert.ok(/black/.test(this.data.Colormap['1'])); } else { if (!isLinux) { assert.equal(2, this.data.color); } var blueWorks = this.data.Colors['0'] == '( 0, 0,255)\t blue'; var blackWorks = this.data.Colors['1'] == '( 0, 0, 0)\t black'; if (!blueWorks) { blueWorks = this.data.Colors['1'] == '( 0, 0,255)\t blue'; blackWorks = this.data.Colors['0'] == '( 0, 0, 0)\t black'; } assert.ok(blueWorks); assert.ok(blackWorks); } callback(); }); } function pattern () { const bluePath = path.join(dir, 'blue.gif'); var test = gm(bluePath); var format = '%f: %m, %wx%h'; var value = 'blue.gif: GIF, 100x200'; test.options({ imageMagick }); test.identify(format, function (err, result) { if (err) return finish(err); assert.equal(result, value); test.identify({ format: format }, function (err, result) { if (err) return finish(err); assert.equal(result, value); finish(); }) }); } } ================================================ FILE: test/getterIptc.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const iptcPath = path.join(__dirname, 'fixtures', 'iptc.jpg'); var test = gm(iptcPath).options({imageMagick}) test.identify(function (err) { if (err) return finish(err); var d = this.data; if (imageMagick) { var iptc = d['Profiles'] && d['Profiles']['Profile-iptc']; assert.equal(iptc['Caption[2,120]'], 'Some caption with colon space: for example'); } finish(); }); } ================================================ FILE: test/getterMultipleIptc.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const iptcPath = path.join(__dirname, 'fixtures', 'iptc-multiple.jpg'); var test = gm(iptcPath).options({imageMagick}) test.identify(function (err) { if (err) return finish(err); var d = this.data; if (imageMagick) { var iptc = d['Profiles'] && d['Profiles']['Profile-iptc']; var keywords = iptc['Keyword[2,25]']; assert(Array.isArray(keywords)); assert.equal(keywords.length, 5); // just make sure another value assert(! Array.isArray(iptc['Headline[2,105]'])); } finish(); }); } ================================================ FILE: test/getterRes.js ================================================ var assert = require('assert') module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); gm .res(function getterres (err, res) { if (err) return finish(err); if (gm._options.imageMagick) { assert.equal('72x72', res); } else { assert.equal('72x72 pixels/inch', res); } assert.equal(res, this.data.Resolution) finish(); }); } ================================================ FILE: test/getterSize.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); sizeJPEG(function (err) { if (err) return finish(err); sizeGIF(function (err) { if (err) return finish(err); sizePNG(finish); }) }) function sizeJPEG(done) { const originalPath = path.join(dir, 'original.jpg'); gm(originalPath).options({imageMagick}).size(function gettersize (err, size) { if (err) return done(err); assert.equal(size.width, 460); assert.equal(size.height, 155); const identifyParseErrPath = path.join(dir, 'identifyParseErr.jpg'); gm(identifyParseErrPath).options({imageMagick}).size(done); }); } function sizeGIF(done) { const originalGifPath = path.join(dir, 'original.gif'); gm(originalGifPath).options({imageMagick}).size(function (err, size) { if (err) return done(err); assert.equal(size.width, 192) assert.equal(size.height, 56) done() }) } function sizePNG(done) { const originalPngPath = path.join(dir, 'original.png'); gm(originalPngPath).options({imageMagick}).size(function (err, size) { if (err) return done(err); assert.equal(size.width, 460) assert.equal(size.height, 155) done() }) } } ================================================ FILE: test/gh-17.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .crop(200, 155, 300, 0) .resize(58, 50, '%'); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-crop', args[2]); assert.equal('200x155+300+0', args[3]); assert.equal('-resize', args[4]); assert.equal('58x50%', args[5]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'cropresize.png'); m.write(destPath, function crop (err) { finish(err); }); } ================================================ FILE: test/gifFrame.js ================================================ const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const originalGifPath = path.join(dir, 'original.gif[0]'); const gifFramePath = path.join(dir, 'gifFrame.jpg'); gm(originalGifPath).options({imageMagick}) .write(gifFramePath, function gifFrame (err){ finish(err); }); } ================================================ FILE: test/gifFrameIdentify.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { const originalGifPath = path.join(dir, 'original.gif[0]'); var m = gm(originalGifPath).options({imageMagick}); if (!gm.integration) return finish(); m.identify('%n', function (err, stdout) { if (err) return finish(err); assert.equal(parseInt(stdout.toString(), 10), 1); finish(); }) } ================================================ FILE: test/gifFrameStream.js ================================================ const assert = require('assert') const path = require('path'); const fs = require('fs'); module.exports = function (_, dir, finish, gm, imageMagick) { const originalGifPath = path.join(dir, 'original.gif'); const readStream = fs.createReadStream(originalGifPath); const m = gm(readStream, "original.gif[0]").options({imageMagick}); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-[0]', args[1]); if (!gm.integration) return finish(); const destPath = path.join(dir, 'gifFrameStream.jpg'); m.write(destPath, function gifFrame (err){ finish(err); }); } ================================================ FILE: test/gravity.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (img, dir, finish, gm) { var changed = gm('whatever.png').gravity("Souths") assert.equal(changed._out[1], 'NorthWest'); var m = img .scale(200, 100) .gravity("South") .extent(300,300); var args = m.args(); assert.equal('convert', args[0]); args= args.slice(2); assert.deepEqual(args, [ '-scale', '200x100', '-gravity', 'South', '-extent', '300x300', '-' ]) if (!gm.integration) return finish(); const destPath = path.join(dir, 'gravity.png'); m.write(destPath, function resize (err) { finish(err); }); } ================================================ FILE: test/implode.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .implode(0.8); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-implode', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'implode.png'); m.write(destPath, function implode (err) { finish(err); }); } ================================================ FILE: test/index.js ================================================ const cp = require('child_process'); const path = require('path'); const Async = require('async'); const dir = path.join(__dirname, '..', 'examples', 'imgs'); const gm = require('..'); const fs = require('fs'); const os = require('os'); const only = process.argv.slice(2); gm.integration = !! ~process.argv.indexOf('--integration'); if (gm.integration) only.shift(); let files = fs.readdirSync(__dirname).filter(filter); if (files.length === 0) { console.log('No tests found matching', only); } function filter (file) { if (!/\.js$/.test(file)) return false; if ('index.js' === file) return false; if (only.length && !~only.indexOf(file)) return false; var filename = path.join(__dirname, file); if (!fs.statSync(filename).isFile()) return false; return true; } const originalPathName = path.join(dir, 'original.jpg'); function test (imageMagick) { return gm(originalPathName).options({ imageMagick }); } function finish (filename) { return function (err) { if (err) { console.error('\n\nError occured with file: ' + filename); throw err; } } } function isGraphicsMagickInstalled() { try { cp.execSync('gm -version'); return true; } catch (_) { return false; } } function isConvertInstalled() { try { cp.execSync('convert -version'); return true; } catch (_) { return false; } } function isMagickInstalled() { try { cp.execSync('magick -version'); return true; } catch (_) { return false; } } const isWindows = () => os.platform() === 'win32'; var q = Async.queue(function (task, callback) { var filename = task.filename; var im = task.imagemagick; console.log(`Testing ${filename} ..`); require(filename)(test(im), dir, function (err) { finish(filename)(err); callback(); }, gm, im); }, 1); q.drain = function(){ console.log("\n\u001B[32mAll tests passed\u001B[0m"); }; files = files.map(function (file) { return path.join(__dirname, file); }); if (isGraphicsMagickInstalled()) { console.log('gm is installed'); files.forEach(function (filename) { q.push({ imagemagick: false, filename }) }); } if (!isWindows() && isConvertInstalled()) { // windows has a different convert binary console.log('convert is installed'); files.forEach(function (filename) { q.push({ imagemagick: true, filename }) }); } if (isMagickInstalled()) { console.log('magick is installed'); files.forEach(function (filename) { q.push({ imagemagick: '7+', filename }) }); } ================================================ FILE: test/inputIs.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (_, dir, finish, gm) { var err; try { const blahPath = path.join('path', 'to', 'blah.gif') ; var gif = gm(blahPath); assert.equal(true, gif.inputIs('gif')); assert.equal(false, gif.inputIs('jpg')); assert.equal(false, gif.inputIs('crazy')); var png = gm('png.png'); assert.equal(true, png.inputIs('png')); assert.equal(false, png.inputIs('gif')); assert.equal(false, png.inputIs('tif')); const jpgPath = path.join('super', 'duper.jpeg') var jpg = gm(jpgPath); assert.equal(true, jpg.inputIs('jpg')); assert.equal(true, jpg.inputIs('jpeg')); assert.equal(false, jpg.inputIs('gif')); assert.equal(false, jpg.inputIs('tif')); assert.equal(false, jpg.inputIs('gif')); var unknown = gm('super.unknown'); assert.equal(true, unknown.inputIs('unknown')); assert.equal(true, unknown.inputIs('.unknown')); assert.equal(false, unknown.inputIs()); assert.equal(false, unknown.inputIs('')); assert.equal(false, unknown.inputIs('png')); assert.equal(false, unknown.inputIs('pngasdf')); } catch (e) { err = e; console.error(e.stack); } finish(err); } ================================================ FILE: test/interlace.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .interlace(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-interlace', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'interlace.png'); m.write(destPath, function interlace (err) { finish(err); }); } ================================================ FILE: test/label.js ================================================ const assert = require('assert') const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .label("%m:%f %wx%h") var args= m.args(); assert.equal('convert', args[0]); assert.equal('-label', args[2]); assert.equal('"%m:%f %wx%h"', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'label.png'); m.write(destPath, function label (err) { finish(err); }); } ================================================ FILE: test/limit.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .limit("memory", "32MB") .limit("map", "64MB") var args = m.args() assert.equal('convert', args[0]); assert.equal('-limit', args[2]); assert.equal('memory', args[3]); assert.equal('32MB', args[4]); assert.equal('-limit', args[5]); assert.equal('map', args[6]); assert.equal('64MB', args[7]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'limit.png'); m.write(destPath, function limit (err) { finish(err); }); } ================================================ FILE: test/line.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 3) .drawLine(20, 10, 50, 40); var args = m.args(); assert.equal('-blur', args[2]); assert.equal('8x4', args[3]); assert.equal('-strokewidth', args[4]); assert.equal(3, args[5]); assert.equal('-stroke', args[6]); assert.equal('red', args[7]); assert.equal('-draw', args[8]); assert.equal('line 20,10 50,40', args[9]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'line.png'); m.write(destPath, function line (err) { finish(err); }); } ================================================ FILE: test/lower.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .lower(10, 14); var args= m.args(); assert.equal('convert', args[0]); assert.equal('+raise', args[2]); assert.equal('10x14', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'lower.png'); m.write(destPath, function lower (err) { finish(err); }); } ================================================ FILE: test/magnify.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (gm._options.imageMagick) return finish(); var m = gm .magnify(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-magnify', args[1]); assert.equal(4, args.length); if (!GM.integration) return finish(); const destPath = path.join(dir, 'magnify.png'); m.write(destPath, function magnify (err) { finish(err); }); } ================================================ FILE: test/median.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .median(4); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-median', args[2]); assert.equal(4, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'median.png'); m.write(destPath, function media (err) { finish(err); }); } ================================================ FILE: test/minify.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (gm._options.imageMagick) return finish(); var m = gm .minify(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-minify', args[1]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'minify.png'); m.write(destPath, function minify (err) { finish(err); }); } ================================================ FILE: test/minifyIM.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm.minify(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-minify', args[1]); if(gm._options.imageMagick) { assert.throws( function() { const destPath = path.join(dir, 'minify.png'); m.write(destPath, function minify (err) { throw err;}) }, Error ); } return finish(); } ================================================ FILE: test/modulate.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .modulate(120, 100, 80); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-modulate', args[2]); assert.equal('120,100,80', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'modulate.png'); m.write(destPath, function modulate (err) { finish(err); }); } ================================================ FILE: test/monochrome.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .monochrome(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-monochrome', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'monochrome.png'); m.write(destPath, function monochrome (err) { finish(err); }); } ================================================ FILE: test/montage.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { const fixturesPath = path.join(__dirname, 'fixtures'); const srcPath = path.join(fixturesPath, 'compare_1.png'); gm.source = srcPath; const faviconPath = path.join(fixturesPath, 'favicon.png'); var a = gm.montage(faviconPath); var args = a.args(); assert.equal('montage', args[0]); assert.equal(faviconPath, args[1]); assert.equal(srcPath, args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'montage.png'); a.write(destPath, function(err) { finish(err); }); } ================================================ FILE: test/morph-more.js ================================================ const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (gm._options.imageMagick) return finish(); if (!GM.integration) return finish(); const morpherPath = path.join(dir, 'morpher.jpg'); const originalPath = path.join(dir, 'original.png'); const morphedPath = path.join(dir, 'morphed2.jpg'); gm .morph([morpherPath, originalPath], morphedPath, function morph (err) { finish(err); }); } ================================================ FILE: test/morph.js ================================================ const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (gm._options.imageMagick) return finish(); if (!GM.integration) return finish(); const morpherPath = path.join(dir, 'morpher.jpg'); const morphedPath = path.join(dir, 'morphed.jpg'); gm.morph(morpherPath, morphedPath, function morph (err) { finish(err); }); } ================================================ FILE: test/negative.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = GM('temp.jpg').negative(true); var args = m.args(); assert.equal('convert', args[0]); assert.equal('+negate', args[2]); m = gm.negative(); args = m.args(); assert.equal('convert', args[0]); assert.equal('-negate', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'negative.png'); m.write(destPath, function negative (err) { finish(err); }); } ================================================ FILE: test/new.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { var m = gm(525, 110, "#00ff55aa") .options({imageMagick}) .fontSize(68) .stroke("#efe", 2) .fill("#555") .drawText(20, 72, "graphics") .fill("#fa0") .drawText(274, 72, " magick"); var args = m.args(); assert.deepEqual(args, [ 'convert', '-size', '525x110', 'xc:#00ff55aa', '-pointsize', 68, '-strokewidth', 2, '-stroke', '#efe', '-fill', '#555', '-draw', 'text 20,72 "graphics"', '-fill', '#fa0', '-draw', 'text 274,72 "magick"', '-' ]) if (!gm.integration) return finish(); const destPath = path.join(dir, 'new.png'); m.write(destPath, function New (err){ finish(err); }); } ================================================ FILE: test/newImage.js ================================================ // https://github.com/aheckmann/gm/issues/127 const path = require('path'); const fs = require('fs') module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const dest1Path = path.join(dir, 'ignore.me.png'); createImage().write(dest1Path, function (err) { if (err) return finish(err); createImage().stream(function (err, stdout) { if (err) return finish(err); const dest2Path = path.join(dir, 'ignore.me.2.png'); stdout.pipe(fs.createWriteStream(dest2Path)) stdout.on('error', finish) stdout.on('end', finish) }) }) function createImage() { return gm(70, 30, '#000') .options({imageMagick}) .font("arial", 20) .stroke("#fff", 2) .fill("#888") .drawText(10, 22, 'Some text') } } ================================================ FILE: test/noise1.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .noise(0.3); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-noise', args[2]); assert.equal(0.3, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'noise1.png'); m.write(destPath, function noise1 (err) { finish(err); }); } ================================================ FILE: test/noise2.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .noise('laplacian'); var args = m.args(); assert.equal('convert', args[0]); assert.equal('+noise', args[2]); assert.equal('laplacian', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'noise2.png'); m.write(destPath, function noise2 (err) { finish(err); }); } ================================================ FILE: test/options.js ================================================ const assert = require('assert'); const path = require('path'); const fs = require('fs'); const checkCmd = (cmd, imageMagick) => { switch (imageMagick) { case true: assert.ok(/^convert /.test(cmd)); break; case '7+': assert.ok(/^magick "convert" /.test(cmd)); break; default: assert.ok(/^gm "convert" /.test(cmd)); break; } } module.exports = function (_, dir, finish, gm, imageMagick) { var sub = gm.subClass({ subclassed: true }); var s = sub('test').options({ setWithMethod: 2 }); var g = gm('test').options({ hellowwww: 'there' }); assert.equal(2, s._options.setWithMethod); assert.equal(true, s._options.subclassed); assert.equal('there', g._options.hellowwww); assert.equal(undefined, g._options.setWithMethod); assert.equal(undefined, s._options.hellowwww); assert.equal(undefined, g._options.subclassed); /// subclass options var s2 = sub('another'); assert.equal(true, s2._options.subclassed); assert.equal(undefined, s2._options.setWithMethod); if (!gm.integration) return finish(); // test commands // test with subclass const photoPath = path.join(dir, 'photo.JPG'); const writeFile = path.join(dir, `options${Math.random()}.png`); const instance = gm.subClass({ imageMagick }); instance(photoPath) .negative() .write(writeFile, function (err, _1, _2, cmd) { if (err) return finish(err); checkCmd(cmd, imageMagick); fs.stat(writeFile, function (err) { if (err) return finish(new Error('did not write file')); try { fs.unlinkSync(writeFile); } catch (e) {} /// inline options gm(photoPath) .negative() .options({ imageMagick }) .write(writeFile, function (err, _1, _2, cmd) { if (err) return finish(err); checkCmd(cmd, imageMagick); fs.stat(writeFile, function (err) { if (err) return finish(new Error('did not write 2nd file')); try { fs.unlinkSync(writeFile); } catch (e) {} finish(); }); }); }); }); } ================================================ FILE: test/paint.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .paint(2); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-paint', args[2]); assert.equal(2, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'paint.png'); m.write(destPath, function paint (err) { finish(err); }); } ================================================ FILE: test/polygon.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 3) .fill("#ffffffbb") .drawPolygon([60, 10], [183, 73], [185, 13], [167, 35], [165, 17], [163, 19]); var args = m.args(); assert.equal('convert', args[0]); args = args.slice(2); assert.deepEqual(args, [ '-blur', '8x4', '-strokewidth', 3, '-stroke', 'red', '-fill', '#ffffffbb', '-draw', 'polygon 60,10,183,73,185,13,167,35,165,17,163,19', '-' ]) if (!GM.integration) return finish(); const destPath = path.join(dir, 'polygon.png'); m.write(destPath, function polygon (err) { finish(err); }); } ================================================ FILE: test/polyline.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 3) .fill("#ffffffbb") .drawPolyline([40, 10], [143, 153], [185, 53], [147, 15], [145, 17], [43, 19]); var args = m.args(); assert.equal('convert', args[0]); args = args.slice(2); assert.deepEqual(args, [ '-blur', '8x4', '-strokewidth', 3, '-stroke', 'red', '-fill', '#ffffffbb', '-draw', 'polyline 40,10,143,153,185,53,147,15,145,17,43,19', '-' ]) if (!GM.integration) return finish(); const destPath = path.join(dir, 'polyline.png'); m.write(destPath, function polyline (err) { finish(err); }); } ================================================ FILE: test/quality.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .quality(5); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-quality', args[1]); assert.equal(5, args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'quality.png'); m.write(destPath, function quality (err) { finish(err); }); } ================================================ FILE: test/raise.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .raise(10,14); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-raise', args[2]); assert.equal('10x14', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'raise.png'); m.write(destPath, function raise (err) { finish(err); }); } ================================================ FILE: test/rectangle.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .stroke("red", 3) .fill("#ffffffbb") .drawRectangle(40, 10, 251, 120) .drawRectangle(160, 10, 270, 220, 3); var args = m.args(); assert.equal('convert', args[0]); args = args.slice(2); assert.deepEqual(args, [ '-blur', '8x4', '-strokewidth', 3, '-stroke', 'red', '-fill', '#ffffffbb', '-draw', 'rectangle 40,10 251,120 ', '-draw', 'roundRectangle 160,10 270,220 3,3', '-' ]) if (!GM.integration) return finish(); const destPath = path.join(dir, 'rectangle.png'); m.write(destPath, function rectangle (err) { finish(err); }); } ================================================ FILE: test/region.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .region(130, 170, 307, 00); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-region', args[2]); assert.equal('130x170+307+0', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'region.png'); m.write(destPath, function region (err) { finish(err); }); } ================================================ FILE: test/repagePlus.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .repage('+'); var args = m.args(); assert.equal('convert', args[0]); assert.equal('+repage', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'repage.png'); m.write(destPath, function blur (err) { finish(err); }); } ================================================ FILE: test/resample.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .resample(420, 120); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-resample', args[2]); assert.equal('420x120', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'resample.png'); m.write(destPath, function resample (err) { finish(err); }); } ================================================ FILE: test/resize.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM, imageMagick) { var a = GM('img.png').options({imageMagick}).resize(10); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-resize', args[2]); if (imageMagick) { assert.equal('10', args[3]); } else { assert.equal('10x', args[3]); } var a = GM('img.png').options({imageMagick}).resize(10, 20); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-resize', args[2]); assert.equal('10x20', args[3]); var a = GM('img.png').options({imageMagick}).resize(10, false, '%'); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-resize', args[2]); if (imageMagick) { assert.equal('10%', args[3]); } else { assert.equal('10x%', args[3]); } var a = GM('img.png').options({imageMagick}).resize('10%'); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-resize', args[2]); if (imageMagick) { assert.equal('10%', args[3]); } else { assert.equal('10%x', args[3]); } var m = gm.options({imageMagick}).resize(58, 50, '%'); var args= m.args(); assert.equal('convert', args[0]); assert.equal('-resize', args[2]); assert.equal('58x50%', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'resize.png'); m.write(destPath, function resize (err) { finish(err); }); } ================================================ FILE: test/resizeAndAutoOrientFromBuffer.js ================================================ const assert = require('assert'); const path = require('path'); const fs = require('fs') module.exports = function (_, dir, finish, gm, imageMagick) { const original = path.join(dir, 'orientation', 'Portrait_7.jpg'); const result = path.join(dir, 'resizeAutoOrientFromBuffer.png'); var buf = fs.readFileSync(original); var m = gm(buf, 'resizefrombuffer.jpg') .options({imageMagick}) .autoOrient() .resize('20%') const expectedArgs = imageMagick ? ['convert', '-', '-auto-orient', '-resize', '20%', '-'] : ['convert', '-', '-resize', '20%x', '-']; assert.deepEqual(m.args(), expectedArgs); if (!gm.integration) return finish(); size(original, imageMagick, function (err, origSize) { if (err) return finish(err); m .write(result, function resizeFromBuffer (err) { if (err) return finish(err); size(result, imageMagick, function (err, newSize) { if (err) return finish(err); assert.ok(origSize.width / 2 >= newSize.width); assert.ok(origSize.height / 2 >= newSize.height); finish(); }); }); }); function size (file, imageMagick, cb) { gm(file).options({imageMagick}).identify(function (err, data) { if (err) return cb(err); cb(err, data.size); }); } } ================================================ FILE: test/resizeBuffer.js ================================================ const assert = require('assert'); const path = require('path'); const fs = require('fs') module.exports = function (_, dir, finish, gm, imageMagick) { var original = path.join(dir, 'original.jpg'); var result = path.join(dir, 'resizeFromBuffer.png'); var buf = fs.readFileSync(original); var m = gm(buf, 'resizefrombuffer.jpg') .options({imageMagick}) .resize('48%') var args = m.args(); assert.equal('convert', args[0]); assert.equal('-', args[1]); assert.equal('-resize', args[2]); if (m._options.imageMagick) { assert.equal('48%', args[3]); } else { assert.equal('48%x', args[3]); } if (!gm.integration) return finish(); size(original, imageMagick, function (err, origSize) { if (err) return finish(err); m .write(result, function resizeFromBuffer (err) { if (err) return finish(err); size(result, imageMagick, function (err, newSize) { if (err) return finish(err); assert.ok(origSize.width / 2 >= newSize.width); assert.ok(origSize.height / 2 >= newSize.height); finish(); }); }); }); function size (file, imageMagick, cb) { gm(file).options({imageMagick}).identify(function (err, data) { if (err) return cb(err); cb(err, data.size); }); } } ================================================ FILE: test/resizeWrong.js ================================================ const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const original = path.join(dir, 'original.png'); const resized = path.join(dir, 'resize'); var widths = [300, 700, 400, 800, 200], i, cb; var resizeExact = function (width, index) { var name = resized + index + '.png'; if (index == widths.length) { return finish(); } else { index++; } gm(original) .options({imageMagick}) .resizeExact(width) .write(name, function(err){ if (err) return finish(err); gm(name).options({imageMagick}) .size(function (err, size) { if (err) return finish(err); if (size.width !== width) { return finish("Wrong resizing on requested:" + width + ", resized:" + size.width); } if (cb) return cb(); resizeExact(widths[index], index); }); }); }; resizeExact(widths[0], 0); } ================================================ FILE: test/roll.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .roll(40,-100); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-roll', args[2]); assert.equal('+40-100', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'roll.png'); m.write(destPath, function roll (err) { finish(err); }); } ================================================ FILE: test/rotate.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .rotate('red', -40); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-background', args[2]); assert.equal('red', args[3]); assert.equal('-rotate', args[4]); assert.equal(-40, args[5]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'rotate.png'); m.write(destPath, function rotate (err, _0, _1, cmd) { assert.ok(/"-rotate" "-40"/.test(cmd)); m .rotate('red', 0) .write(destPath, function rotate (err, _0, _1, cmd) { assert.ok(!/"-rotate" "-40"/.test(cmd)); assert.ok(/"-rotate" "0"/.test(cmd)); finish(err); }); }); } ================================================ FILE: test/scale.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM, imageMagick) { var a = GM('img.png').options({imageMagick}).scale(100); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-scale', args[2]); if (a._options.imageMagick) { assert.equal('100', args[3]); } else { assert.equal('100x', args[3]); } var a = GM('img.png').options({imageMagick}).scale(100, 200, '%'); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-scale', args[2]); assert.equal('100x200%', args[3]); var a = GM('img.png').options({imageMagick}).scale(100, '200%'); var args = a.args(); assert.equal('convert', args[0]); assert.equal('-scale', args[2]); assert.equal('100x200%', args[3]); var m = gm.options({imageMagick}).scale(100, 100); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-scale', args[2]); assert.equal('100x100', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'scale.png'); m.write(destPath, function scale (err) { finish(err); }); } ================================================ FILE: test/selectFrame.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { const gifPath = path.join(dir, 'original.gif[0]'); var m = gm(gifPath); if (!gm.integration) return finish(); m.options({imageMagick}).identify('%#', function (err, hash1) { if (err) return finish(err); m.selectFrame(2).identify('%#', function (err, hash2) { if (err) return finish(err); assert.ok(hash1.toString().trim() !== hash2.toString().trim()) finish(); }) }) } ================================================ FILE: test/sepia.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .sepia(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-modulate', args[2]); assert.equal('115,0,100', args[3]); assert.equal('-colorize', args[4]); assert.equal('7,21,50', args[5]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'sepia.png'); m.write(destPath, function sepia (err) { finish(err); }); } ================================================ FILE: test/setFormat.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .setFormat('png'); assert.equal('png', m._outputFormat); if (!GM.integration) return finish(); const destPath = path.join(dir, 'setFormat.png'); m.write(destPath, function setformat (err) { finish(err); }); } ================================================ FILE: test/sharpen.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .sharpen(19, 10); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-sharpen', args[2]); assert.equal('19x10', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'sharpen.png'); m.write(destPath, function sharpen (err) { finish(err); }); } ================================================ FILE: test/solarize.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .solarize(68.5); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-solarize', args[2]); assert.equal('68.5%', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'solarize.png'); m.write(destPath, function solarize (err) { finish(err); }); } ================================================ FILE: test/spread.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .spread(12); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-spread', args[2]); assert.equal(12, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'spread.png'); m.write(destPath, function spread (err) { finish(err); }); } ================================================ FILE: test/streamIn.js ================================================ const assert = require('assert'); const path = require('path'); const fs = require('fs'); module.exports = function (_, dir, finish, gm, imageMagick) { const originalPath = path.join(dir, 'original.jpg'); const stream = fs.createReadStream(originalPath); const m = gm(stream, "original.jpg").options({imageMagick}); assert.equal(stream, m.sourceStream); assert.equal('original.jpg', m.source); if (!gm.integration) return finish(); const destPath = path.join(dir, 'streamIn.png'); m.write(destPath, function streamIn (err) { finish(err); }); } ================================================ FILE: test/streamInGetter.js ================================================ const path = require('path'); const fs = require('fs'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const originalPath = path.join(dir, 'original.jpg'); gm(fs.createReadStream(originalPath)) .options({imageMagick}) .size({bufferStream: true}, function (err, size) { const destPath = path.join(dir, 'streamInGetter.png'); this.write(destPath, function streamInGetter (err){ finish(err); }); }); } ================================================ FILE: test/streamInOut.js ================================================ const path = require('path'); const fs = require('fs'); module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish(); const originalPath = path.join(dir, 'original.jpg'); gm(fs.createReadStream(originalPath), "original.jpg") .options({imageMagick}) .stream(function streamOut (err, stdout, stderr) { if (err) return finish(err); const destPath = path.join(dir, 'streamInOut.jpg'); stdout.pipe(fs.createWriteStream(destPath)); stdout.on('error', finish); stdout.on('close', finish); }); } ================================================ FILE: test/streamOut.js ================================================ const path = require('path'); const fs = require('fs'); module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); withCallback(function (err) { if (err) return finish(err); withoutCallback(finish); }); function withCallback(done) { gm .stream(function streamOut (err, stdout, stderr) { if (err) return done(err); const destPath = path.join(dir, 'streamOut.png'); stdout.pipe(fs.createWriteStream(destPath)); stdout.on('error', done); stdout.on('close', done); }); } function withoutCallback(done) { var stream = gm.stream() stream.on('error', done) const destPath = path.join(dir, 'streamOut2.png'); stream.pipe(fs.createWriteStream(destPath)) stream.on('end', done) } } ================================================ FILE: test/streamOutFormat.js ================================================ const assert = require('assert') const path = require('path'); const fs = require('fs'); module.exports = function (gm, dir, finish, GM, imageMagick) { if (!GM.integration) return finish(); withCallback(function (err) { if (err) return finish(err); withoutCallback(function (err) { if (err) return finish(err); checkOutputFormat(finish); }); }); function withCallback(done) { gm .stream('PNG', function streamOut (err, stdout, stderr) { if (err) return done(err); const destPath = path.join(dir, 'streamOutFormat.png'); stdout.pipe(fs.createWriteStream(destPath)); stdout.on('error', done); stdout.on('close', done); }); } function withoutCallback(done) { var stream = gm.stream('PNG') stream.on('error', done) const destPath = path.join(dir, 'streamOutFormat2.png'); stream.pipe(fs.createWriteStream(destPath)) stream.on('end', done) } function checkOutputFormat(done) { var stream = gm.stream('PNG') stream.on('error', done) GM(stream).options({imageMagick}).format(function (err, value) { if (err) return done(err) assert.equal(value.toLowerCase(), 'png') done() }) } } ================================================ FILE: test/strip.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (!gm._options.imageMagick) return finish(); var m = gm .strip(); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-strip', args[2]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'strip.png'); m.write(destPath, function strip (err) { finish(err); }); } ================================================ FILE: test/subclass.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (_, dir, finish, gm, imageMagick) { assert.equal('gm', gm('test').constructor.name); assert.equal(undefined, gm.prototype._options.imageMagick); var sub = gm.subClass({ imageMagick: true }); assert.equal('gm', sub('test').constructor.name); assert.equal(true, sub.prototype._options.imageMagick); assert.equal(undefined, gm.prototype._options.imageMagick); var s = sub('test'); assert.equal(true, s._options.imageMagick); var g = gm('test'); assert.equal(undefined, g._options.imageMagick); var imageMagick7 = gm.subClass({ imageMagick: '7+'}); assert.equal('7+', imageMagick7.prototype._options.imageMagick); if (!gm.integration) return finish(); const sourcePath = path.join(dir, 'photo.JPG'); const destPath = path.join(dir, 'subclass.png'); const m = gm.subClass({ imageMagick }); m(sourcePath) .thumb(50, 80, destPath, function subthumb (err) { if (err) return finish(err); finish(); }); } ================================================ FILE: test/swirl.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .swirl(129); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-swirl', args[2]); assert.equal(129, args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'swirl.png'); m.write(destPath, function swirl (err) { finish(err); }); } ================================================ FILE: test/text.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .blur(8, 4) .fontSize(68) .stroke("#efe", 2) .fill("#888") .drawText(-20, 98, "graphics magick"); var args = m.args(); assert.equal('convert', args[0]); args = args.slice(2) assert.deepEqual(args, [ '-blur', '8x4', '-pointsize', 68, '-strokewidth', 2, '-stroke', '#efe', '-fill', '#888', '-draw', 'text -20,98 "graphics magick"', '-' ]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'text.png'); m.write(destPath, function text (err) { finish(err); }); } ================================================ FILE: test/thumb.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); const destPath = path.join(dir, 'thumb.png'); gm.thumb(150, 40, destPath, function thumb (err) { finish(err); }); } ================================================ FILE: test/thumbnail.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (gm, dir, finish, GM) { var m = gm .thumbnail(200, 201); var args = m.args(); assert.equal('convert', args[0]); assert.equal('-thumbnail', args[2]); assert.equal('200x201', args[3]); if (!GM.integration) return finish(); const destPath = path.join(dir, 'thumbnail.png'); m.write(destPath, function thumbnail (err) { finish(err); }); } ================================================ FILE: test/timeout.js ================================================ const assert = require('assert'); const path = require('path'); module.exports = function (img, dir, finish, gm, imageMagick) { assert.equal(undefined, gm.prototype._options.timeout); assert.equal(undefined, img._options.timeout); var g = gm('test').options({ timeout: 100 }); assert.equal(100, g._options.timeout); var sub = gm.subClass({ timeout: 2000 }); assert.equal(2000, sub.prototype._options.timeout); if (!gm.integration) return finish(); const sourcePath = path.join(dir, 'photo.JPG'); const timeoutPath = path.join(dir, 'timeout.png'); gm(sourcePath).options({ timeout: 1, imageMagick }) .thumb(50, 80, timeoutPath, function subthumb (err) { assert.ok(err, "Expecting a timeout error"); noTimeout(); }); function noTimeout() { gm(sourcePath).options({ timeout: 0, imageMagick }) .thumb(50, 80, timeoutPath, function subthumb (err) { finish(err); }); } } ================================================ FILE: test/toBuffer.js ================================================ var assert = require('assert'); var fs = require('fs'); module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); gm .toBuffer(function (err, buffer) { if (err) return finish(err); assert.ok(buffer instanceof Buffer); assert.ok(buffer.length); finish(); }) } ================================================ FILE: test/toBufferFormat.js ================================================ var assert = require('assert'); var fs = require('fs'); module.exports = function (gm, dir, finish, GM) { if (!GM.integration) return finish(); gm .toBuffer('PNG', function (err, buffer) { if (err) return finish(err); assert.ok(buffer instanceof Buffer); assert.ok(buffer.length); finish(); }) } ================================================ FILE: test/utils.js ================================================ var assert = require('assert') module.exports = function (_, dir, finish, gm) { assert.equal('function', typeof gm.utils.escape); assert.equal('function', typeof gm.utils.unescape); finish(); } ================================================ FILE: test/webp.js ================================================ const assert = require('assert'); const path = require('path'); const fs = require('fs') module.exports = function (_, dir, finish, gm, imageMagick) { if (!gm.integration) return finish() // Don't know how to install IM with WEBP on ubuntu // if (require('os').platform() === 'linux') return finish() // GraphicsMagick currently does not support webp :( // if (!im) return finish() gm = gm.subClass({ imageMagick }) const imagePath = path.join(dir, 'original.png'); write(function (err) { if (err) return finish(err) stream(finish) }) function write(done) { const webpPath = path.join(dir, 'original.x.webp'); gm(imagePath) .write(webpPath, function (err) { if (err) return done(err) gm(webpPath).identify(function (err, value) { if (err) return done(err) assert.ok(value) assert.equal(value.format, 'WEBP') done() }) }) } function stream(done) { gm(imagePath) .stream('webp', function (err, stdout) { if (err) return done(err) gm(stdout).identify(function (err, value) { if (err) return done(err) assert.ok(value) assert.equal(value.format, 'WEBP') done() }) }) } }