Compare commits

...

221 Commits

Author SHA1 Message Date
Lovell Fuller
0144358afb Release v0.20.8 2018-09-05 08:44:01 +01:00
Lovell Fuller
136097efe7 Downgrade nyc for continued Node 4 support 2018-09-04 17:07:10 +01:00
Lovell Fuller
374c6959d7 Changelog and credit for #1358 #1362 2018-09-04 16:39:24 +01:00
Axel Eirola
7d48a5ccf4 Allow floating point density input (#1362)
Metadata output will still remain integer
2018-09-01 08:58:30 +01:00
ajhool
bf3254cb16 Install: avoid race conditions when creating directories (#1358) 2018-08-29 09:20:26 +01:00
Lovell Fuller
5bed3a7d52 Release v0.20.7 2018-08-21 11:50:14 +01:00
Lovell Fuller
ece111280b Use copy+unlink if rename fails during install #1345 2018-08-20 15:14:31 +01:00
Lovell Fuller
a15a9b956b Release v0.20.6 2018-08-20 11:40:10 +01:00
Lovell Fuller
42860c2f83 Changelog, credit and doc refresh for #1342 2018-08-19 10:43:25 +01:00
Alun Davies
b5b95e5ae1 Expose depth option for tile-based output (#1342) 2018-08-18 15:09:53 +01:00
Lovell Fuller
d705cffdd6 Ensure extractChannel works with 16-bit images #1330 2018-08-12 20:22:39 +01:00
Rodrigo Alviani
23a4bc103e Docs: correct quality option in overlayWith example (#1325) 2018-08-08 08:42:18 +01:00
Lovell Fuller
c14434f9e7 Add removeAlpha op, removes alpha channel if any #1248 2018-08-07 20:32:11 +01:00
Lovell Fuller
25bd2cea3e Add experimental entropy field to stats response 2018-08-06 15:41:27 +01:00
Lovell Fuller
532de4ecab Cache libvips binaries to reduce re-install time #1301 2018-08-05 10:31:41 +01:00
Lovell Fuller
bfdd27eeef Doc refresh and dependency bumps 2018-08-05 09:42:09 +01:00
Lovell Fuller
bd9f238ab4 Improve install time error messages for FreeBSD #1310 2018-08-04 22:27:32 +01:00
Lovell Fuller
75556bb57c Ensure vendor platform mismatch throws error #1303 2018-08-04 21:34:11 +01:00
thegareth
2de062a34a Docs: update the "make a transparent image" example (#1316)
Alpha for colour is between 0-1, not 0-255.
2018-08-02 09:42:25 +01:00
Lovell Fuller
4589b15dea Changelog and credit for #1285 #1290 2018-07-10 16:12:16 +01:00
Sylvain Dumont
8b75ce6786 Allow full WebP alphaQuality range of 0-100 (#1290) 2018-07-10 15:58:17 +01:00
Espen Hovlandsdal
7bbc5176a1 Expose mozjpeg quant_table flag (#1285) 2018-07-10 15:56:05 +01:00
Lovell Fuller
5cb35485f1 Release v0.20.5 2018-06-27 08:44:31 +01:00
Lovell Fuller
80189ed689 Add changelog and credit for #1265 2018-06-27 07:54:41 +01:00
Muhammad Faheem Akhtar
3d7e8ef432 Docs: update new Buffer() to Buffer.from() (#1273) 2018-06-26 08:19:27 +01:00
Lovell Fuller
1999c7103c Docs: add CSS to improve left-hand nav nesting 2018-06-25 19:58:50 +01:00
Thomas Vantuycom
9c20ae383e Remove top of file table of contents in documentation (#1270) 2018-06-24 21:45:51 +01:00
Tom Lokhorst
76c41eaf05 Expose libjpeg optimize_coding flag (#1265) 2018-06-21 18:12:10 +01:00
Lovell Fuller
873aa6700f Release v0.20.4 2018-06-20 08:26:28 +01:00
Lovell Fuller
0d9590a9a0 Documentation refresh 2018-06-20 08:14:03 +01:00
Lovell Fuller
94607b585a Ensure extractChannel sets bw colourspace interp #1257 2018-06-19 22:47:52 +01:00
Lovell Fuller
da0b0348a2 Prevent rounding err with shrink-on-load and 90/270 rot #1241 2018-06-19 21:19:34 +01:00
Lovell Fuller
09263455b5 Release v0.20.3 2018-05-29 08:38:42 +01:00
Lovell Fuller
ddc23493d4 Add warning about possible concurrent tile race #1151 2018-05-25 19:53:23 +01:00
Lovell Fuller
54a71fc142 Fix tint op by ensuring LAB and allowing negative values #1235
Add test cases for more tint colours and input interpretations
2018-05-23 20:51:47 +01:00
Lovell Fuller
b1a9bf10a2 Pre-built binaries provided for even-numbered major versions 2018-05-21 11:44:34 +01:00
Lovell Fuller
97cfbe1b63 Bump dependency versions 2018-05-19 15:19:23 +01:00
Lovell Fuller
0ee8c63551 Replace use of libvips API deprecated since v8.6.1
See jcupitt/libvips@b085908
2018-05-19 15:03:50 +01:00
Lovell Fuller
0ac5a9ad82 Promote nw.js details to main installation docs - see 6e51f2d 2018-05-19 14:53:22 +01:00
Michael
6e51f2d608 rebuild doc for NW.js (#1229)
refers to https://github.com/lovell/sharp/issues/1223
2018-05-15 07:28:09 +01:00
Lovell Fuller
f23a8dc9dc Release v0.20.2 2018-04-28 18:29:32 +01:00
Lovell Fuller
d09fe6178c Add support for Node 10, drop support for Node 9 2018-04-28 18:12:10 +01:00
Lovell Fuller
ae2cfcc4f3 Version bumps, hold simple-get at v2 for Node 4 support 2018-04-28 18:11:20 +01:00
Lovell Fuller
853cc65e32 Changelog entry for #1208 2018-04-28 14:06:45 +01:00
Nathan Graves
5d140d949f Add support for Group4 (CCITTFAX4) compression to TIFF output (#1208) 2018-04-26 19:49:08 +01:00
Lovell Fuller
6d2da2b3ba Switch unzip test dependency for Node 10 support 2018-04-25 20:37:10 +01:00
Lovell Fuller
165e337e44 Changelog entry and doc refresh for #1204 2018-04-25 10:19:33 +01:00
Nathan Graves
b154cd0418 Add support for page selection with multi-page TIFF input (#1204) 2018-04-24 22:57:27 +01:00
Lovell Fuller
8ef1532691 Dependency version bumps 2018-04-17 20:46:22 +01:00
Lovell Fuller
771e44f2a7 Add error highlighting lack of Windows x86 node.exe support 2018-04-17 20:37:19 +01:00
Lovell Fuller
8933f1128d Changelog entry and credit for #1165 2018-04-11 20:30:16 +01:00
Rik Heywood
dbac4b9a63 Add tint operation to set image chroma 2018-04-11 20:05:48 +01:00
Lovell Fuller
bdac5b5807 Add code usage examples for output-related functions 2018-04-06 19:52:00 +01:00
Lovell Fuller
b0961b5213 Bump dependencies 2018-04-06 19:49:17 +01:00
Thomas Parisot
0d7c3fc4d8 Ignore global libvips during install via SHARP_IGNORE_GLOBAL_LIBVIPS (#1165) 2018-03-22 18:48:30 +00:00
Lovell Fuller
8dac256096 Release v0.20.1 2018-03-17 14:04:35 +00:00
Lovell Fuller
8320da39c3 Changelog entry and doc refresh for #1161 2018-03-17 11:12:43 +00:00
Andrea Bianco
875937e3d8 Expose libvips' median filter operation (#1161) 2018-03-17 10:52:44 +00:00
Lovell Fuller
f880adbaac Bump dependencies ahead of v0.20.1 2018-03-16 20:46:08 +00:00
Lovell Fuller
48c5f86adb Improve install when global libvips below min version #1148 2018-03-13 20:37:42 +00:00
Lovell Fuller
f60f7dab12 Prevent error when cumulative rounding below target #1154 2018-03-13 19:42:10 +00:00
Lovell Fuller
8f690236ed Release v0.20.0 2018-03-04 21:54:28 +00:00
Lovell Fuller
430a4297aa Add support for prebuilt sharp binaries on common platforms 2018-03-04 14:33:44 +00:00
Oskar Thornblad
69e3ab02c4 Mention EXIF orientation in metadata's jsdocs (#1142) 2018-03-04 14:19:53 +00:00
Lovell Fuller
b87a20b881 Release v0.19.1 2018-02-24 10:02:12 +00:00
Lovell Fuller
0e6f2d16ab Bump dependencies 2018-02-23 19:27:34 +00:00
Lovell Fuller
498b061819 Upgrade nan dependency, enables async hooks 2018-02-23 19:18:31 +00:00
Lovell Fuller
5ab6f599fb Prevent crop when at or below target dimensions #1134 2018-02-23 10:31:11 +00:00
Lovell Fuller
8b80626035 Changelog, credit and doc refresh for #1121 2018-02-18 19:14:37 +00:00
Andrea Bianco
f86ae79fdb Expose angle option in tile feature (#1121) 2018-02-18 20:00:08 +01:00
Lovell Fuller
1a4e68096f Changelog and credit for #1024, bump dependencies 2018-02-04 13:30:47 +00:00
Marcel
d599d1f29e Expose linear transform feature of libvips (#1024) 2018-02-04 10:36:04 +00:00
Lovell Fuller
73edfb3d2c Update list of files that npm can ignore 2018-01-13 10:28:31 +00:00
Lovell Fuller
ebae68d579 Doc refresh for #1077 2018-01-13 10:27:43 +00:00
Tony Mobily
573836e2b8 Add mention of max() to preserve ratio in withoutEnlargement (#1077) 2018-01-13 09:59:59 +00:00
Lovell Fuller
da5deb8177 Release v0.19.0 2018-01-11 22:31:51 +00:00
Lovell Fuller
8fca89e876 Update documentation hostname 2018-01-10 23:35:50 +00:00
Lovell Fuller
d5295a2d0c Doc refresh for #1079 2018-01-10 22:24:46 +00:00
Oleg Aleynik
c4df115948 Expose IPTC and XMP metadata when available (#1079) 2018-01-10 22:12:11 +00:00
Lovell Fuller
8afcb16d8e Update performance benchmark results for v0.19.0 2018-01-07 14:30:25 +00:00
Lovell Fuller
3764d63244 Add valgrind suppressions for Node 8 2018-01-06 13:39:26 +00:00
Lovell Fuller
c82914df30 Doc refresh and devDependencies version bumps 2018-01-06 00:07:35 +00:00
Lovell Fuller
84ba921f5b Unpin tar dep as race condition is fixed - see 053e727 2018-01-05 10:51:24 +00:00
Lovell Fuller
8e74668e3c Update linter plus related spacing fixes 2018-01-05 10:18:08 +00:00
Lovell Fuller
707c05b5f5 Update libvips dependency minimum to v8.6.1 2018-01-05 09:57:33 +00:00
Lovell Fuller
9bd2cec199 Update benchmark test dependencies 2018-01-02 20:19:11 +00:00
Lovell Fuller
358b8fe8b6 Refresh Lambda install docs to recommend use of Docker 2017-12-22 19:31:03 +00:00
Lovell Fuller
7115ae5375 Prevent toFile ext taking precedence over toFormat #1037 2017-12-20 20:33:08 +00:00
Lovell Fuller
13997ca653 Run unit test files sequentially through valgrind 2017-12-18 19:57:26 +00:00
Lovell Fuller
9fa04a0b93 Attach event listener to clone only for Stream #995 2017-12-12 21:53:27 +00:00
Lovell Fuller
0894145284 Changelog and doc refresh for #1038 2017-12-12 19:42:07 +00:00
Kenric D'Souza
927b77700d Add gravity support to embed feature (#1038) 2017-12-12 19:29:16 +00:00
Lovell Fuller
1d7a0ea99e Changelog and doc refresh for #915 2017-12-09 13:14:23 +00:00
Rahul Nanwani
d6aee8e5ba Add pixel-derived image statistics via vips_stats (#915) 2017-12-09 11:17:48 +00:00
Lovell Fuller
dfaa39fa5d Enable OS X CI 2017-12-09 10:47:02 +00:00
Lovell Fuller
8fe3b59efe Update test fixtures for e9b7231ac0 2017-12-08 17:54:39 +00:00
Lovell Fuller
47237b1f15 Add expected min libvips version to error messages 2017-12-07 23:16:33 +00:00
Lovell Fuller
053e727bd5 Pin tar dependency as latest version has a race condition with Node 4 2017-12-01 19:00:28 +00:00
Lovell Fuller
2ce9e81d80 Wait for close event before decompressing tarball
Should reduce the chance of a race condition
2017-11-30 20:29:18 +00:00
Lovell Fuller
50848ee462 Add unit test coverage report for C++ 2017-11-30 20:16:30 +00:00
Lovell Fuller
ef06d560cd Windows CI: retry npm install to workaround race condition 2017-11-30 20:12:14 +00:00
Lovell Fuller
2abf9f96c7 Force TIFF predictor=none to match fixture in squash tests 2017-11-27 19:55:20 +00:00
Lovell Fuller
a91686b4cd Temporarily revert to previous npm for Node 9 support 2017-11-27 19:38:44 +00:00
Lovell Fuller
1be424cd47 Add missing file from commit fc233ed 2017-11-27 19:35:08 +00:00
Lovell Fuller
929ea10f76 Re-enable test for 1200 DPI SVG rasterisation to PNG 2017-11-27 19:31:31 +00:00
Lovell Fuller
11d1f39e3d Add Node 9 to CI test environments 2017-11-27 19:15:09 +00:00
Lovell Fuller
fc233ed4ff Update upstream libvips source to v8.6.0-beta1 2017-11-27 19:14:30 +00:00
Lovell Fuller
efd2e893cf Ensure expected fixtures match libvips v8.6.0 behaviour 2017-11-27 19:13:39 +00:00
Lovell Fuller
2a18b9a8f7 Remove centreSampling option, update some expected test fixtures
See https://github.com/jcupitt/libvips/issues/705
2017-11-26 13:49:56 +00:00
Lovell Fuller
6aa214181b Version bump dependencies 2017-11-25 11:25:27 +00:00
Lovell Fuller
7067beda99 Docs refresh for cropOffsetLeft/cropOffsetTop 2017-11-25 11:24:53 +00:00
Lovell Fuller
e0f0baf164 Silence a couple of MSVC type conversion warnings 2017-11-17 20:10:10 +00:00
Lovell Fuller
1fec132dee Add tilecache before smartcrop to avoid over-computation 2017-11-17 19:53:50 +00:00
Lovell Fuller
ba521fccb4 Replace caw with its tunnel-agent dependency 2017-11-07 19:38:10 +00:00
Lovell Fuller
965a97105e Default TIFF predictor to horizontal to match libvips' behaviour 2017-10-19 19:40:07 +01:00
Lovell Fuller
3c88c84998 Doc refresh, changelog and dead code removal for #977 2017-10-19 11:05:43 +01:00
Jarda Kotěšovec
d0f66c3734 Switch to libvips' resize, make fastShrinkOnLoad optional (#977) 2017-10-19 11:05:43 +01:00
Lovell Fuller
ebc2a741f6 Ensure accessMethod is applied during shrink-on-load 2017-10-19 11:05:43 +01:00
Lovell Fuller
d46512af1c Doc refresh and changelog entry for #976 2017-10-19 11:05:43 +01:00
Matthew McEachen
b4d72bd544 Add failOnError option to fail-fast on bad input image data (#976) 2017-10-19 11:05:43 +01:00
Lovell Fuller
382d476271 Temporarily allow CI failures on OS X 2017-10-19 11:05:43 +01:00
Lovell Fuller
80c240b54a Add compile time check for libvips 8.6.0+ 2017-10-19 11:05:43 +01:00
Lovell Fuller
21f99d88ab Docs: possible to install libvips via pkg on FreeBSD 2017-10-19 11:05:43 +01:00
Lovell Fuller
d5873a00d5 Docs refresh 2017-10-19 11:05:43 +01:00
Lovell Fuller
99076edc89 Default PNG output to adaptiveFiltering=false, compressionLevel=9
PNG is mostly used for logos and line art, so these defaults will
produce the smallest files for most output most of the time.
2017-10-19 11:05:43 +01:00
Lovell Fuller
7b6c80327e Verify platform of vendor binaries at install and run time 2017-10-19 11:05:43 +01:00
Lovell Fuller
57946ed672 Upgrade to libvips v8.6.0
Expose offset coordinates of strategy-based crop
Switch to Github releases for prebuilt libvips
Move packaging scripts to lovell/sharp-libvips repo
2017-10-19 11:05:43 +01:00
Aditya Bharti
aad16ac50d Improved jsdocs for withoutEnlargement and sequentialRead #972 (#992) 2017-10-15 09:28:08 +01:00
Brooks Becton
bbe897e607 Added Coding tools section and added types link (#975) 2017-10-04 13:02:11 +01:00
Mika Fischer
eca0e66e23 Remove use of dynamic require to facilitate bundling (#960) 2017-09-25 21:00:40 +01:00
Lovell Fuller
3511723914 Release v0.18.4 2017-09-18 18:26:12 +01:00
Lovell Fuller
6a1c7b7588 Ensure input Buffer really is marked as Persistent #950 2017-09-16 20:17:32 +01:00
Lovell Fuller
18fd6ef119 Release v0.18.3 2017-09-13 10:51:08 +01:00
Matt Parrish
0004f5d2ff Migrate from got to simple-get (#945)
The simple-get module provides support for basic auth and
is already used by the future prebuild dependency.
2017-09-12 07:38:17 +01:00
Mario Viens
5f29d1ba9c Clarifying cache documentation (#919) 2017-08-19 10:43:36 +01:00
Jasper Blues
791fd35c35 Update README.md (#913) 2017-08-16 12:09:02 +01:00
Kleis Auke Wolthuizen
e0d622d347 Skip shrink-on-load when trimming (#887) (#888) 2017-07-28 21:02:30 +01:00
Lovell Fuller
6b34e8a804 Docs: FreeBSD gcc v4/v5 needs _GLIBCXX_USE_C99 for C++11 #873 2017-07-25 14:54:44 +01:00
Lovell Fuller
eb8773fe3e Use detect-libc instead of ldd output parsing 2017-07-17 12:11:13 +01:00
Lovell Fuller
b40e3fa1f1 Docs: Alpine vips-dev package requires fftw-dev also 2017-07-15 14:47:25 +01:00
Lovell Fuller
d25d761b55 Update benchmark deps, allow node-images to fail 2017-07-14 13:18:13 +01:00
Lovell Fuller
d6051dd714 Release v0.18.2 2017-07-01 09:52:47 +01:00
Lovell Fuller
53ff061efa Document SHARP_DIST_BASE_URL #841 2017-07-01 09:44:02 +01:00
Lovell Fuller
72b0efd393 Remove possible switch case fall through
Luckily there were no side effects in this... case
2017-06-25 19:09:20 +01:00
Lovell Fuller
df97ef23d9 Document/changelog for Solus Linux support #857 2017-06-25 17:42:03 +01:00
Ekrem Karaca
f6373971bd Add support for Solus OS (#857) 2017-06-24 13:48:03 +01:00
Lovell Fuller
ec617f2489 Document minimum Node dependency of v4.5.0 #847 2017-06-20 22:05:05 +01:00
Lovell Fuller
502ae78579 Allow binary download URL override via SHARP_DIST_BASE_URL #841 2017-06-20 21:40:46 +01:00
Lovell Fuller
49297d6afb Ensure flip and flop operations work with auto-rotate #837 2017-06-19 23:42:26 +01:00
Lovell Fuller
29354badd8 Docs: add Alpine Linux install details 2017-06-19 08:13:49 +01:00
Lovell Fuller
3c4de796c8 Dependency bumps and next point release 2017-06-04 19:55:45 +01:00
Lovell Fuller
c7f4488e77 Docs and changelog entry for #828 2017-06-04 19:51:22 +01:00
Yves Bos
d8765f955d Allow xres and yres to be set for TIFF output (#828) 2017-06-03 10:52:09 +01:00
Lovell Fuller
9f20037dad Release v0.18.1 2017-05-30 21:02:35 +01:00
Lovell Fuller
2ebb090df2 Update Travis CI to Ubuntu 16.04
Rollback Appveyor CI from Node 8 to 7
2017-05-30 20:50:32 +01:00
Lovell Fuller
110fff3ab9 Replace Node 7 with Node 8 in CI environment 2017-05-30 20:32:15 +01:00
Lovell Fuller
f42a1ceab7 Recalculate residual after adjusting shrink #831 2017-05-30 20:22:15 +01:00
Lovell Fuller
9e39a7fa95 Correct shrink calc, regression introduced in e398b47 #831 2017-05-30 17:16:41 +01:00
Lovell Fuller
c879df3b31 Release v0.18.0 2017-05-30 08:09:59 +01:00
Lovell Fuller
361ed98353 Remove previously-deprecated output format 'option' functions 2017-05-23 21:57:05 +01:00
Lovell Fuller
d45f8ef2d3 Document the cache-free nature of metadata extraction #796 2017-05-23 21:24:29 +01:00
Lovell Fuller
d6a63d11d7 Docs refresh 2017-05-22 21:49:37 +01:00
jingsam
4c6804eadc Add toFormat 'jpg' alias for 'jpeg' (#814) 2017-05-22 12:59:43 +01:00
Nicolas Coden
99810c0311 Add support for any rotation angle (#791)
Allow to provide any positive or negative multiple of 90 to `.rotate(...)`.
Negative angles and angles above 360 are converted to valid 0/90/180/270
rotations (0 rotations are still ignored).

Changes:
- [Node] Add `useExifOrientation` internal variable to know if the Exif
  orientation must be used instead of the provided angle. This allows to save a
  negative angle in the `angle` option, because the `-1` special case is not
  needed.

- [Node] Change check for planed-rotation in extract, to prepare a
  rotation before extraction: check with both `angle` and `useExifOrientation`
  options.
  I think this check contains a bit too much logics on rotation options. Maybe
  we could move this condition to a dedicated function.

- [C++] Separate `CalculateRotationAndFlip` into two generic functions:
  - `CalculateExifRotationAndFlip`: Calculate the angle of rotation and
    need-to-flip for the given Exif orientation.
  - `CalculateAngleRotation`: Calculate the rotation for the given angle.

  One or the other function is used to calculate the rotation, depending on
  wether the Exif orientation tag or the provided angle must be used.

- Add unit tests for `-3690`, `-450`, `-90`, `90`, `450`, `3690` and `-3780`,
  `-540`, `0`, `180`, `540`, `3780` rotations
- Add `320x240` fixture image for tests.

Unrelated changes (squashed):
- Add ncoden to the list of contributors
2017-05-22 11:08:33 +01:00
gmaliar
d15fb1ab1b Docs: add link to TailorBrands-maintained libvips Dockerfiles (#813) 2017-05-21 20:37:57 +01:00
Lovell Fuller
0a6d8b37ad Ensure double to int cast introduced in 4d1a169 is static 2017-05-21 19:05:56 +01:00
Lovell Fuller
f78ffdb9ce Upgrade to libvips v8.5.5 2017-05-21 18:31:06 +01:00
Lovell Fuller
b7b6fdbdf5 Update perf test contenders, add node-images 2017-05-13 20:08:53 +01:00
Lovell Fuller
e398b471e1 Prevent aliasing by using dynamic values for shrink(-on-load) 2017-05-13 18:46:39 +01:00
Lovell Fuller
48f69f3d88 Upgrade libpng to v1.6.29 2017-05-13 18:20:54 +01:00
Lovell Fuller
95850d75f6 Include pixel format depth when reading metadata 2017-05-07 09:29:38 +01:00
Lovell Fuller
c41d755441 Ctor single arg: allow plain object, reject null/undefined
Thank you @kub1x
2017-05-06 19:03:14 +01:00
Lovell Fuller
39a21787b7 Remove 'require' test as bufferutil now ships prebuilt 2017-05-06 15:49:50 +01:00
Lovell Fuller
36078f9903 Switch to the libvips crop strategy implementations 2017-05-06 14:46:28 +01:00
Lovell Fuller
2f534dc01c Base maximum output dimensions on limitation of format 2017-05-04 23:20:37 +01:00
Lovell Fuller
c8e59f08ec Add support for Buffer and Stream-based TIFF output 2017-05-04 16:40:49 +01:00
Lovell Fuller
19dd6a997f Doc refresh, thank you @cspotcode 2017-05-01 09:34:10 +01:00
Lovell Fuller
4d1a1694cd Improve perf/accuracy of nearest neighbour integral upsample 2017-04-30 20:54:48 +01:00
Lovell Fuller
52bea15ad7 Upgrade libvips dependency to v8.5.4, plus other bumps 2017-04-26 23:04:08 +01:00
Lovell Fuller
6592361c5a Ensure ARM64 pre-built binaries use correct C++11 ABI 2017-04-26 21:41:03 +01:00
Lovell Fuller
f3f83494f5 Credit contributor YvesBos 2017-04-26 21:40:30 +01:00
Lovell Fuller
1169afbe90 Avoid (un)premultiplication for overlay image without alpha channel
Add 'premultiplied' boolean attribute to output info, helps test
2017-04-26 21:37:43 +01:00
Lovell Fuller
301bfbd271 Expose libvips warnings via NODE_DEBUG env var 2017-04-26 21:37:43 +01:00
Lovell Fuller
46aec7eabc Upgrade libvips dependency and packaging to v8.5.1 2017-04-26 21:37:43 +01:00
YvesBos
4cd3b66761 Add support for squashing TIFF output to 1-bit (#783) 2017-04-26 17:47:29 +01:00
Jakub Podlaha
567e3dd258 Add gentoo support to glibc detection (#760) 2017-04-06 15:17:30 +01:00
Lovell Fuller
fcf853712c Release v0.17.3 2017-04-01 10:20:44 +01:00
Lovell Fuller
088d36b47b Add support for TIFF float predictor 2017-04-01 10:08:47 +01:00
Lovell Fuller
27fb864ac4 Update dev deps, deconstify all the functions, API doc refresh 2017-03-31 21:42:23 +01:00
Lovell Fuller
4001c4a48a Add changelog and credit for #738 2017-03-31 21:17:19 +01:00
Sagiv Frankel
f64c18ef15 Docs: Add download info to Heroku section (#748) 2017-03-30 12:55:33 +01:00
Kristo Jorgenson
f8e72f443d Expose TIFF compression and predictor options (#738) 2017-03-29 12:12:04 +01:00
Lovell Fuller
5e015cc3ca Docs: use NODE_MODULES_CACHE=false for Heroku+yarn #722 2017-03-27 20:31:50 +01:00
Andreas Lind
9707f8c5d2 Add support for passing the crop strategy as a string (#735) 2017-03-16 14:27:09 +00:00
Lovell Fuller
6b1d698448 Add credit and changelog for #732 2017-03-16 07:37:05 +00:00
Alice Monday
72f69dda30 Add support for the "nearest" kernel for image reductions (#732) 2017-03-14 10:29:23 +00:00
Lovell Fuller
8b5d8a0577 Switch from seq to random access for normalise and 'smart' crop 2017-03-11 19:56:55 +00:00
Lovell Fuller
1aa053ce6f Create blank image (width, height, channels, background) #470 2017-03-11 11:46:01 +00:00
Lovell Fuller
701b1c4216 Document overlayWith image density parameter #729 2017-03-10 22:59:46 +00:00
Lovell Fuller
f1c4cef781 Version bump of dev dependencies 2017-03-04 22:28:01 +00:00
Lovell Fuller
6fe5b307b1 Allow toBuffer to resolve Promise with info+data #143 2017-03-04 22:15:31 +00:00
Lovell Fuller
679ce08998 Small doc updates 2017-03-04 18:37:23 +00:00
Lovell Fuller
eeb923eb5b Update docs domain name 2017-03-04 18:36:18 +00:00
Lovell Fuller
142c431745 Release v0.17.2 2017-02-11 10:35:34 +00:00
Lovell Fuller
81f5589411 Add use of 'cc' to improve C++ code style linting 2017-02-11 09:59:23 +00:00
Mark van Seventer
04f5c884a4 Add CLI tools section to installation guide (#691) 2017-01-25 21:34:23 +00:00
Lovell Fuller
d8df503404 Ensure Readable can start flowing after Writable finish #671 2017-01-22 14:03:06 +00:00
Lovell Fuller
d241efcdbe Add changelog entry and credit for #685 2017-01-22 13:58:11 +00:00
Rahul Nanwani
a1b8efe721 Expose WebP alpha quality, lossless and near-lossless output options (#685) 2017-01-19 13:45:32 +00:00
Lovell Fuller
815d076b35 Release v0.17.1 2017-01-15 15:23:49 +00:00
Lovell Fuller
86b4816b3f Allow HTTP-over-HTTPS proxy when d/l pre-compiled deps #679 2017-01-14 11:23:13 +00:00
Lovell Fuller
473055468a Docs: ensure alpha attribute is used for transparency 2017-01-13 21:24:57 +00:00
Brandon Aaron
c6a28db8b1 Packaging: bump zlib to 1.2.10 and png16 to 1.6.28 (#676) 2017-01-10 18:19:23 +00:00
子龙山人
971f567571 Docs: correct alpha attribute in extend background example (#675) 2017-01-09 10:47:02 +00:00
Lovell Fuller
7e2eca3d1e Credit recent new contributors, thank you! 2017-01-05 22:27:30 +00:00
Lovell Fuller
86b0053bf0 Removed preinstall.sh script 2017-01-05 22:21:41 +00:00
Lovell Fuller
cfc4b282f0 Doc refresh for d9b667e 2017-01-05 22:20:33 +00:00
Lovell Fuller
b85d2aa565 Merge branch 'master' of https://github.com/lovell/sharp 2017-01-05 22:17:16 +00:00
Lovell Fuller
70a3d4fb5e Improve error messages for invalid resize parameters
Dependency version bumps and doc refresh
2017-01-05 22:17:04 +00:00
Adam Coyne
d9b667e346 Docs: remove parentheses from sharp.format (#663) 2016-12-31 19:32:18 +00:00
Jérémy Lal
3a1db53d5a Simpler expression for finding vips-cpp libdir (#656)
Fixes: #655
2016-12-18 08:57:50 +00:00
191 changed files with 7052 additions and 3098 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
src/libvips/* linguist-vendored

7
.gitignore vendored
View File

@@ -1,6 +1,6 @@
build
node_modules
coverage
/coverage
test/bench/node_modules
test/fixtures/output*
test/leak/libvips.supp
@@ -9,8 +9,7 @@ test/saliency/Image*
test/saliency/[Uu]serData*
!test/saliency/userData.js
vendor
packaging/libvips*
packaging/*.log
!packaging/build
.gitattributes
.DS_Store
.nyc_output
package-lock.json

View File

@@ -2,13 +2,14 @@ build
node_modules
coverage
.editorconfig
.gitattributes
.gitignore
test
.travis.yml
appveyor.yml
circle.yml
mkdocs.yml
docs/css/
vendor
packaging
preinstall.sh
.prebuildrc
.nyc_output
CONTRIBUTING.md

4
.prebuildrc Normal file
View File

@@ -0,0 +1,4 @@
{
"include-regex": "(sharp\\.node|libvips-cpp\\.dll)",
"strip": true
}

View File

@@ -1,21 +1,34 @@
language: node_js
node_js:
- "4"
- "6"
- "7"
os:
- linux
- osx
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
osx_image: xcode8
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-4.8; fi
matrix:
include:
- os: linux
dist: trusty
sudo: false
node_js: "4"
- os: linux
dist: trusty
sudo: false
node_js: "6"
- os: linux
dist: trusty
sudo: false
node_js: "8"
- os: linux
dist: trusty
sudo: false
node_js: "10"
- os: osx
osx_image: xcode8.3
node_js: "4"
- os: osx
osx_image: xcode8.3
node_js: "6"
- os: osx
osx_image: xcode8.3
node_js: "8"
- os: osx
osx_image: xcode8.3
node_js: "10"
after_success:
- npm install coveralls
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js

View File

@@ -14,7 +14,7 @@ New bugs are assigned a `triage` label whilst under investigation.
If a [similar request](https://github.com/lovell/sharp/labels/enhancement) exists, it's probably fastest to add a comment to it about your requirement.
Implementation is usually straightforward if _libvips_ [already supports](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/ch03.html) the feature you need.
Implementation is usually straightforward if _libvips_ [already supports](https://jcupitt.github.io/libvips/API/current/) the feature you need.
## Submit a Pull Request to fix a bug
@@ -41,9 +41,8 @@ Any change that modifies the existing public API should be added to the relevant
| Release | WIP branch |
| ------: | :--------- |
| v0.17.0 | quill |
| v0.18.0 | ridge |
| v0.19.0 | suit |
| v0.21.0 | teeth |
| v0.22.0 | uptake |
Please squash your changes into a single commit using a command like `git rebase -i upstream/<wip-branch>`.
@@ -72,12 +71,7 @@ These can be converted to Markdown by running:
npm run docs
```
The `types.d.ts` TypeScript declaration can be generated by running:
```sh
npm run types
```
Please include documentation and TypeScript declaration updates in any Pull Request that modifies the public API.
Please include documentation updates in any Pull Request that modifies the public API.
## Run the tests
@@ -95,15 +89,6 @@ Requires [Valgrind](http://valgrind.org/).
npm run test-leak
```
### Packaging tests
Tests the installation on a number of Linux-based operating systems.
Requires docker.
```sh
npm run test-packaging
```
## Finally
Please feel free to ask any questions via a

View File

@@ -4,6 +4,10 @@
npm install sharp
```
```sh
yarn add sharp
```
The typical use case for this high speed Node.js module
is to convert large images in common formats to
smaller, web-friendly JPEG, PNG and WebP images of varying dimensions.
@@ -17,19 +21,21 @@ Lanczos resampling ensures quality is not sacrificed for speed.
As well as image resizing, operations such as
rotation, extraction, compositing and gamma correction are available.
OS X, Windows (x64), Linux (x64, ARM) systems do not require
the installation of any external runtime dependencies.
Most modern 64-bit OS X, Windows and Linux (glibc) systems running
Node versions 4, 6, 8 and 10
do not require any additional install or runtime dependencies.
## Examples
```javascript
import sharp from 'sharp';
const sharp = require('sharp');
```
```javascript
sharp(inputBuffer)
.resize(320, 240)
.toFile('output.webp', (err, info) => ... );
// A Promises/A+ promise is returned when callback is not provided.
```
```javascript
@@ -42,7 +48,7 @@ sharp('input.jpg')
```
```javascript
const roundedCorners = new Buffer(
const roundedCorners = Buffer.from(
'<svg><rect x="0" y="0" width="200" height="200" rx="50" ry="50"/></svg>'
);
@@ -61,11 +67,11 @@ readableStream
### Documentation
Visit [sharp.dimens.io](http://sharp.dimens.io/) for complete
[installation instructions](http://sharp.dimens.io/page/install),
[API documentation](http://sharp.dimens.io/page/api),
[benchmark tests](http://sharp.dimens.io/page/performance) and
[changelog](http://sharp.dimens.io/page/changelog).
Visit [sharp.pixelplumbing.com](http://sharp.pixelplumbing.com/) for complete
[installation instructions](http://sharp.pixelplumbing.com/page/install),
[API documentation](http://sharp.pixelplumbing.com/page/api),
[benchmark tests](http://sharp.pixelplumbing.com/page/performance) and
[changelog](http://sharp.pixelplumbing.com/page/changelog).
### Contributing
@@ -74,7 +80,7 @@ covers reporting bugs, requesting features and submitting code changes.
### Licence
Copyright 2013, 2014, 2015, 2016 Lovell Fuller and contributors.
Copyright 2013, 2014, 2015, 2016, 2017, 2018 Lovell Fuller and contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -6,10 +6,11 @@ environment:
matrix:
- nodejs_version: "4"
- nodejs_version: "6"
- nodejs_version: "7"
- nodejs_version: "8"
- nodejs_version: "10"
install:
- ps: Install-Product node $env:nodejs_version x64
- npm install -g npm@latest
- npm install -g npm@5
- npm install
test_script:
- npm test

View File

@@ -5,9 +5,6 @@
['OS == "win"', {
# Build libvips C++ binding for Windows due to MSVC std library ABI changes
'type': 'shared_library',
'variables': {
'download_vips': '<!(node -e "require(\'./binding\').download_vips()")'
},
'defines': [
'VIPS_CPLUSPLUS_EXPORTS',
'_ALLOW_KEYWORD_MACROS'
@@ -49,43 +46,22 @@
'dependencies': [
'libvips-cpp'
],
# Nested variables "pattern" borrowed from http://src.chromium.org/viewvc/chrome/trunk/src/build/common.gypi
'variables': {
'variables': {
'variables': {
'conditions': [
['OS != "win"', {
# Build the PKG_CONFIG_PATH environment variable with all possible combinations
'pkg_config_path': '<!(which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR || true):$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig'
}, {
'pkg_config_path': ''
}]
],
},
'conditions': [
['OS != "win"', {
# Which version, if any, of libvips is available globally via pkg-config?
'global_vips_version': '<!(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --modversion vips-cpp 2>/dev/null || true)'
}, {
'global_vips_version': ''
}]
],
'pkg_config_path%': '<(pkg_config_path)'
},
'pkg_config_path%': '<(pkg_config_path)',
'runtime_link%': 'shared',
'conditions': [
['OS != "win"', {
# Does the globally available version of libvips, if any, meet the minimum version requirement?
'use_global_vips': '<!(GLOBAL_VIPS_VERSION="<(global_vips_version)" node -e "require(\'./binding\').use_global_vips()")'
'pkg_config_path': '<!(node -e "console.log(require(\'./lib/libvips\').pkgConfigPath())")',
'use_global_libvips': '<!(node -e "console.log(Boolean(require(\'./lib/libvips\').useGlobalLibvips()).toString())")'
}, {
'use_global_vips': ''
'pkg_config_path': '',
'use_global_libvips': ''
}]
]
},
'sources': [
'src/common.cc',
'src/metadata.cc',
'src/stats.cc',
'src/operations.cc',
'src/pipeline.cc',
'src/sharp.cc',
@@ -95,7 +71,7 @@
'<!(node -e "require(\'nan\')")'
],
'conditions': [
['use_global_vips == "true"', {
['use_global_libvips == "true"', {
# Use pkg-config for include and lib
'include_dirs': ['<!@(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --cflags-only-I vips-cpp vips glib-2.0 | sed s\/-I//g)'],
'conditions': [
@@ -107,12 +83,12 @@
['OS == "linux"', {
'defines': [
# Inspect libvips-cpp.so to determine which C++11 ABI version was used and set _GLIBCXX_USE_CXX11_ABI accordingly. This is quite horrible.
'_GLIBCXX_USE_CXX11_ABI=<!(if readelf -Ws "$(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs-only-L vips-cpp | cut -c 3- | sed -e "s/[[:space:]]*$//" | sed -e "s/^$/\/usr\/lib/")/libvips-cpp.so" | c++filt | grep -qF __cxx11;then echo "1";else echo "0";fi)'
'_GLIBCXX_USE_CXX11_ABI=<!(if readelf -Ws "$(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --variable libdir vips-cpp)/libvips-cpp.so" | c++filt | grep -qF __cxx11;then echo "1";else echo "0";fi)'
]
}]
]
}, {
# Attempt to download pre-built libvips and install locally within node_modules
# Use pre-built libvips stored locally within node_modules
'include_dirs': [
'vendor/include',
'vendor/include/glib-2.0',
@@ -130,9 +106,6 @@
]
}],
['OS == "mac"', {
'variables': {
'download_vips': '<!(node -e "require(\'./binding\').download_vips()")'
},
'libraries': [
'../vendor/lib/libvips-cpp.42.dylib',
'../vendor/lib/libvips.42.dylib',
@@ -143,9 +116,6 @@
]
}],
['OS == "linux"', {
'variables': {
'download_vips': '<!(LDD_VERSION="<!(ldd --version 2>&1 || true)" node -e "require(\'./binding\').download_vips()")'
},
'defines': [
'_GLIBCXX_USE_CXX11_ABI=0'
],
@@ -218,61 +188,5 @@
]
}
},
}, {
'target_name': 'win_copy_dlls',
'type': 'none',
'dependencies': [
'sharp'
],
'conditions': [
['OS == "win"', {
# Windows lacks support for rpath
'copies': [{
'destination': 'build/Release',
'files': [
'vendor/lib/GNU.Gettext.dll',
'vendor/lib/libasprintf-0.dll',
'vendor/lib/libcairo-2.dll',
'vendor/lib/libcairo-gobject-2.dll',
'vendor/lib/libcairo-script-interpreter-2.dll',
'vendor/lib/libcharset-1.dll',
'vendor/lib/libcroco-0.6-3.dll',
'vendor/lib/libexif-12.dll',
'vendor/lib/libexpat-1.dll',
'vendor/lib/libffi-6.dll',
'vendor/lib/libfftw3-3.dll',
'vendor/lib/libfontconfig-1.dll',
'vendor/lib/libfreetype-6.dll',
'vendor/lib/libgcc_s_seh-1.dll',
'vendor/lib/libgdk_pixbuf-2.0-0.dll',
'vendor/lib/libgif-7.dll',
'vendor/lib/libgio-2.0-0.dll',
'vendor/lib/libglib-2.0-0.dll',
'vendor/lib/libgmodule-2.0-0.dll',
'vendor/lib/libgobject-2.0-0.dll',
'vendor/lib/libgsf-1-114.dll',
'vendor/lib/libgthread-2.0-0.dll',
'vendor/lib/libiconv-2.dll',
'vendor/lib/libintl-8.dll',
'vendor/lib/libjpeg-62.dll',
'vendor/lib/liblcms2-2.dll',
'vendor/lib/libpango-1.0-0.dll',
'vendor/lib/libpangocairo-1.0-0.dll',
'vendor/lib/libpangowin32-1.0-0.dll',
'vendor/lib/libpixman-1-0.dll',
'vendor/lib/libpng16-16.dll',
'vendor/lib/libquadmath-0.dll',
'vendor/lib/librsvg-2-2.dll',
'vendor/lib/libssp-0.dll',
'vendor/lib/libstdc++-6.dll',
'vendor/lib/libtiff-5.dll',
'vendor/lib/libvips-42.dll',
'vendor/lib/libwebp-6.dll',
'vendor/lib/libxml2-2.dll',
'vendor/lib/zlib1.dll'
]
}]
}]
]
}]
}

View File

@@ -1,129 +0,0 @@
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const zlib = require('zlib');
const caw = require('caw');
const got = require('got');
const semver = require('semver');
const tar = require('tar');
const distBaseUrl = 'https://dl.bintray.com/lovell/sharp/';
// Use NPM-provided environment variable where available, falling back to require-based method for Electron
const minimumLibvipsVersion = process.env.npm_package_config_libvips || require('./package.json').config.libvips;
const platform = process.env.npm_config_platform || process.platform;
const arch = process.env.npm_config_arch || process.arch;
// -- Helpers
// Does this file exist?
const isFile = function (file) {
try {
return fs.statSync(file).isFile();
} catch (err) {}
};
const unpack = function (tarPath, done) {
const extractor = tar.Extract({ path: path.join(__dirname, 'vendor') });
if (done) {
extractor.on('end', done);
}
extractor.on('error', error);
fs.createReadStream(tarPath)
.on('error', error)
.pipe(zlib.Unzip())
.pipe(extractor);
};
const platformId = function () {
const platformId = [platform];
if (arch === 'arm' || arch === 'armhf' || arch === 'arch64') {
const armVersion = (arch === 'arch64') ? '8' : process.env.npm_config_armv || process.config.variables.arm_version || '6';
platformId.push('armv' + armVersion);
} else {
platformId.push(arch);
}
return platformId.join('-');
};
// Error
const error = function (msg) {
if (msg instanceof Error) {
msg = msg.message;
}
process.stderr.write('ERROR: ' + msg + '\n');
process.exit(1);
};
// -- Binary downloaders
module.exports.download_vips = function () {
// Has vips been installed locally?
const vipsHeaderPath = path.join(__dirname, 'vendor', 'include', 'vips', 'vips.h');
if (!isFile(vipsHeaderPath)) {
// Ensure Intel 64-bit or ARM
if (arch === 'ia32') {
error('Intel Architecture 32-bit systems require manual installation - please see http://sharp.dimens.io/en/stable/install/');
}
// Ensure glibc >= 2.15
const lddVersion = process.env.LDD_VERSION;
if (lddVersion) {
if (/(glibc|gnu libc)/i.test(lddVersion)) {
const glibcVersion = lddVersion ? lddVersion.split(/\n/)[0].split(' ').slice(-1)[0].trim() : '';
if (glibcVersion && semver.lt(glibcVersion + '.0', '2.13.0')) {
error('glibc version ' + glibcVersion + ' requires manual installation - please see http://sharp.dimens.io/en/stable/install/');
}
} else {
error(lddVersion.split(/\n/)[0] + ' requires manual installation - please see http://sharp.dimens.io/en/stable/install/');
}
}
// Arch/platform-specific .tar.gz
const tarFilename = ['libvips', minimumLibvipsVersion, platformId()].join('-') + '.tar.gz';
const tarPathLocal = path.join(__dirname, 'packaging', tarFilename);
if (isFile(tarPathLocal)) {
unpack(tarPathLocal);
} else {
// Download to per-process temporary file
const tarPathTemp = path.join(os.tmpdir(), process.pid + '-' + tarFilename);
const tmpFile = fs.createWriteStream(tarPathTemp).on('finish', function () {
unpack(tarPathTemp, function () {
// Attempt to remove temporary file
try {
fs.unlinkSync(tarPathTemp);
} catch (err) {}
});
});
const gotOpt = {};
if (process.env.npm_config_https_proxy) {
// Use the NPM-configured HTTPS proxy
gotOpt.agent = caw(process.env.npm_config_https_proxy);
}
const url = distBaseUrl + tarFilename;
got.stream(url, gotOpt).on('response', function (response) {
if (response.statusCode !== 200) {
error(url + ' status code ' + response.statusCode);
}
}).on('error', function (err) {
error('Download of ' + url + ' failed: ' + err.message);
}).pipe(tmpFile);
}
}
};
module.exports.use_global_vips = function () {
const globalVipsVersion = process.env.GLOBAL_VIPS_VERSION;
if (globalVipsVersion) {
const useGlobalVips = semver.gte(
globalVipsVersion,
minimumLibvipsVersion
);
process.stdout.write(useGlobalVips ? 'true' : 'false');
} else {
process.stdout.write('false');
}
};

View File

@@ -1,8 +0,0 @@
machine:
node:
version: v4.6.1
services:
- docker
test:
override:
- ./packaging/test-linux-x64.sh

View File

@@ -1,14 +1,30 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# extractChannel
## removeAlpha
Remove alpha channel, if any. This is a no-op if the image does not have an alpha channel.
### Examples
```javascript
sharp('rgba.png')
.removeAlpha()
.toFile('rgb.png', function(err, info) {
// rgb.png is a 3 channel image without an alpha channel
});
```
Returns **Sharp**
## extractChannel
Extract a single channel from a multi-channel image.
**Parameters**
### Parameters
- `channel` **([Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** zero-indexed band number to extract, or `red`, `green` or `blue` as alternative to `0`, `1` or `2` respectively.
- `channel` **([Number][1] \| [String][2])** zero-indexed band number to extract, or `red`, `green` or `blue` as alternative to `0`, `1` or `2` respectively.
**Examples**
### Examples
```javascript
sharp(input)
@@ -19,11 +35,11 @@ sharp(input)
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid channel
- Throws **[Error][3]** Invalid channel
Returns **Sharp**
# joinChannel
## joinChannel
Join one or more channels to the image.
The meaning of the added channels depends on the output colourspace, set with `toColourspace()`.
@@ -36,25 +52,25 @@ Channel ordering follows vips convention:
Buffers may be any of the image formats supported by sharp: JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data.
For raw pixel input, the `options` object should contain a `raw` attribute, which follows the format of the attribute of the same name in the `sharp()` constructor.
**Parameters**
### Parameters
- `images` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Buffer](https://nodejs.org/api/buffer.html))> | [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Buffer](https://nodejs.org/api/buffer.html))** one or more images (file paths, Buffers).
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** image options, see `sharp()` constructor.
- `images` **([Array][4]&lt;([String][2] \| [Buffer][5])> | [String][2] \| [Buffer][5])** one or more images (file paths, Buffers).
- `options` **[Object][6]** image options, see `sharp()` constructor.
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][3]** Invalid parameters
Returns **Sharp**
# bandbool
## bandbool
Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.
**Parameters**
### Parameters
- `boolOp` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
- `boolOp` **[String][2]** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
**Examples**
### Examples
```javascript
sharp('3-channel-rgb-input.png')
@@ -66,6 +82,18 @@ sharp('3-channel-rgb-input.png')
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][3]** Invalid parameters
Returns **Sharp**
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
[5]: https://nodejs.org/api/buffer.html
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object

View File

@@ -1,6 +1,6 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# background
## background
Set the background for the `embed`, `flatten` and `extend` operations.
The default background is `{r: 0, g: 0, b: 0, alpha: 1}`, black without transparency.
@@ -9,16 +9,30 @@ Delegates to the _color_ module, which can throw an Error
but is liberal in what it accepts, clipping values to sensible min/max.
The alpha value is a float between `0` (transparent) and `1` (opaque).
**Parameters**
### Parameters
- `rgba` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
- `rgba` **([String][1] \| [Object][2])** parsed by the [color][3] module to extract values for red, green, blue and alpha.
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameter
- Throws **[Error][4]** Invalid parameter
Returns **Sharp**
# greyscale
## tint
Tint the image using the provided chroma while preserving the image luminance.
An alpha channel may be present and will be unchanged by the operation.
### Parameters
- `rgb` **([String][1] \| [Object][2])** parsed by the [color][3] module to extract chroma values.
- Throws **[Error][4]** Invalid parameter
Returns **Sharp**
## greyscale
Convert to 8-bit greyscale; 256 shades of grey.
This is a linear operation. If the input image is in a non-linear colour space such as sRGB, use `gamma()` with `greyscale()` for the best results.
@@ -27,45 +41,57 @@ This may be overridden by other sharp operations such as `toColourspace('b-w')`,
which will produce an output image containing one color channel.
An alpha channel may be present, and will be unchanged by the operation.
**Parameters**
### Parameters
- `greyscale` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `greyscale` **[Boolean][5]** (optional, default `true`)
Returns **Sharp**
# grayscale
## grayscale
Alternative spelling of `greyscale`.
**Parameters**
### Parameters
- `grayscale` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `grayscale` **[Boolean][5]** (optional, default `true`)
Returns **Sharp**
# toColourspace
## toColourspace
Set the output colourspace.
By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
**Parameters**
### Parameters
- `colourspace` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
- `colourspace` **[String][1]?** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...][6]
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][4]** Invalid parameters
Returns **Sharp**
# toColorspace
## toColorspace
Alternative spelling of `toColourspace`.
**Parameters**
### Parameters
- `colorspace` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** output colorspace.
- `colorspace` **[String][1]?** output colorspace.
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][4]** Invalid parameters
Returns **Sharp**
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[3]: https://www.npmjs.org/package/color
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[6]: https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568

View File

@@ -1,27 +1,35 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# overlayWith
## overlayWith
Overlay (composite) an image over the processed (resized, extracted etc.) image.
The overlay image must be the same size or smaller than the processed image.
If both `top` and `left` options are provided, they take precedence over `gravity`.
**Parameters**
If the overlay image contains an alpha channel then composition with premultiplication will occur.
- `overlay` **([Buffer](https://nodejs.org/api/buffer.html) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** Buffer containing image data or String containing the path to an image file.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `options.gravity` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** gravity at which to place the overlay. (optional, default `'centre'`)
- `options.top` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the pixel offset from the top edge.
- `options.left` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the pixel offset from the left edge.
- `options.tile` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** set to true to repeat the overlay image across the entire image with the given `gravity`. (optional, default `false`)
- `options.cutout` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another. (optional, default `false`)
- `options.raw` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** describes overlay when using raw pixel data.
- `options.raw.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `options.raw.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `options.raw.channels` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
### Parameters
**Examples**
- `overlay` **([Buffer][1] \| [String][2])** Buffer containing image data or String containing the path to an image file.
- `options` **[Object][3]?**
- `options.gravity` **[String][2]** gravity at which to place the overlay. (optional, default `'centre'`)
- `options.top` **[Number][4]?** the pixel offset from the top edge.
- `options.left` **[Number][4]?** the pixel offset from the left edge.
- `options.tile` **[Boolean][5]** set to true to repeat the overlay image across the entire image with the given `gravity`. (optional, default `false`)
- `options.cutout` **[Boolean][5]** set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another. (optional, default `false`)
- `options.density` **[Number][4]** number representing the DPI for vector overlay image. (optional, default `72`)
- `options.raw` **[Object][3]?** describes overlay when using raw pixel data.
- `options.raw.width` **[Number][4]?**
- `options.raw.height` **[Number][4]?**
- `options.raw.channels` **[Number][4]?**
- `options.create` **[Object][3]?** describes a blank overlay to be created.
- `options.create.width` **[Number][4]?**
- `options.create.height` **[Number][4]?**
- `options.create.channels` **[Number][4]?** 3-4
- `options.create.background` **([String][2] \| [Object][3])?** parsed by the [color][6] module to extract values for red, green, blue and alpha.
### Examples
```javascript
sharp('input.png')
@@ -32,8 +40,7 @@ sharp('input.png')
.overlayWith('overlay.png', { gravity: sharp.gravity.southeast } )
.sharpen()
.withMetadata()
.quality(90)
.webp()
.webp( { quality: 90 } )
.toBuffer()
.then(function(outputBuffer) {
// outputBuffer contains upside down, 300px wide, alpha channel flattened
@@ -42,6 +49,20 @@ sharp('input.png')
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][7]** Invalid parameters
Returns **Sharp**
[1]: https://nodejs.org/api/buffer.html
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[6]: https://www.npmjs.org/package/color
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error

View File

@@ -1,21 +1,30 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# Sharp
## Sharp
**Parameters**
### Parameters
- `input` **([Buffer](https://nodejs.org/api/buffer.html) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))?** if present, can be
- `input` **([Buffer][1] \| [String][2])?** if present, can be
a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
a String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when null or undefined.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** if present, is an Object with optional attributes.
- `options.density` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** integral number representing the DPI for vector images. (optional, default `72`)
- `options.raw` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** describes raw pixel image data. See `raw()` for pixel ordering.
- `options.raw.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `options.raw.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `options.raw.channels` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
- `options` **[Object][3]?** if present, is an Object with optional attributes.
- `options.failOnError` **[Boolean][4]** by default apply a "best effort"
to decode images, even if the data is corrupt or invalid. Set this flag to true
if you'd rather halt processing and raise an error when loading invalid images. (optional, default `false`)
- `options.density` **[Number][5]** number representing the DPI for vector images. (optional, default `72`)
- `options.page` **[Number][5]** page number to extract for multi-page input (GIF, TIFF) (optional, default `0`)
- `options.raw` **[Object][3]?** describes raw pixel input image data. See `raw()` for pixel ordering.
- `options.raw.width` **[Number][5]?**
- `options.raw.height` **[Number][5]?**
- `options.raw.channels` **[Number][5]?** 1-4
- `options.create` **[Object][3]?** describes a new image to be created.
- `options.create.width` **[Number][5]?**
- `options.create.height` **[Number][5]?**
- `options.create.channels` **[Number][5]?** 3-4
- `options.create.background` **([String][2] \| [Object][3])?** parsed by the [color][6] module to extract values for red, green, blue and alpha.
**Examples**
### Examples
```javascript
sharp('input.jpg')
@@ -39,43 +48,74 @@ var transformer = sharp()
readableStream.pipe(transformer).pipe(writableStream);
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
```javascript
// Create a blank 300x200 PNG image of semi-transluent red pixels
sharp({
create: {
width: 300,
height: 200,
channels: 4,
background: { r: 255, g: 0, b: 0, alpha: 0.5 }
}
})
.png()
.toBuffer()
.then( ... );
```
Returns **[Sharp](#sharp)**
- Throws **[Error][7]** Invalid parameters
## format
Returns **[Sharp][8]**
### format
An Object containing nested boolean values representing the available input and output formats/methods.
**Examples**
#### Examples
```javascript
console.log(sharp.format());
console.log(sharp.format);
```
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
Returns **[Object][3]**
## versions
### versions
An Object containing the version numbers of libvips and its dependencies.
**Examples**
#### Examples
```javascript
console.log(sharp.versions);
```
# queue
## queue
An EventEmitter that emits a `change` event when a task is either:
- queued, waiting for _libuv_ to provide a worker thread
- complete
**Examples**
### Examples
```javascript
sharp.queue.on('change', function(queueLength) {
console.log('Queue contains ' + queueLength + ' task(s)');
});
```
[1]: https://nodejs.org/api/buffer.html
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[6]: https://www.npmjs.org/package/color
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[8]: #sharp

View File

@@ -1,12 +1,12 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# clone
## clone
Take a "snapshot" of the Sharp instance, returning a new instance.
Cloned instances inherit the input of their parent instance.
This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
**Examples**
### Examples
```javascript
const pipeline = sharp().rotate();
@@ -19,28 +19,31 @@ readableStream.pipe(pipeline);
Returns **Sharp**
# metadata
## metadata
Fast access to image metadata without decoding any compressed image data.
Fast access to (uncached) image metadata without decoding any compressed image data.
A Promises/A+ promise is returned when `callback` is not provided.
- `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
- `width`: Number of pixels wide
- `height`: Number of pixels high
- `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
- `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
- `height`: Number of pixels high (EXIF orientation is not taken into consideration)
- `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...][1]
- `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
- `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...][2]
- `density`: Number of pixels per inch (DPI), if present
- `hasProfile`: Boolean indicating the presence of an embedded ICC profile
- `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
- `orientation`: Number value of the EXIF Orientation header, if present
- `exif`: Buffer containing raw EXIF data, if present
- `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
- `icc`: Buffer containing raw [ICC][3] profile data, if present
- `iptc`: Buffer containing raw IPTC data, if present
- `xmp`: Buffer containing raw XMP data, if present
**Parameters**
### Parameters
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)?** called with the arguments `(err, metadata)`
- `callback` **[Function][4]?** called with the arguments `(err, metadata)`
**Examples**
### Examples
```javascript
const image = sharp(inputJpg);
@@ -57,30 +60,86 @@ image
});
```
Returns **([Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> | Sharp)**
Returns **([Promise][5]&lt;[Object][6]> | Sharp)**
# limitInputPixels
## stats
Access to pixel-derived image statistics for every channel in the image.
A Promise is returned when `callback` is not provided.
- `channels`: Array of channel statistics for each channel in the image. Each channel statistic contains
- `min` (minimum value in the channel)
- `max` (maximum value in the channel)
- `sum` (sum of all values in a channel)
- `squaresSum` (sum of squared values in a channel)
- `mean` (mean of the values in a channel)
- `stdev` (standard deviation for the values in a channel)
- `minX` (x-coordinate of one of the pixel where the minimum lies)
- `minY` (y-coordinate of one of the pixel where the minimum lies)
- `maxX` (x-coordinate of one of the pixel where the maximum lies)
- `maxY` (y-coordinate of one of the pixel where the maximum lies)
- `isOpaque`: Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel
- `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
### Parameters
- `callback` **[Function][4]?** called with the arguments `(err, stats)`
### Examples
```javascript
const image = sharp(inputJpg);
image
.stats()
.then(function(stats) {
// stats contains the channel-wise statistics array and the isOpaque value
});
```
Returns **[Promise][5]&lt;[Object][6]>**
## limitInputPixels
Do not process input images where the number of pixels (width _ height) exceeds this limit.
Assumes image dimensions contained in the input metadata can be trusted.
The default limit is 268402689 (0x3FFF _ 0x3FFF) pixels.
**Parameters**
### Parameters
- `limit` **([Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** an integral Number of pixels, zero or false to remove limit, true to use default limit.
- `limit` **([Number][7] \| [Boolean][8])** an integral Number of pixels, zero or false to remove limit, true to use default limit.
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid limit
- Throws **[Error][9]** Invalid limit
Returns **Sharp**
# sequentialRead
## sequentialRead
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
This will reduce memory usage and can improve performance on some systems.
**Parameters**
The default behaviour _before_ function call is `false`, meaning the libvips access method is not sequential.
- `sequentialRead` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
### Parameters
- `sequentialRead` **[Boolean][8]** (optional, default `true`)
Returns **Sharp**
[1]: https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636
[2]: https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672
[3]: https://www.npmjs.com/package/icc
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error

View File

@@ -1,11 +1,14 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# rotate
## rotate
Rotate the output image by either an explicit angle
or auto-orient based on the EXIF `Orientation` tag.
Use this method without angle to determine the angle from EXIF data.
If an angle is provided, it is converted to a valid 90/180/270deg rotation.
For example, `-450` will produce a 270deg rotation.
If no angle is provided, it is determined from the EXIF data.
Mirroring is supported and may infer the use of a flip operation.
The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
@@ -13,11 +16,11 @@ The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
Method order is important when both rotating and extracting regions,
for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
**Parameters**
### Parameters
- `angle` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** 0, 90, 180 or 270. (optional, default `auto`)
- `angle` **[Number][1]** angle of rotation, must be a multiple of 90. (optional, default `auto`)
**Examples**
### Examples
```javascript
const pipeline = sharp()
@@ -31,11 +34,11 @@ const pipeline = sharp()
readableStream.pipe(pipeline);
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# extract
## extract
Extract a region of the image.
@@ -43,15 +46,15 @@ Extract a region of the image.
- Use `extract` after `resize` for post-resize extraction.
- Use `extract` before and after for both.
**Parameters**
### Parameters
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `options.left` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** zero-indexed offset from left edge
- `options.top` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** zero-indexed offset from top edge
- `options.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** dimension of extracted image
- `options.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** dimension of extracted image
- `options` **[Object][3]**
- `options.left` **[Number][1]** zero-indexed offset from left edge
- `options.top` **[Number][1]** zero-indexed offset from top edge
- `options.width` **[Number][1]** dimension of extracted image
- `options.height` **[Number][1]** dimension of extracted image
**Examples**
### Examples
```javascript
sharp(input)
@@ -71,118 +74,132 @@ sharp(input)
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# flip
## flip
Flip the image about the vertical Y axis. This always occurs after rotation, if any.
The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
**Parameters**
### Parameters
- `flip` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `flip` **[Boolean][4]** (optional, default `true`)
Returns **Sharp**
# flop
## flop
Flop the image about the horizontal X axis. This always occurs after rotation, if any.
The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
**Parameters**
### Parameters
- `flop` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `flop` **[Boolean][4]** (optional, default `true`)
Returns **Sharp**
# sharpen
## sharpen
Sharpen the image.
When used without parameters, performs a fast, mild sharpen of the output image.
When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space.
Separate control over the level of sharpening in "flat" and "jagged" areas is available.
**Parameters**
### Parameters
- `sigma` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
- `flat` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the level of sharpening to apply to "flat" areas. (optional, default `1.0`)
- `jagged` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the level of sharpening to apply to "jagged" areas. (optional, default `2.0`)
- `sigma` **[Number][1]?** the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
- `flat` **[Number][1]** the level of sharpening to apply to "flat" areas. (optional, default `1.0`)
- `jagged` **[Number][1]** the level of sharpening to apply to "jagged" areas. (optional, default `2.0`)
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# blur
## median
Apply median filter.
When used without parameters the default window is 3x3.
### Parameters
- `size` **[Number][1]** square mask size: size x size (optional, default `3`)
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
## blur
Blur the image.
When used without parameters, performs a fast, mild blur of the output image.
When a `sigma` is provided, performs a slower, more accurate Gaussian blur.
**Parameters**
### Parameters
- `sigma` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
- `sigma` **[Number][1]?** a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# extend
## extend
Extends/pads the edges of the image with the colour provided to the `background` method.
This operation will always occur after resizing and extraction, if any.
**Parameters**
### Parameters
- `extend` **([Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** single pixel count to add to all edges or an Object with per-edge counts
- `extend.top` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `extend.left` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `extend.bottom` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `extend.right` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `extend` **([Number][1] \| [Object][3])** single pixel count to add to all edges or an Object with per-edge counts
- `extend.top` **[Number][1]?**
- `extend.left` **[Number][1]?**
- `extend.bottom` **[Number][1]?**
- `extend.right` **[Number][1]?**
**Examples**
### Examples
```javascript
// Resize to 140 pixels wide, then add 10 transparent pixels
// to the top, left and right edges and 20 to the bottom edge
sharp(input)
.resize(140)
.background({r: 0, g: 0, b: 0, a: 0})
.background({r: 0, g: 0, b: 0, alpha: 0})
.extend({top: 10, bottom: 20, left: 10, right: 10})
...
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# flatten
## flatten
Merge alpha transparency channel, if any, with `background`.
**Parameters**
### Parameters
- `flatten` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `flatten` **[Boolean][4]** (optional, default `true`)
Returns **Sharp**
# trim
## trim
Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
**Parameters**
### Parameters
- `tolerance` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** value between 1 and 99 representing the percentage similarity. (optional, default `10`)
- `tolerance` **[Number][1]** value between 1 and 99 representing the percentage similarity. (optional, default `10`)
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# gamma
## gamma
Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`
then increasing the encoding (brighten) post-resize at a factor of `gamma`.
@@ -190,59 +207,59 @@ This can improve the perceived brightness of a resized image in non-linear colou
JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation
when applying a gamma correction.
**Parameters**
### Parameters
- `gamma` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** value between 1.0 and 3.0. (optional, default `2.2`)
- `gamma` **[Number][1]** value between 1.0 and 3.0. (optional, default `2.2`)
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# negate
## negate
Produce the "negative" of the image.
**Parameters**
### Parameters
- `negate` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `negate` **[Boolean][4]** (optional, default `true`)
Returns **Sharp**
# normalise
## normalise
Enhance output image contrast by stretching its luminance to cover the full dynamic range.
**Parameters**
### Parameters
- `normalise` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `normalise` **[Boolean][4]** (optional, default `true`)
Returns **Sharp**
# normalize
## normalize
Alternative spelling of normalise.
**Parameters**
### Parameters
- `normalize` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
- `normalize` **[Boolean][4]** (optional, default `true`)
Returns **Sharp**
# convolve
## convolve
Convolve the image with the specified kernel.
**Parameters**
### Parameters
- `kernel` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
- `kernel.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** width of the kernel in pixels.
- `kernel.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** width of the kernel in pixels.
- `kernel.kernel` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)>** Array of length `width*height` containing the kernel values.
- `kernel.scale` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the scale of the kernel in pixels. (optional, default `sum`)
- `kernel.offset` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** the offset of the kernel in pixels. (optional, default `0`)
- `kernel` **[Object][3]**
- `kernel.width` **[Number][1]** width of the kernel in pixels.
- `kernel.height` **[Number][1]** width of the kernel in pixels.
- `kernel.kernel` **[Array][5]&lt;[Number][1]>** Array of length `width*height` containing the kernel values.
- `kernel.scale` **[Number][1]** the scale of the kernel in pixels. (optional, default `sum`)
- `kernel.offset` **[Number][1]** the offset of the kernel in pixels. (optional, default `0`)
**Examples**
### Examples
```javascript
sharp(input)
@@ -258,44 +275,72 @@ sharp(input)
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# threshold
## threshold
Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
**Parameters**
### Parameters
- `threshold` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** a value in the range 0-255 representing the level at which the threshold will be applied. (optional, default `128`)
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `options.greyscale` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** convert to single channel greyscale. (optional, default `true`)
- `options.grayscale` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** alternative spelling for greyscale. (optional, default `true`)
- `threshold` **[Number][1]** a value in the range 0-255 representing the level at which the threshold will be applied. (optional, default `128`)
- `options` **[Object][3]?**
- `options.greyscale` **[Boolean][4]** convert to single channel greyscale. (optional, default `true`)
- `options.grayscale` **[Boolean][4]** alternative spelling for greyscale. (optional, default `true`)
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
# boolean
## boolean
Perform a bitwise boolean operation with operand image.
This operation creates an output image where each pixel is the result of
the selected bitwise boolean `operation` between the corresponding pixels of the input images.
**Parameters**
### Parameters
- `operand` **([Buffer](https://nodejs.org/api/buffer.html) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** Buffer containing image data or String containing the path to an image file.
- `operator` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `options.raw` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** describes operand when using raw pixel data.
- `options.raw.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `options.raw.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `options.raw.channels` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `operand` **([Buffer][6] \| [String][7])** Buffer containing image data or String containing the path to an image file.
- `operator` **[String][7]** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
- `options` **[Object][3]?**
- `options.raw` **[Object][3]?** describes operand when using raw pixel data.
- `options.raw.width` **[Number][1]?**
- `options.raw.height` **[Number][1]?**
- `options.raw.channels` **[Number][1]?**
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
## linear
Apply the linear formula a \* input + b to the image (levels adjustment)
### Parameters
- `a` **[Number][1]** multiplier (optional, default `1.0`)
- `b` **[Number][1]** offset (optional, default `0.0`)
- Throws **[Error][2]** Invalid parameters
Returns **Sharp**
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
[6]: https://nodejs.org/api/buffer.html
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String

View File

@@ -1,6 +1,6 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# toFile
## toFile
Write output image data to a file.
@@ -8,157 +8,281 @@ If an explicit output format is not selected, it will be inferred from the exten
with JPEG, PNG, WebP, TIFF, DZI, and libvips' V format supported.
Note that raw pixel data is only supported for buffer output.
A Promises/A+ promise is returned when `callback` is not provided.
A `Promise` is returned when `callback` is not provided.
**Parameters**
### Parameters
- `fileOut` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the path to write the image data to.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)?** called on completion with two arguments `(err, info)`.
`info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
- `fileOut` **[String][1]** the path to write the image data to.
- `callback` **[Function][2]?** called on completion with two arguments `(err, info)`.
`info` contains the output image `format`, `size` (bytes), `width`, `height`,
`channels` and `premultiplied` (indicating if premultiplication was used).
When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
### Examples
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
```javascript
sharp(input)
.toFile('output.png', (err, info) => { ... });
```
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>** when no callback is provided
```javascript
sharp(input)
.toFile('output.png')
.then(info => { ... })
.catch(err => { ... });
```
# toBuffer
- Throws **[Error][3]** Invalid parameters
Returns **[Promise][4]&lt;[Object][5]>** when no callback is provided
## toBuffer
Write output to a Buffer.
JPEG, PNG, WebP, and RAW output are supported.
JPEG, PNG, WebP, TIFF and RAW output are supported.
By default, the format will match the input image, except GIF and SVG input which become PNG output.
`callback`, if present, gets three arguments `(err, buffer, info)` where:
`callback`, if present, gets three arguments `(err, data, info)` where:
- `err` is an error message, if any.
- `buffer` is the output image data.
- `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
A Promises/A+ promise is returned when `callback` is not provided.
- `err` is an error, if any.
- `data` is the output image data.
- `info` contains the output image `format`, `size` (bytes), `width`, `height`,
`channels` and `premultiplied` (indicating if premultiplication was used).
When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
**Parameters**
A `Promise` is returned when `callback` is not provided.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)?**
### Parameters
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Buffer](https://nodejs.org/api/buffer.html)>** when no callback is provided
- `options` **[Object][5]?**
- `options.resolveWithObject` **[Boolean][6]?** Resolve the Promise with an Object containing `data` and `info` properties instead of resolving only with `data`.
- `callback` **[Function][2]?**
# withMetadata
### Examples
```javascript
sharp(input)
.toBuffer((err, data, info) => { ... });
```
```javascript
sharp(input)
.toBuffer()
.then(data => { ... })
.catch(err => { ... });
```
```javascript
sharp(input)
.toBuffer({ resolveWithObject: true })
.then(({ data, info }) => { ... })
.catch(err => { ... });
```
Returns **[Promise][4]&lt;[Buffer][7]>** when no callback is provided
## withMetadata
Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
The default behaviour, when `withMetadata` is not used, is to strip all metadata and convert to the device-independent sRGB colour space.
This will also convert to and add a web-friendly sRGB ICC profile.
**Parameters**
### Parameters
- `withMetadata` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `withMetadata.orientation` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** value between 1 and 8, used to update the EXIF `Orientation` tag.
- `withMetadata` **[Object][5]?**
- `withMetadata.orientation` **[Number][8]?** value between 1 and 8, used to update the EXIF `Orientation` tag.
### Examples
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
```javascript
sharp('input.jpg')
.withMetadata()
.toFile('output-with-metadata.jpg')
.then(info => { ... });
```
- Throws **[Error][3]** Invalid parameters
Returns **Sharp**
# jpeg
## jpeg
Use these JPEG options for output image.
**Parameters**
### Parameters
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** output options
- `options.quality` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** quality, integer 1-100 (optional, default `80`)
- `options.progressive` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** use progressive (interlace) scan (optional, default `false`)
- `options.chromaSubsampling` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** set to '4:4:4' to prevent chroma subsampling when quality &lt;= 90 (optional, default `'4:2:0'`)
- `options.trellisQuantisation` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** apply trellis quantisation, requires mozjpeg (optional, default `false`)
- `options.overshootDeringing` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** apply overshoot deringing, requires mozjpeg (optional, default `false`)
- `options.optimiseScans` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** optimise progressive scans, forces progressive, requires mozjpeg (optional, default `false`)
- `options.optimizeScans` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** alternative spelling of optimiseScans (optional, default `false`)
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** force JPEG output, otherwise attempt to use input format (optional, default `true`)
- `options` **[Object][5]?** output options
- `options.quality` **[Number][8]** quality, integer 1-100 (optional, default `80`)
- `options.progressive` **[Boolean][6]** use progressive (interlace) scan (optional, default `false`)
- `options.chromaSubsampling` **[String][1]** set to '4:4:4' to prevent chroma subsampling when quality &lt;= 90 (optional, default `'4:2:0'`)
- `options.trellisQuantisation` **[Boolean][6]** apply trellis quantisation, requires mozjpeg (optional, default `false`)
- `options.overshootDeringing` **[Boolean][6]** apply overshoot deringing, requires mozjpeg (optional, default `false`)
- `options.optimiseScans` **[Boolean][6]** optimise progressive scans, forces progressive, requires mozjpeg (optional, default `false`)
- `options.optimizeScans` **[Boolean][6]** alternative spelling of optimiseScans (optional, default `false`)
- `options.optimiseCoding` **[Boolean][6]** optimise Huffman coding tables (optional, default `true`)
- `options.optimizeCoding` **[Boolean][6]** alternative spelling of optimiseCoding (optional, default `true`)
- `options.quantisationTable` **[Number][8]** quantization table to use, integer 0-8, requires mozjpeg (optional, default `0`)
- `options.quantizationTable` **[Number][8]** alternative spelling of quantisationTable (optional, default `0`)
- `options.force` **[Boolean][6]** force JPEG output, otherwise attempt to use input format (optional, default `true`)
### Examples
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
```javascript
// Convert any input to very high quality JPEG output
const data = await sharp(input)
.jpeg({
quality: 100,
chromaSubsampling: '4:4:4'
})
.toBuffer();
```
- Throws **[Error][3]** Invalid options
Returns **Sharp**
# png
## png
Use these PNG options for output image.
**Parameters**
PNG output is always full colour at 8 or 16 bits per pixel.
Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `options.progressive` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** use progressive (interlace) scan (optional, default `false`)
- `options.compressionLevel` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** zlib compression level (optional, default `6`)
- `options.adaptiveFiltering` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** use adaptive row filtering (optional, default `true`)
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** force PNG output, otherwise attempt to use input format (optional, default `true`)
### Parameters
- `options` **[Object][5]?**
- `options.progressive` **[Boolean][6]** use progressive (interlace) scan (optional, default `false`)
- `options.compressionLevel` **[Number][8]** zlib compression level, 0-9 (optional, default `9`)
- `options.adaptiveFiltering` **[Boolean][6]** use adaptive row filtering (optional, default `false`)
- `options.force` **[Boolean][6]** force PNG output, otherwise attempt to use input format (optional, default `true`)
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
### Examples
```javascript
// Convert any input to PNG output
const data = await sharp(input)
.png()
.toBuffer();
```
- Throws **[Error][3]** Invalid options
Returns **Sharp**
# webp
## webp
Use these WebP options for output image.
**Parameters**
### Parameters
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** output options
- `options.quality` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** quality, integer 1-100 (optional, default `80`)
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** force WebP output, otherwise attempt to use input format (optional, default `true`)
- `options` **[Object][5]?** output options
- `options.quality` **[Number][8]** quality, integer 1-100 (optional, default `80`)
- `options.alphaQuality` **[Number][8]** quality of alpha layer, integer 0-100 (optional, default `100`)
- `options.lossless` **[Boolean][6]** use lossless compression mode (optional, default `false`)
- `options.nearLossless` **[Boolean][6]** use near_lossless compression mode (optional, default `false`)
- `options.force` **[Boolean][6]** force WebP output, otherwise attempt to use input format (optional, default `true`)
### Examples
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
```javascript
// Convert any input to lossless WebP output
const data = await sharp(input)
.webp({ lossless: true })
.toBuffer();
```
- Throws **[Error][3]** Invalid options
Returns **Sharp**
# tiff
## tiff
Use these TIFF options for output image.
**Parameters**
### Parameters
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** output options
- `options.quality` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** quality, integer 1-100 (optional, default `80`)
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** force TIFF output, otherwise attempt to use input format (optional, default `true`)
- `options` **[Object][5]?** output options
- `options.quality` **[Number][8]** quality, integer 1-100 (optional, default `80`)
- `options.force` **[Boolean][6]** force TIFF output, otherwise attempt to use input format (optional, default `true`)
- `options.compression` **[Boolean][6]** compression options: lzw, deflate, jpeg, ccittfax4 (optional, default `'jpeg'`)
- `options.predictor` **[Boolean][6]** compression predictor options: none, horizontal, float (optional, default `'horizontal'`)
- `options.xres` **[Number][8]** horizontal resolution in pixels/mm (optional, default `1.0`)
- `options.yres` **[Number][8]** vertical resolution in pixels/mm (optional, default `1.0`)
- `options.squash` **[Boolean][6]** squash 8-bit images down to 1 bit (optional, default `false`)
### Examples
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
```javascript
// Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
sharp('input.svg')
.tiff({
compression: 'lzw',
squash: true
})
.toFile('1-bpp-output.tiff')
.then(info => { ... });
```
- Throws **[Error][3]** Invalid options
Returns **Sharp**
# raw
## raw
Force output to be raw, uncompressed uint8 pixel data.
### Examples
```javascript
// Extract raw RGB pixel data from JPEG input
const { data, info } = await sharp('input.jpg')
.raw()
.toBuffer({ resolveWithObject: true });
```
Returns **Sharp**
# toFormat
## toFormat
Force output to a given format.
**Parameters**
### Parameters
- `format` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** as a String or an Object with an 'id' attribute
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** output options
- `format` **([String][1] \| [Object][5])** as a String or an Object with an 'id' attribute
- `options` **[Object][5]** output options
### Examples
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** unsupported format or options
```javascript
// Convert any input to PNG output
const data = await sharp(input)
.toFormat('png')
.toBuffer();
```
- Throws **[Error][3]** unsupported format or options
Returns **Sharp**
# tile
## tile
Use tile-based deep zoom (image pyramid) output.
Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions.
Use a `.zip` or `.szi` file extension with `toFile` to write to a compressed archive file format.
**Parameters**
Warning: multiple sharp instances concurrently producing tile output can expose a possible race condition in some versions of libgsf.
- `tile` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `tile.size` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** tile size in pixels, a value between 1 and 8192. (optional, default `256`)
- `tile.overlap` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** tile overlap in pixels, a value between 0 and 8192. (optional, default `0`)
- `tile.container` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** tile container, with value `fs` (filesystem) or `zip` (compressed file). (optional, default `'fs'`)
- `tile.layout` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** filesystem layout, possible values are `dz`, `zoomify` or `google`. (optional, default `'dz'`)
### Parameters
**Examples**
- `tile` **[Object][5]?**
- `tile.size` **[Number][8]** tile size in pixels, a value between 1 and 8192. (optional, default `256`)
- `tile.overlap` **[Number][8]** tile overlap in pixels, a value between 0 and 8192. (optional, default `0`)
- `tile.angle` **[Number][8]** tile angle of rotation, must be a multiple of 90. (optional, default `0`)
- `tile.depth` **[String][1]?** how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
- `tile.container` **[String][1]** tile container, with value `fs` (filesystem) or `zip` (compressed file). (optional, default `'fs'`)
- `tile.layout` **[String][1]** filesystem layout, possible values are `dz`, `zoomify` or `google`. (optional, default `'dz'`)
### Examples
```javascript
sharp('input.tiff')
@@ -172,6 +296,22 @@ sharp('input.tiff')
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][3]** Invalid parameters
Returns **Sharp**
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[7]: https://nodejs.org/api/buffer.html
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number

View File

@@ -1,58 +1,47 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# resize
## resize
Resize image to `width` x `height`.
By default, the resized image is centre cropped to the exact size specified.
Possible reduction kernels are:
Possible kernels are:
- `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
- `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
- `nearest`: Use [nearest neighbour interpolation][1].
- `cubic`: Use a [Catmull-Rom spline][2].
- `lanczos2`: Use a [Lanczos kernel][3] with `a=2`.
- `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
Possible enlargement interpolators are:
### Parameters
- `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
- `bilinear`: Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation), faster than bicubic but with less smooth results.
- `vertexSplitQuadraticBasisSpline`: Use the smoother [VSQBS interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48) to prevent "staircasing" when enlarging.
- `bicubic`: Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default).
- `locallyBoundedBicubic`: Use [LBB interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100), which prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2.
- `nohalo`: Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/), which prevents acutance but typically reduces performance by a factor of 3.
- `width` **[Number][4]?** pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
- `height` **[Number][4]?** pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
- `options` **[Object][5]?**
- `options.kernel` **[String][6]** the kernel to use for image reduction. (optional, default `'lanczos3'`)
- `options.fastShrinkOnLoad` **[Boolean][7]** take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern on some images. (optional, default `true`)
**Parameters**
- `width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** pixels wide the resultant image should be, between 1 and 16383 (0x3FFF). Use `null` or `undefined` to auto-scale the width to match the height.
- `height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** pixels high the resultant image should be, between 1 and 16383. Use `null` or `undefined` to auto-scale the height to match the width.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?**
- `options.kernel` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** the kernel to use for image reduction. (optional, default `'lanczos3'`)
- `options.interpolator` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** the interpolator to use for image enlargement. (optional, default `'bicubic'`)
- `options.centreSampling` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** use \*magick centre sampling convention instead of corner sampling. (optional, default `false`)
- `options.centerSampling` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** alternative spelling of centreSampling. (optional, default `false`)
**Examples**
### Examples
```javascript
sharp(inputBuffer)
.resize(200, 300, {
kernel: sharp.kernel.lanczos2,
interpolator: sharp.interpolator.nohalo
kernel: sharp.kernel.nearest
})
.background('white')
.embed()
.toFile('output.tiff')
.then(function() {
// output.tiff is a 200 pixels wide and 300 pixels high image
// containing a lanczos2/nohalo scaled version, embedded on a white canvas,
// containing a nearest-neighbour scaled version, embedded on a white canvas,
// of the image data in inputBuffer
});
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][8]** Invalid parameters
Returns **Sharp**
# crop
## crop
Crop the resized image to the exact size specified, the default behaviour.
@@ -62,14 +51,14 @@ Possible attributes of the optional `sharp.gravity` are `north`, `northeast`, `e
The experimental strategy-based approach resizes so one dimension is at its target length
then repeatedly ranks edge regions, discarding the edge with the lowest score based on the selected strategy.
- `entropy`: focus on the region with the highest [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_%28information_theory%29).
- `entropy`: focus on the region with the highest [Shannon entropy][9].
- `attention`: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
**Parameters**
### Parameters
- `crop` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** A member of `sharp.gravity` to crop to an edge/corner or `sharp.strategy` to crop dynamically. (optional, default `'centre'`)
- `crop` **[String][6]** A member of `sharp.gravity` to crop to an edge/corner or `sharp.strategy` to crop dynamically. (optional, default `'centre'`)
**Examples**
### Examples
```javascript
const transformer = sharp()
@@ -83,11 +72,11 @@ const transformer = sharp()
readableStream.pipe(transformer).pipe(writableStream);
```
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
- Throws **[Error][8]** Invalid parameters
Returns **Sharp**
# embed
## embed
Preserving aspect ratio, resize the image to the maximum `width` or `height` specified
then embed on a background of the exact `width` and `height` specified.
@@ -95,12 +84,16 @@ then embed on a background of the exact `width` and `height` specified.
If the background contains an alpha value then WebP and PNG format output images will
contain an alpha channel, even when the input image does not.
**Examples**
### Parameters
- `embed` **[String][6]** A member of `sharp.gravity` to embed to an edge/corner. (optional, default `'centre'`)
### Examples
```javascript
sharp('input.gif')
.resize(200, 300)
.background({r: 0, g: 0, b: 0, a: 0})
.background({r: 0, g: 0, b: 0, alpha: 0})
.embed()
.toFormat(sharp.format.webp)
.toBuffer(function(err, outputBuffer) {
@@ -112,16 +105,18 @@ sharp('input.gif')
});
```
- Throws **[Error][8]** Invalid parameters
Returns **Sharp**
# max
## max
Preserving aspect ratio, resize the image to be as large as possible
while ensuring its dimensions are less than or equal to the `width` and `height` specified.
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
**Examples**
### Examples
```javascript
sharp(inputBuffer)
@@ -137,7 +132,7 @@ sharp(inputBuffer)
Returns **Sharp**
# min
## min
Preserving aspect ratio, resize the image to be as small as possible
while ensuring its dimensions are greater than or equal to the `width` and `height` specified.
@@ -146,21 +141,42 @@ Both `width` and `height` must be provided via `resize` otherwise the behaviour
Returns **Sharp**
# ignoreAspectRatio
## ignoreAspectRatio
Ignoring the aspect ratio of the input, stretch the image to
the exact `width` and/or `height` provided via `resize`.
Returns **Sharp**
# withoutEnlargement
## withoutEnlargement
Do not enlarge the output image if the input image width _or_ height are already less than the required dimensions.
This is equivalent to GraphicsMagick's `>` geometry option:
"_change the dimensions of the image only if its width or height exceeds the geometry specification_".
Use with `max()` to preserve the image's aspect ratio.
**Parameters**
The default behaviour _before_ function call is `false`, meaning the image will be enlarged.
- `withoutEnlargement` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `true`)
### Parameters
- `withoutEnlargement` **[Boolean][7]** (optional, default `true`)
Returns **Sharp**
[1]: http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation
[2]: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
[3]: https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel
[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[9]: https://en.wikipedia.org/wiki/Entropy_%28information_theory%29

View File

@@ -1,20 +1,20 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# cache
## cache
Gets, or when options are provided sets, the limits of _libvips'_ operation cache.
Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
Existing entries in the cache will be trimmed after any change in limits.
This method always returns cache statistics,
useful for determining how much working memory is required for a particular task.
**Parameters**
### Parameters
- `options` **([Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching.
- `options.memory` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** is the maximum memory in MB to use for this cache (optional, default `50`)
- `options.files` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** is the maximum number of files to hold open (optional, default `20`)
- `options.items` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** is the maximum number of operations to cache (optional, default `100`)
- `options` **([Object][1] \| [Boolean][2])** Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching (optional, default `true`)
- `options.memory` **[Number][3]** is the maximum memory in MB to use for this cache (optional, default `50`)
- `options.files` **[Number][3]** is the maximum number of files to hold open (optional, default `20`)
- `options.items` **[Number][3]** is the maximum number of operations to cache (optional, default `100`)
**Examples**
### Examples
```javascript
const stats = sharp.cache();
@@ -26,11 +26,11 @@ sharp.cache( { files: 0 } );
sharp.cache(false);
```
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
Returns **[Object][1]**
# concurrency
## concurrency
Gets, or when a concurrency is provided sets,
Gets or, when a concurrency is provided, sets
the number of threads _libvips'_ should create to process each image.
The default value is the number of CPU cores.
A value of `0` will reset to this default.
@@ -40,11 +40,11 @@ is limited by libuv's `UV_THREADPOOL_SIZE` environment variable.
This method always returns the current concurrency.
**Parameters**
### Parameters
- `concurrency` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?**
- `concurrency` **[Number][3]?**
**Examples**
### Examples
```javascript
const threads = sharp.concurrency(); // 4
@@ -52,24 +52,24 @@ sharp.concurrency(2); // 2
sharp.concurrency(0); // 4
```
Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** concurrency
Returns **[Number][3]** concurrency
# counters
## counters
Provides access to internal task counters.
- queue is the number of tasks this module has queued waiting for _libuv_ to provide a worker thread from its pool.
- process is the number of resize tasks currently being processed.
**Examples**
### Examples
```javascript
const counters = sharp.counters(); // { queue: 2, process: 4 }
```
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
Returns **[Object][1]**
# simd
## simd
Get and set use of SIMD vector unit instructions.
Requires libvips to have been compiled with liborc support.
@@ -80,11 +80,11 @@ by taking advantage of the SIMD vector unit of the CPU, e.g. Intel SSE and ARM N
This feature is currently off by default but future versions may reverse this.
Versions of liborc prior to 0.4.25 are known to segfault under heavy load.
**Parameters**
### Parameters
- `simd` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** (optional, default `false`)
- `simd` **[Boolean][2]** (optional, default `false`)
**Examples**
### Examples
```javascript
const simd = sharp.simd();
@@ -96,4 +96,10 @@ const simd = sharp.simd(true);
// attempts to enable the use of SIMD, returning true if available
```
Returns **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
Returns **[Boolean][2]**
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number

View File

@@ -1,9 +1,321 @@
# Changelog
### v0.20 - "*prebuild*"
Requires libvips v8.6.1.
#### v0.20.8 - 5<sup>th</sup> September 2018
* Avoid race conditions when creating directories during installation.
[#1358](https://github.com/lovell/sharp/pull/1358)
[@ajhool](https://github.com/ajhool)
* Accept floating point values for input density parameter.
[#1362](https://github.com/lovell/sharp/pull/1362)
[@aeirola](https://github.com/aeirola)
#### v0.20.7 - 21<sup>st</sup> August 2018
* Use copy+unlink if rename operation fails during installation.
[#1345](https://github.com/lovell/sharp/issues/1345)
#### v0.20.6 - 20<sup>th</sup> August 2018
* Add removeAlpha operation to remove alpha channel, if any.
[#1248](https://github.com/lovell/sharp/issues/1248)
* Expose mozjpeg quant_table flag.
[#1285](https://github.com/lovell/sharp/pull/1285)
[@rexxars](https://github.com/rexxars)
* Allow full WebP alphaQuality range of 0-100.
[#1290](https://github.com/lovell/sharp/pull/1290)
[@sylvaindumont](https://github.com/sylvaindumont)
* Cache libvips binaries to reduce re-install time.
[#1301](https://github.com/lovell/sharp/issues/1301)
* Ensure vendor platform mismatch throws error at install time.
[#1303](https://github.com/lovell/sharp/issues/1303)
* Improve install time error messages for FreeBSD users.
[#1310](https://github.com/lovell/sharp/issues/1310)
* Ensure extractChannel works with 16-bit images.
[#1330](https://github.com/lovell/sharp/issues/1330)
* Expose depth option for tile-based output.
[#1342](https://github.com/lovell/sharp/pull/1342)
[@alundavies](https://github.com/alundavies)
* Add experimental entropy field to stats response.
#### v0.20.5 - 27<sup>th</sup> June 2018
* Expose libjpeg optimize_coding flag.
[#1265](https://github.com/lovell/sharp/pull/1265)
[@tomlokhorst](https://github.com/tomlokhorst)
#### v0.20.4 - 20<sup>th</sup> June 2018
* Prevent possible rounding error when using shrink-on-load and 90/270 degree rotation.
[#1241](https://github.com/lovell/sharp/issues/1241)
[@anahit42](https://github.com/anahit42)
* Ensure extractChannel sets correct single-channel colour space interpretation.
[#1257](https://github.com/lovell/sharp/issues/1257)
[@jeremychone](https://github.com/jeremychone)
#### v0.20.3 - 29<sup>th</sup> May 2018
* Fix tint operation by ensuring LAB interpretation and allowing negative values.
[#1235](https://github.com/lovell/sharp/issues/1235)
[@wezside](https://github.com/wezside)
#### v0.20.2 - 28<sup>th</sup> April 2018
* Add tint operation to set image chroma.
[#825](https://github.com/lovell/sharp/pull/825)
[@rikh42](https://github.com/rikh42)
* Add environment variable to ignore globally-installed libvips.
[#1165](https://github.com/lovell/sharp/pull/1165)
[@oncletom](https://github.com/oncletom)
* Add support for page selection with multi-page input (GIF/TIFF).
[#1204](https://github.com/lovell/sharp/pull/1204)
[@woolite64](https://github.com/woolite64)
* Add support for Group4 (CCITTFAX4) compression with TIFF output.
[#1208](https://github.com/lovell/sharp/pull/1208)
[@woolite64](https://github.com/woolite64)
#### v0.20.1 - 17<sup>th</sup> March 2018
* Improve installation experience when a globally-installed libvips below the minimum required version is found.
[#1148](https://github.com/lovell/sharp/issues/1148)
* Prevent smartcrop error when cumulative rounding is below target size.
[#1154](https://github.com/lovell/sharp/issues/1154)
[@ralrom](https://github.com/ralrom)
* Expose libvips' median filter operation.
[#1161](https://github.com/lovell/sharp/pull/1161)
[@BiancoA](https://github.com/BiancoA)
#### v0.20.0 - 5<sup>th</sup> March 2018
* Add support for prebuilt sharp binaries on common platforms.
[#186](https://github.com/lovell/sharp/issues/186)
### v0.19 - "*suit*"
Requires libvips v8.6.1.
#### v0.19.1 - 24<sup>th</sup> February 2018
* Expose libvips' linear transform feature.
[#1024](https://github.com/lovell/sharp/pull/1024)
[@3epnm](https://github.com/3epnm)
* Expose angle option for tile-based output.
[#1121](https://github.com/lovell/sharp/pull/1121)
[@BiancoA](https://github.com/BiancoA)
* Prevent crop operation when image already at or below target dimensions.
[#1134](https://github.com/lovell/sharp/issues/1134)
[@pieh](https://github.com/pieh)
#### v0.19.0 - 11<sup>th</sup> January 2018
* Expose offset coordinates of strategy-based crop.
[#868](https://github.com/lovell/sharp/issues/868)
[@mirohristov-com](https://github.com/mirohristov-com)
* PNG output now defaults to adaptiveFiltering=false, compressionLevel=9
[#872](https://github.com/lovell/sharp/issues/872)
[@wmertens](https://github.com/wmertens)
* Add stats feature for pixel-derived image statistics.
[#915](https://github.com/lovell/sharp/pull/915)
[@rnanwani](https://github.com/rnanwani)
* Add failOnError option to fail-fast on bad input image data.
[#976](https://github.com/lovell/sharp/pull/976)
[@mceachen](https://github.com/mceachen)
* Resize: switch to libvips' implementation, make fastShrinkOnLoad optional, remove interpolator and centreSampling options.
[#977](https://github.com/lovell/sharp/pull/977)
[@jardakotesovec](https://github.com/jardakotesovec)
* Attach finish event listener to a clone only for Stream-based input.
[#995](https://github.com/lovell/sharp/issues/995)
[@whmountains](https://github.com/whmountains)
* Add tilecache before smartcrop to avoid over-computation of previous operations.
[#1028](https://github.com/lovell/sharp/issues/1028)
[@coffeebite](https://github.com/coffeebite)
* Prevent toFile extension taking precedence over requested format.
[#1037](https://github.com/lovell/sharp/issues/1037)
[@tomgallagher](https://github.com/tomgallagher)
* Add support for gravity option to existing embed feature.
[#1038](https://github.com/lovell/sharp/pull/1038)
[@AzureByte](https://github.com/AzureByte)
* Expose IPTC and XMP metadata when available.
[#1079](https://github.com/lovell/sharp/pull/1079)
[@oaleynik](https://github.com/oaleynik)
* TIFF output: switch default predictor from 'none' to 'horizontal' to match libvips' behaviour.
### v0.18 - "*ridge*"
Requires libvips v8.5.5.
#### v0.18.4 - 18<sup>th</sup> September 2017
* Ensure input Buffer really is marked as Persistent, prevents mark-sweep GC.
[#950](https://github.com/lovell/sharp/issues/950)
[@lfdoherty](https://github.com/lfdoherty)
#### v0.18.3 - 13<sup>th</sup> September 2017
* Skip shrink-on-load when trimming.
[#888](https://github.com/lovell/sharp/pull/888)
[@kleisauke](https://github.com/kleisauke)
* Migrate from got to simple-get for basic auth support.
[#945](https://github.com/lovell/sharp/pull/945)
[@pbomb](https://github.com/pbomb)
#### v0.18.2 - 1<sup>st</sup> July 2017
* Expose libvips' xres and yres properties for TIFF output.
[#828](https://github.com/lovell/sharp/pull/828)
[@YvesBos](https://github.com/YvesBos)
* Ensure flip and flop operations work with auto-rotate.
[#837](https://github.com/lovell/sharp/issues/837)
[@rexxars](https://github.com/rexxars)
* Allow binary download URL override via SHARP_DIST_BASE_URL env variable.
[#841](https://github.com/lovell/sharp/issues/841)
* Add support for Solus Linux.
[#857](https://github.com/lovell/sharp/pull/857)
[@ekremkaraca](https://github.com/ekremkaraca)
#### v0.18.1 - 30<sup>th</sup> May 2017
* Remove regression from #781 that could cause incorrect shrink calculation.
[#831](https://github.com/lovell/sharp/issues/831)
[@suprMax](https://github.com/suprMax)
#### v0.18.0 - 30<sup>th</sup> May 2017
* Remove the previously-deprecated output format "option" functions:
quality, progressive, compressionLevel, withoutAdaptiveFiltering,
withoutChromaSubsampling, trellisQuantisation, trellisQuantization,
overshootDeringing, optimiseScans and optimizeScans.
* Ensure maximum output dimensions are based on the format to be used.
[#176](https://github.com/lovell/sharp/issues/176)
[@stephanebachelier](https://github.com/stephanebachelier)
* Avoid costly (un)premultiply when using overlayWith without alpha channel.
[#573](https://github.com/lovell/sharp/issues/573)
[@strarsis](https://github.com/strarsis)
* Include pixel depth (e.g. "uchar") when reading metadata.
[#577](https://github.com/lovell/sharp/issues/577)
[@moedusa](https://github.com/moedusa)
* Add support for Buffer and Stream-based TIFF output.
[#587](https://github.com/lovell/sharp/issues/587)
[@strarsis](https://github.com/strarsis)
* Expose warnings from libvips via NODE_DEBUG=sharp environment variable.
[#607](https://github.com/lovell/sharp/issues/607)
[@puzrin](https://github.com/puzrin)
* Switch to the libvips implementation of "attention" and "entropy" crop strategies.
[#727](https://github.com/lovell/sharp/issues/727)
* Improve performance and accuracy of nearest neighbour integral upsampling.
[#752](https://github.com/lovell/sharp/issues/752)
[@MrIbby](https://github.com/MrIbby)
* Constructor single argument API: allow plain object, reject null/undefined.
[#768](https://github.com/lovell/sharp/issues/768)
[@kub1x](https://github.com/kub1x)
* Ensure ARM64 pre-built binaries use correct C++11 ABI version.
[#772](https://github.com/lovell/sharp/issues/772)
[@ajiratech2](https://github.com/ajiratech2)
* Prevent aliasing by using dynamic values for shrink(-on-load).
[#781](https://github.com/lovell/sharp/issues/781)
[@kleisauke](https://github.com/kleisauke)
* Expose libvips' "squash" parameter to enable 1-bit TIFF output.
[#783](https://github.com/lovell/sharp/pull/783)
[@YvesBos](https://github.com/YvesBos)
* Add support for rotation using any multiple of +/-90 degrees.
[#791](https://github.com/lovell/sharp/pull/791)
[@ncoden](https://github.com/ncoden)
* Add "jpg" alias to toFormat as shortened form of "jpeg".
[#814](https://github.com/lovell/sharp/pull/814)
[@jingsam](https://github.com/jingsam)
### v0.17 - "*quill*"
Requires libvips v8.4.2.
#### v0.17.3 - 1<sup>st</sup> April 2017
* Allow toBuffer to optionally resolve a Promise with both info and data.
[#143](https://github.com/lovell/sharp/issues/143)
[@salzhrani](https://github.com/salzhrani)
* Create blank image of given width, height, channels and background.
[#470](https://github.com/lovell/sharp/issues/470)
[@pjarts](https://github.com/pjarts)
* Add support for the "nearest" kernel for image reductions.
[#732](https://github.com/lovell/sharp/pull/732)
[@alice0meta](https://github.com/alice0meta)
* Add support for TIFF compression and predictor options.
[#738](https://github.com/lovell/sharp/pull/738)
[@kristojorg](https://github.com/kristojorg)
#### v0.17.2 - 11<sup>th</sup> February 2017
* Ensure Readable side of Stream can start flowing after Writable side has finished.
[#671](https://github.com/lovell/sharp/issues/671)
[@danhaller](https://github.com/danhaller)
* Expose WebP alpha quality, lossless and near-lossless output options.
[#685](https://github.com/lovell/sharp/pull/685)
[@rnanwani](https://github.com/rnanwani)
#### v0.17.1 - 15<sup>th</sup> January 2017
* Improve error messages for invalid parameters.
[@spikeon](https://github.com/spikeon)
[#644](https://github.com/lovell/sharp/pull/644)
* Simplify expression for finding vips-cpp libdir.
[#656](https://github.com/lovell/sharp/pull/656)
* Allow HTTPS-over-HTTP proxy when downloading pre-compiled dependencies.
[@wangzhiwei1888](https://github.com/wangzhiwei1888)
[#679](https://github.com/lovell/sharp/issues/679)
#### v0.17.0 - 11<sup>th</sup> December 2016
* Drop support for versions of Node prior to v4.

5
docs/css/extra.css Normal file
View File

@@ -0,0 +1,5 @@
/* Nest document subheadings in navigation */
ul.subnav ul:not(.subnav) {
padding-left: 2em;
font-size: 80%;
}

View File

@@ -13,8 +13,9 @@ Lanczos resampling ensures quality is not sacrificed for speed.
As well as image resizing, operations such as
rotation, extraction, compositing and gamma correction are available.
OS X, Windows (x64), Linux (x64, ARM) systems do not require
the installation of any external runtime dependencies.
Most 64-bit OS X, Windows and Linux (glibc) systems running
Node versions 4, 6, 8 and 10
do not require any additional install or runtime dependencies.
[![Test Coverage](https://coveralls.io/repos/lovell/sharp/badge.png?branch=master)](https://coveralls.io/r/lovell/sharp?branch=master)
@@ -22,7 +23,7 @@ the installation of any external runtime dependencies.
This module supports reading JPEG, PNG, WebP, TIFF, GIF and SVG images.
Output images can be in JPEG, PNG and WebP formats as well as uncompressed raw pixel data.
Output images can be in JPEG, PNG, WebP and TIFF formats as well as uncompressed raw pixel data.
Streams, Buffer objects and the filesystem can be used for input and output.
@@ -46,7 +47,7 @@ are held in memory and processed at a time,
taking full advantage of multiple CPU cores and L1/L2/L3 cache.
Everything remains non-blocking thanks to _libuv_,
no child processes are spawned and Promises/A+ are supported.
no child processes are spawned and Promises/async/await are supported.
### Optimal
@@ -55,9 +56,9 @@ without having to use separate command line tools like
[jpegoptim](https://github.com/tjko/jpegoptim) and
[jpegtran](http://jpegclub.org/jpegtran/).
PNG filtering can be disabled,
PNG filtering is disabled by default,
which for diagrams and line art often produces the same result
as [pngcrush](http://pmt.sourceforge.net/pngcrush/).
as [pngcrush](https://pmt.sourceforge.io/pngcrush/).
### Contributing
@@ -94,12 +95,35 @@ the help and code contributions of the following people:
* [Kleis Auke Wolthuizen](https://github.com/kleisauke)
* [Matt Hirsch](https://github.com/mhirsch)
* [Rahul Nanwani](https://github.com/rnanwani)
* [Matthias Thoemmes](https://github.com/cmtt)
* [Patrick Paskaris](https://github.com/ppaskaris)
* [Jérémy Lal](https://github.com/kapouer)
* [Alice Monday](https://github.com/alice0meta)
* [Kristo Jorgenson](https://github.com/kristojorg)
* [Yves Bos](https://github.com/YvesBos)
* [Nicolas Coden](https://github.com/ncoden)
* [Matt Parrish](https://github.com/pbomb)
* [Matthew McEachen](https://github.com/mceachen)
* [Jarda Kotěšovec](https://github.com/jardakotesovec)
* [Kenric D'Souza](https://github.com/AzureByte)
* [Oleh Aleinyk](https://github.com/oaleynik)
* [Marcel Bretschneider](https://github.com/3epnm)
* [Andrea Bianco](https://github.com/BiancoA)
* [Rik Heywood](https://github.com/rikh42)
* [Thomas Parisot](https://github.com/oncletom)
* [Nathan Graves](https://github.com/woolite64)
* [Tom Lokhorst](https://github.com/tomlokhorst)
* [Espen Hovlandsdal](https://github.com/rexxars)
* [Sylvain Dumont](https://github.com/sylvaindumont)
* [Alun Davies](https://github.com/alundavies)
* [Aidan Hoolachan](https://github.com/ajhool)
* [Axel Eirola](https://github.com/aeirola)
Thank you!
### Licence
Copyright 2013, 2014, 2015, 2016 Lovell Fuller and contributors.
Copyright 2013, 2014, 2015, 2016, 2017, 2018 Lovell Fuller and contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -8,36 +8,53 @@ npm install sharp
yarn add sharp
```
### Prerequisites
## Prerequisites
* Node v4.5.0+
### Building from source
Pre-compiled binaries for sharp are provided for use with
Node versions 4, 6, 8 and 10 on
64-bit Windows, OS X and Linux platforms.
Sharp will be built from source at install time when:
* a globally-installed libvips is detected,
* pre-compiled binaries do not exist for the current platform and Node version, or
* when the `npm install --build-from-source` flag is used.
Building from source requires:
* Node v4+
* C++11 compatible compiler such as gcc 4.8+, clang 3.0+ or MSVC 2013+
* [node-gyp](https://github.com/TooTallNate/node-gyp#installation) and its dependencies
* [node-gyp](https://github.com/TooTallNate/node-gyp#installation) and its dependencies (includes Python)
## libvips
### Linux
[![Ubuntu 14.04 Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp)
[![Linux Build Status](https://circleci.com/gh/lovell/sharp.svg?style=svg&circle-token=6cb6d1d287a51af83722b19ed8885377fbc85e5c)](https://circleci.com/gh/lovell/sharp)
[![Ubuntu 16.04 Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp)
libvips and its dependencies are fetched and stored within `node_modules/sharp/vendor` during `npm install`.
This involves an automated HTTPS download of approximately 6.5MB.
This involves an automated HTTPS download of approximately 7MB.
Most recent Linux-based operating systems with glibc running on x64 and ARMv6+ CPUs should "just work", e.g.:
* Debian 7, 8
* Ubuntu 12.04, 14.04, 16.04
* Centos 7
* Fedora 23, 24
* openSUSE 13.2
* Debian 7+
* Ubuntu 14.04+
* Centos 7+
* Fedora
* openSUSE 13.2+
* Archlinux
* Raspbian Jessie
* Amazon Linux 2016.03, 2016.09
* Amazon Linux
* Solus
To use a globally-installed version of libvips instead of the provided binaries,
make sure it is at least the version listed under `config.libvips` in the `package.json` file
and that it can be located using `pkg-config --modversion vips-cpp`.
If you are using non-stadard paths (anything other than `/usr` or `/usr/local`),
If you are using non-standard paths (anything other than `/usr` or `/usr/local`),
you might need to set `PKG_CONFIG_PATH` during `npm install`
and `LD_LIBRARY_PATH` at runtime.
@@ -46,18 +63,27 @@ This allows the use of newer versions of libvips with older versions of sharp.
For 32-bit Intel CPUs and older Linux-based operating systems such as Centos 6,
it is recommended to install a system-wide installation of libvips from source:
https://github.com/jcupitt/libvips#building-libvips-from-a-source-tarball
https://jcupitt.github.io/libvips/install.html#building-libvips-from-a-source-tarball
For Linux-based operating systems such as Alpine that use musl libc,
the smaller stack size means libvips' cache should be disabled
#### Alpine Linux
libvips is available in the
[testing repository](https://pkgs.alpinelinux.org/packages?name=vips-dev):
```sh
apk add vips-dev fftw-dev --update-cache --repository https://dl-3.alpinelinux.org/alpine/edge/testing/
```
The smaller stack size of musl libc means
libvips may need to be used without a cache
via `sharp.cache(false)` to avoid a stack overflow.
### Mac OS
[![OS X 10.9.5 Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp)
[![OS X 10.12 Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp)
libvips and its dependencies are fetched and stored within `node_modules/sharp/vendor` during `npm install`.
This involves an automated HTTPS download of approximately 6.3MB.
This involves an automated HTTPS download of approximately 7MB.
To use your own version of libvips instead of the provided binaries, make sure it is
at least the version listed under `config.libvips` in the `package.json` file and
@@ -68,24 +94,34 @@ that it can be located using `pkg-config --modversion vips-cpp`.
[![Windows x64 Build Status](https://ci.appveyor.com/api/projects/status/pgtul704nkhhg6sg)](https://ci.appveyor.com/project/lovell/sharp)
libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`.
This involves an automated HTTPS download of approximately 9MB.
This involves an automated HTTPS download of approximately 12MB.
Only 64-bit (x64) `node.exe` is supported.
### FreeBSD
libvips must be installed before `npm install` is run.
This can be achieved via [FreshPorts](https://www.freshports.org/graphics/vips/):
This can be achieved via package or ports:
```sh
pkg install -y pkgconf vips
```
```sh
cd /usr/ports/graphics/vips/ && make install clean
```
FreeBSD's gcc v4 and v5 need `CXXFLAGS=-D_GLIBCXX_USE_C99` set for C++11 support due to
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193528
### Heroku
[Alessandro Tagliapietra](https://github.com/alex88) maintains an
[Heroku buildpack for libvips](https://github.com/alex88/heroku-buildpack-vips)
and its dependencies.
libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`.
This involves an automated HTTPS download of approximately 7MB.
Set [NODE_MODULES_CACHE](https://devcenter.heroku.com/articles/nodejs-support#cache-behavior)
to `false` when using the `yarn` package manager.
### Docker
@@ -103,38 +139,53 @@ docker pull marcbachmann/libvips
docker pull wjordan/libvips
```
[Tailor Brands](https://github.com/TailorBrands) maintain
[Debian-based Dockerfiles for libvips and nodejs](https://github.com/TailorBrands/docker-libvips).
```sh
docker pull tailor/docker-libvips
```
### AWS Lambda
In order to use sharp on AWS Lambda, you need to [create a deployment package](http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html). Because sharp
downloads and links libraries for the current platform during `npm install` you have to
do this on a system similar to the [Lambda Execution Environment](http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html). The easiest ways to do this, is to setup a
small t2.micro instance using the AMI ID listed in the previous link, ssh into it as ec2-user
and follow the instructions below.
Install dependencies:
A [deployment package](http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html) for the
[Lambda Execution Environment](http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html)
can be built using Docker.
```sh
curl -s https://rpm.nodesource.com/setup_4.x | sudo bash -
sudo yum install -y gcc-c++ nodejs
rm -rf node_modules/sharp
docker run -v "$PWD":/var/task lambci/lambda:build-nodejs6.10 npm install
```
Copy your code and package.json to the instance using `scp` and create a deployment package:
Set the Lambda runtime to Node.js 6.10.
To get the best performance select the largest memory available. A 1536 MB function provides ~12x more CPU time than a 128 MB function.
### NW.js
Run the `nw-gyp` tool after installation.
```sh
cd sharp-lambda-example
npm install
zip -ur9 ../sharp-lambda-example.zip index.js node_modules
cd node-modules/sharp
nw-gyp rebuild --arch=x64 --target=[your nw version]
node node_modules/sharp/install/dll-copy
```
You can now download your deployment ZIP using `scp` and upload it to Lambda. Be sure to set your Lambda runtime to Node.js 4.3.
**Performance Tip:** To get the best performance on Lambda choose the largest memory available because this also gives you the most cpu time (a 1536 MB function is 12x faster than a 128 MB function).
See also http://docs.nwjs.io/en/latest/For%20Users/Advanced/Use%20Native%20Node%20Modules/
### Build tools
* [gulp-responsive](https://www.npmjs.com/package/gulp-responsive)
* [grunt-sharp](https://www.npmjs.com/package/grunt-sharp)
### Coding tools
* [Sharp TypeScript Types](https://www.npmjs.com/package/@types/sharp)
### CLI tools
* [sharp-cli](https://www.npmjs.com/package/sharp-cli)
### Security
Many users of this module process untrusted, user-supplied images,
@@ -170,15 +221,33 @@ configuration file to prevent the use of coders known to be vulnerable.
Set the `MAGICK_CONFIGURE_PATH` environment variable
to the directory containing the `policy.xml` file.
### Licences
### Pre-compiled libvips binaries
If a global installation of libvips that meets the
minimum version requirement cannot be found,
this module will download a pre-compiled bundle of libvips
and its dependencies on Linux and Windows machines.
This module will attempt to download a pre-compiled bundle of libvips
and its dependencies on Linux and Windows machines under either of these
conditions:
1. If a global installation of libvips that meets the
minimum version requirement cannot be found;
1. If `SHARP_IGNORE_GLOBAL_LIBVIPS` environment variable is set.
```sh
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install sharp
```
Should you need to manually download and inspect these files,
you can do so via https://dl.bintray.com/lovell/sharp/
you can do so via https://github.com/lovell/sharp-libvips/releases
Should you wish to install these from your own location,
set the `SHARP_DIST_BASE_URL` environment variable, e.g.
```sh
SHARP_DIST_BASE_URL="https://hostname/path/" npm install sharp
```
to use `https://hostname/path/libvips-x.y.z-platform.tar.gz`.
### Licences
This module is licensed under the terms of the
[Apache 2.0 Licence](https://github.com/lovell/sharp/blob/master/LICENSE).
@@ -193,6 +262,7 @@ Use of libraries under the terms of the LGPLv3 is via the
| Library | Used under the terms of |
|---------------|----------------------------------------------------------------------------------------------------------|
| cairo | Mozilla Public License 2.0 |
| expat | MIT Licence |
| fontconfig | [fontconfig Licence](https://cgit.freedesktop.org/fontconfig/tree/COPYING) (BSD-like) |
| freetype | [freetype Licence](http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/FTL.TXT) (BSD-like) |
| giflib | MIT Licence |

View File

@@ -2,19 +2,20 @@
### Test environment
* AWS EC2 eu-central-1 [c4.xlarge](http://aws.amazon.com/ec2/instance-types/#c4) (4x E5-2666 v3 @ 2.90GHz)
* Ubuntu 16.04.1 LTS (HVM, SSD, 20161115, ami-82cf0aed)
* Node.js v6.9.1
* AWS EC2 eu-west-1 [c5.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz)
* Ubuntu 17.10 (hvm:ebs-ssd, 20180102, ami-0741d47e)
* Node.js v8.9.4
### The contenders
* [jimp](https://www.npmjs.com/package/jimp) v0.2.27 - Image processing in pure JavaScript. Bilinear interpolation only.
* [lwip](https://www.npmjs.com/package/lwip) v0.0.9 - Wrapper around CImg. Compiles outdated, insecure dependencies from source.
* [mapnik](https://www.npmjs.org/package/mapnik) v3.5.14 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
* [jimp](https://www.npmjs.com/package/jimp) v0.2.28 - Image processing in pure JavaScript. Bilinear interpolation only.
* [pajk-lwip](https://www.npmjs.com/package/pajk-lwip) v0.2.0 (fork) - Wrapper around CImg that compiles dependencies from source.
* [mapnik](https://www.npmjs.org/package/mapnik) v3.6.2 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
* [imagemagick-native](https://www.npmjs.com/package/imagemagick-native) v1.9.3 - Wrapper around libmagick++, supports Buffers only.
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
* [gm](https://www.npmjs.com/package/gm) v1.23.0 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
* sharp v0.17.0 / libvips v8.4.2 - Caching within libvips disabled to ensure a fair comparison.
* [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
* [images](https://www.npmjs.com/package/images) v3.0.1 - Compiles dependencies from source. Provides bicubic interpolation.
* sharp v0.19.0 / libvips v8.6.1 - Caching within libvips disabled to ensure a fair comparison.
### The task
@@ -26,18 +27,19 @@ then compress to JPEG at a "quality" setting of 80.
| Module | Input | Output | Ops/sec | Speed-up |
| :----------------- | :----- | :----- | ------: | -------: |
| jimp (bilinear) | buffer | buffer | 1.06 | 1.0 |
| lwip | buffer | buffer | 1.87 | 1.8 |
| mapnik | buffer | buffer | 2.91 | 2.7 |
| imagemagick-native | buffer | buffer | 4.03 | 3.8 |
| imagemagick | file | file | 7.10 | 6.7 |
| gm | buffer | buffer | 7.08 | 6.7 |
| gm | file | file | 7.10 | 6.7 |
| sharp | stream | stream | 27.61 | 26.0 |
| sharp | file | file | 28.41 | 26.8 |
| sharp | buffer | file | 28.71 | 27.1 |
| sharp | file | buffer | 28.60 | 27.0 |
| sharp | buffer | buffer | 29.08 | 27.4 |
| jimp (bilinear) | buffer | buffer | 1.14 | 1.0 |
| lwip | buffer | buffer | 1.86 | 1.6 |
| mapnik | buffer | buffer | 3.34 | 2.9 |
| imagemagick-native | buffer | buffer | 4.13 | 3.6 |
| gm | buffer | buffer | 4.21 | 3.7 |
| gm | file | file | 4.27 | 3.7 |
| imagemagick | file | file | 4.67 | 4.1 |
| images (bicubic) | file | file | 6.22 | 5.5 |
| sharp | stream | stream | 24.43 | 21.4 |
| sharp | file | file | 25.97 | 22.7 |
| sharp | file | buffer | 26.00 | 22.8 |
| sharp | buffer | file | 26.33 | 23.0 |
| sharp | buffer | buffer | 26.43 | 23.1 |
Greater libvips performance can be expected with caching enabled (default)
and using 8+ core machines, especially those with larger L1/L2 CPU caches.
@@ -46,19 +48,20 @@ The I/O limits of the relevant (de)compression library will generally determine
### Benchmark test prerequisites
Requires both _ImageMagick_ and _GraphicsMagick_:
Requires _ImageMagick_, _GraphicsMagick_ and _Mapnik_:
```sh
brew install imagemagick
brew install graphicsmagick
brew install mapnik
```
```sh
sudo apt-get install imagemagick libmagick++-dev graphicsmagick
sudo apt-get install imagemagick libmagick++-dev graphicsmagick mapnik-dev
```
```sh
sudo yum install ImageMagick-devel ImageMagick-c++-devel GraphicsMagick
sudo yum install ImageMagick-devel ImageMagick-c++-devel GraphicsMagick mapnik-devel
```
### Running the benchmark test

35
install/dll-copy.js Normal file
View File

@@ -0,0 +1,35 @@
'use strict';
const fs = require('fs');
const path = require('path');
const copyFileSync = require('fs-copy-file-sync');
const libvips = require('../lib/libvips');
const npmLog = require('npmlog');
if (process.platform === 'win32') {
const buildDir = path.join(__dirname, '..', 'build');
const buildReleaseDir = path.join(buildDir, 'Release');
npmLog.info('sharp', `Creating ${buildReleaseDir}`);
try {
libvips.mkdirSync(buildDir);
libvips.mkdirSync(buildReleaseDir);
} catch (err) {}
const vendorLibDir = path.join(__dirname, '..', 'vendor', 'lib');
npmLog.info('sharp', `Copying DLLs from ${vendorLibDir} to ${buildReleaseDir}`);
try {
fs
.readdirSync(vendorLibDir)
.filter(function (filename) {
return /\.dll$/.test(filename);
})
.forEach(function (filename) {
copyFileSync(
path.join(vendorLibDir, filename),
path.join(buildReleaseDir, filename)
);
});
} catch (err) {
npmLog.error('sharp', err.message);
}
}

100
install/libvips.js Normal file
View File

@@ -0,0 +1,100 @@
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const detectLibc = require('detect-libc');
const npmLog = require('npmlog');
const semver = require('semver');
const simpleGet = require('simple-get');
const tar = require('tar');
const copyFileSync = require('fs-copy-file-sync');
const agent = require('../lib/agent');
const libvips = require('../lib/libvips');
const platform = require('../lib/platform');
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersion}/`;
const extractTarball = function (tarPath) {
const vendorPath = path.join(__dirname, '..', 'vendor');
libvips.mkdirSync(vendorPath);
tar
.extract({
file: tarPath,
cwd: vendorPath,
strict: true
})
.catch(function (err) {
throw err;
});
};
try {
const useGlobalLibvips = libvips.useGlobalLibvips();
if (useGlobalLibvips) {
const globalLibvipsVersion = libvips.globalLibvipsVersion();
npmLog.info('sharp', `Detected globally-installed libvips v${globalLibvipsVersion}`);
npmLog.info('sharp', 'Building from source via node-gyp');
process.exit(1);
} else if (libvips.hasVendoredLibvips()) {
npmLog.info('sharp', `Using existing vendored libvips v${minimumLibvipsVersion}`);
} else {
// Is this arch/platform supported?
const arch = process.env.npm_config_arch || process.arch;
const platformAndArch = platform();
if (platformAndArch === 'win32-ia32') {
throw new Error('Windows x86 (32-bit) node.exe is not supported');
}
if (arch === 'ia32') {
throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
}
if (platformAndArch === 'freebsd-x64') {
throw new Error(`FreeBSD systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
}
if (detectLibc.isNonGlibcLinux) {
throw new Error(`Use with ${detectLibc.family} libc requires manual installation of libvips >= ${minimumLibvipsVersion}`);
}
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) {
throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
}
// Download to per-process temporary file
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.gz';
const tarPathCache = path.join(libvips.cachePath(), tarFilename);
if (fs.existsSync(tarPathCache)) {
npmLog.info('sharp', `Using cached ${tarPathCache}`);
extractTarball(tarPathCache);
} else {
const tarPathTemp = path.join(os.tmpdir(), `${process.pid}-${tarFilename}`);
const tmpFile = fs.createWriteStream(tarPathTemp);
const url = distBaseUrl + tarFilename;
npmLog.info('sharp', `Downloading ${url}`);
simpleGet({ url: url, agent: agent() }, function (err, response) {
if (err) {
throw err;
}
if (response.statusCode !== 200) {
throw new Error(`Status ${response.statusCode}`);
}
response.pipe(tmpFile);
});
tmpFile.on('close', function () {
try {
// Attempt to rename
fs.renameSync(tarPathTemp, tarPathCache);
} catch (err) {
// Fall back to copy and unlink
copyFileSync(tarPathTemp, tarPathCache);
fs.unlinkSync(tarPathTemp);
}
extractTarball(tarPathCache);
});
}
}
} catch (err) {
npmLog.error('sharp', err.message);
npmLog.error('sharp', 'Please see http://sharp.pixelplumbing.com/page/install');
process.exit(1);
}

37
lib/agent.js Normal file
View File

@@ -0,0 +1,37 @@
'use strict';
const url = require('url');
const tunnelAgent = require('tunnel-agent');
const is = require('./is');
const proxies = [
'HTTPS_PROXY',
'https_proxy',
'HTTP_PROXY',
'http_proxy',
'npm_config_https_proxy',
'npm_config_proxy'
];
function env (key) {
return process.env[key];
}
module.exports = function () {
try {
const proxy = url.parse(proxies.map(env).find(is.string));
const tunnel = proxy.protocol === 'https:'
? tunnelAgent.httpsOverHttps
: tunnelAgent.httpsOverHttp;
return tunnel({
proxy: {
port: Number(proxy.port),
host: proxy.hostname,
proxyAuth: proxy.auth
}
});
} catch (err) {
return null;
}
};

View File

@@ -12,6 +12,23 @@ const bool = {
eor: 'eor'
};
/**
* Remove alpha channel, if any. This is a no-op if the image does not have an alpha channel.
*
* @example
* sharp('rgba.png')
* .removeAlpha()
* .toFile('rgb.png', function(err, info) {
* // rgb.png is a 3 channel image without an alpha channel
* });
*
* @returns {Sharp}
*/
function removeAlpha () {
this.options.removeAlpha = true;
return this;
}
/**
* Extract a single channel from a multi-channel image.
*
@@ -27,7 +44,7 @@ const bool = {
* @returns {Sharp}
* @throws {Error} Invalid channel
*/
const extractChannel = function extractChannel (channel) {
function extractChannel (channel) {
if (channel === 'red') {
channel = 0;
} else if (channel === 'green') {
@@ -41,7 +58,7 @@ const extractChannel = function extractChannel (channel) {
throw new Error('Cannot extract invalid channel ' + channel);
}
return this;
};
}
/**
* Join one or more channels to the image.
@@ -59,7 +76,7 @@ const extractChannel = function extractChannel (channel) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const joinChannel = function joinChannel (images, options) {
function joinChannel (images, options) {
if (Array.isArray(images)) {
images.forEach(function (image) {
this.options.joinChannelIn.push(this._createInputDescriptor(image, options));
@@ -68,7 +85,7 @@ const joinChannel = function joinChannel (images, options) {
this.options.joinChannelIn.push(this._createInputDescriptor(images, options));
}
return this;
};
}
/**
* Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.
@@ -86,14 +103,14 @@ const joinChannel = function joinChannel (images, options) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const bandbool = function bandbool (boolOp) {
function bandbool (boolOp) {
if (is.string(boolOp) && is.inArray(boolOp, ['and', 'or', 'eor'])) {
this.options.bandBoolOp = boolOp;
} else {
throw new Error('Invalid bandbool operation ' + boolOp);
}
return this;
};
}
/**
* Decorate the Sharp prototype with channel-related functions.
@@ -102,6 +119,7 @@ const bandbool = function bandbool (boolOp) {
module.exports = function (Sharp) {
// Public instance functions
[
removeAlpha,
extractChannel,
joinChannel,
bandbool

View File

@@ -27,7 +27,7 @@ const colourspace = {
* @returns {Sharp}
* @throws {Error} Invalid parameter
*/
const background = function background (rgba) {
function background (rgba) {
const colour = color(rgba);
this.options.background = [
colour.red(),
@@ -36,7 +36,22 @@ const background = function background (rgba) {
Math.round(colour.alpha() * 255)
];
return this;
};
}
/**
* Tint the image using the provided chroma while preserving the image luminance.
* An alpha channel may be present and will be unchanged by the operation.
*
* @param {String|Object} rgb - parsed by the [color](https://www.npmjs.org/package/color) module to extract chroma values.
* @returns {Sharp}
* @throws {Error} Invalid parameter
*/
function tint (rgb) {
const colour = color(rgb);
this.options.tintA = colour.a();
this.options.tintB = colour.b();
return this;
}
/**
* Convert to 8-bit greyscale; 256 shades of grey.
@@ -48,19 +63,19 @@ const background = function background (rgba) {
* @param {Boolean} [greyscale=true]
* @returns {Sharp}
*/
const greyscale = function greyscale (greyscale) {
function greyscale (greyscale) {
this.options.greyscale = is.bool(greyscale) ? greyscale : true;
return this;
};
}
/**
* Alternative spelling of `greyscale`.
* @param {Boolean} [grayscale=true]
* @returns {Sharp}
*/
const grayscale = function grayscale (grayscale) {
function grayscale (grayscale) {
return this.greyscale(grayscale);
};
}
/**
* Set the output colourspace.
@@ -69,13 +84,13 @@ const grayscale = function grayscale (grayscale) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const toColourspace = function toColourspace (colourspace) {
function toColourspace (colourspace) {
if (!is.string(colourspace)) {
throw new Error('Invalid output colourspace ' + colourspace);
}
this.options.colourspace = colourspace;
return this;
};
}
/**
* Alternative spelling of `toColourspace`.
@@ -83,9 +98,9 @@ const toColourspace = function toColourspace (colourspace) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const toColorspace = function toColorspace (colorspace) {
function toColorspace (colorspace) {
return this.toColourspace(colorspace);
};
}
/**
* Decorate the Sharp prototype with colour-related functions.
@@ -95,6 +110,7 @@ module.exports = function (Sharp) {
// Public instance functions
[
background,
tint,
greyscale,
grayscale,
toColourspace,

View File

@@ -8,6 +8,8 @@ const is = require('./is');
* The overlay image must be the same size or smaller than the processed image.
* If both `top` and `left` options are provided, they take precedence over `gravity`.
*
* If the overlay image contains an alpha channel then composition with premultiplication will occur.
*
* @example
* sharp('input.png')
* .rotate(180)
@@ -17,8 +19,7 @@ const is = require('./is');
* .overlayWith('overlay.png', { gravity: sharp.gravity.southeast } )
* .sharpen()
* .withMetadata()
* .quality(90)
* .webp()
* .webp( { quality: 90 } )
* .toBuffer()
* .then(function(outputBuffer) {
* // outputBuffer contains upside down, 300px wide, alpha channel flattened
@@ -33,14 +34,20 @@ const is = require('./is');
* @param {Number} [options.left] - the pixel offset from the left edge.
* @param {Boolean} [options.tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`.
* @param {Boolean} [options.cutout=false] - set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another.
* @param {Number} [options.density=72] - number representing the DPI for vector overlay image.
* @param {Object} [options.raw] - describes overlay when using raw pixel data.
* @param {Number} [options.raw.width]
* @param {Number} [options.raw.height]
* @param {Number} [options.raw.channels]
* @param {Object} [options.create] - describes a blank overlay to be created.
* @param {Number} [options.create.width]
* @param {Number} [options.create.height]
* @param {Number} [options.create.channels] - 3-4
* @param {String|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const overlayWith = function overlayWith (overlay, options) {
function overlayWith (overlay, options) {
this.options.overlay = this._createInputDescriptor(overlay, options, {
allowStream: false
});
@@ -60,10 +67,7 @@ const overlayWith = function overlayWith (overlay, options) {
}
}
if (is.defined(options.left) || is.defined(options.top)) {
if (
is.integer(options.left) && is.inRange(options.left, 0, this.constructor.maximum.width) &&
is.integer(options.top) && is.inRange(options.top, 0, this.constructor.maximum.height)
) {
if (is.integer(options.left) && options.left >= 0 && is.integer(options.top) && options.top >= 0) {
this.options.overlayXOffset = options.left;
this.options.overlayYOffset = options.top;
} else {
@@ -81,7 +85,7 @@ const overlayWith = function overlayWith (overlay, options) {
}
}
return this;
};
}
/**
* Decorate the Sharp prototype with composite-related functions.

View File

@@ -5,8 +5,25 @@ const util = require('util');
const stream = require('stream');
const events = require('events');
const semver = require('semver');
const is = require('./is');
const platform = require('./platform');
const sharp = require('../build/Release/sharp.node');
// Vendor platform
(function () {
let vendorPlatformId;
try {
vendorPlatformId = require('../vendor/platform.json');
} catch (err) {
return;
}
const currentPlatformId = platform();
/* istanbul ignore if */
if (currentPlatformId !== vendorPlatformId) {
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp/vendor' directory and run 'npm rebuild'.`);
}
})();
// Versioning
let versions = {
vips: sharp.libvipsVersion()
@@ -20,16 +37,19 @@ let versions = {
}
// Include versions of dependencies, if present
try {
versions = require('../vendor/lib/versions.json');
versions = require('../vendor/versions.json');
} catch (err) {}
})();
// Use NODE_DEBUG=sharp to enable libvips warnings
const debuglog = util.debuglog('sharp');
/**
* @class Sharp
*
* Constructor factory to create an instance of `sharp`, to which further methods are chained.
*
* JPEG, PNG or WebP format image data can be streamed out from this object.
* JPEG, PNG, WebP or TIFF format image data can be streamed out from this object.
* When using Stream based output, derived attributes are available from the `info` event.
*
* Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
@@ -54,20 +74,46 @@ let versions = {
* });
* readableStream.pipe(transformer).pipe(writableStream);
*
* @example
* // Create a blank 300x200 PNG image of semi-transluent red pixels
* sharp({
* create: {
* width: 300,
* height: 200,
* channels: 4,
* background: { r: 255, g: 0, b: 0, alpha: 0.5 }
* }
* })
* .png()
* .toBuffer()
* .then( ... );
*
* @param {(Buffer|String)} [input] - if present, can be
* a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
* a String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
* JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when null or undefined.
* JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present.
* @param {Object} [options] - if present, is an Object with optional attributes.
* @param {Number} [options.density=72] - integral number representing the DPI for vector images.
* @param {Object} [options.raw] - describes raw pixel image data. See `raw()` for pixel ordering.
* @param {Boolean} [options.failOnError=false] - by default apply a "best effort"
* to decode images, even if the data is corrupt or invalid. Set this flag to true
* if you'd rather halt processing and raise an error when loading invalid images.
* @param {Number} [options.density=72] - number representing the DPI for vector images.
* @param {Number} [options.page=0] - page number to extract for multi-page input (GIF, TIFF)
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
* @param {Number} [options.raw.width]
* @param {Number} [options.raw.height]
* @param {Number} [options.raw.channels]
* @param {Number} [options.raw.channels] - 1-4
* @param {Object} [options.create] - describes a new image to be created.
* @param {Number} [options.create.width]
* @param {Number} [options.create.height]
* @param {Number} [options.create.channels] - 3-4
* @param {String|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const Sharp = function (input, options) {
if (arguments.length === 1 && !is.defined(input)) {
throw new Error('Invalid input');
}
if (!(this instanceof Sharp)) {
return new Sharp(input, options);
}
@@ -75,7 +121,7 @@ const Sharp = function (input, options) {
this.options = {
// input options
sequentialRead: false,
limitInputPixels: maximum.pixels,
limitInputPixels: Math.pow(0x3FFF, 2),
// ICC profiles
iccProfilePath: path.join(__dirname, 'icc') + path.sep,
// resize options
@@ -91,6 +137,8 @@ const Sharp = function (input, options) {
height: -1,
canvas: 'crop',
crop: 0,
embed: 0,
useExifOrientation: false,
angle: 0,
rotateBeforePreExtract: false,
flip: false,
@@ -101,12 +149,14 @@ const Sharp = function (input, options) {
extendRight: 0,
withoutEnlargement: false,
kernel: 'lanczos3',
interpolator: 'bicubic',
centreSampling: false,
fastShrinkOnLoad: true,
// operations
background: [0, 0, 0, 255],
tintA: 128,
tintB: 128,
flatten: false,
negate: false,
medianSize: 0,
blurSigma: 0,
sharpenSigma: 0,
sharpenFlat: 1,
@@ -121,6 +171,7 @@ const Sharp = function (input, options) {
booleanFileIn: '',
joinChannelIn: [],
extractChannel: -1,
removeAlpha: false,
colourspace: 'srgb',
// overlay
overlayGravity: 0,
@@ -134,6 +185,7 @@ const Sharp = function (input, options) {
streamOut: false,
withMetadata: false,
withMetadataOrientation: -1,
resolveWithObject: false,
// output format
jpegQuality: 80,
jpegProgressive: false,
@@ -141,13 +193,27 @@ const Sharp = function (input, options) {
jpegTrellisQuantisation: false,
jpegOvershootDeringing: false,
jpegOptimiseScans: false,
jpegOptimiseCoding: true,
jpegQuantisationTable: 0,
pngProgressive: false,
pngCompressionLevel: 6,
pngAdaptiveFiltering: true,
pngCompressionLevel: 9,
pngAdaptiveFiltering: false,
webpQuality: 80,
webpAlphaQuality: 100,
webpLossless: false,
webpNearLossless: false,
tiffQuality: 80,
tiffCompression: 'jpeg',
tiffPredictor: 'horizontal',
tiffSquash: false,
tiffXres: 1.0,
tiffYres: 1.0,
tileSize: 256,
tileOverlap: 0,
linearA: 1,
linearB: 0,
// Function to notify of libvips warnings
debuglog: debuglog,
// Function to notify of queue length changes
queueListener: function (queueLength) {
queue.emit('change', queueLength);
@@ -158,18 +224,6 @@ const Sharp = function (input, options) {
};
util.inherits(Sharp, stream.Duplex);
/**
* Pixel limits.
* @member
* @private
*/
const maximum = {
width: 0x3FFF,
height: 0x3FFF,
pixels: Math.pow(0x3FFF, 2)
};
Sharp.maximum = maximum;
/**
* An EventEmitter that emits a `change` event when a task is either:
* - queued, waiting for _libuv_ to provide a worker thread
@@ -186,7 +240,7 @@ Sharp.queue = queue;
/**
* An Object containing nested boolean values representing the available input and output formats/methods.
* @example
* console.log(sharp.format());
* console.log(sharp.format);
* @returns {Object}
*/
Sharp.format = sharp.format();

View File

@@ -1,17 +1,13 @@
'use strict';
const Sharp = require('./constructor');
[
'input',
'resize',
'composite',
'operation',
'colour',
'channel',
'output',
'utility'
].forEach(function (decorator) {
require('./' + decorator)(Sharp);
});
require('./input')(Sharp);
require('./resize')(Sharp);
require('./composite')(Sharp);
require('./operation')(Sharp);
require('./colour')(Sharp);
require('./channel')(Sharp);
require('./output')(Sharp);
require('./utility')(Sharp);
module.exports = Sharp;

View File

@@ -1,6 +1,6 @@
'use strict';
const util = require('util');
const color = require('color');
const is = require('./is');
const sharp = require('../build/Release/sharp.node');
@@ -8,14 +8,17 @@ const sharp = require('../build/Release/sharp.node');
* Create Object containing input and input-related options.
* @private
*/
const _createInputDescriptor = function _createInputDescriptor (input, inputOptions, containerOptions) {
const inputDescriptor = {};
function _createInputDescriptor (input, inputOptions, containerOptions) {
const inputDescriptor = { failOnError: false };
if (is.string(input)) {
// filesystem
inputDescriptor.file = input;
} else if (is.buffer(input)) {
// Buffer
inputDescriptor.buffer = input;
} else if (is.plainObject(input) && !is.defined(inputOptions)) {
// Plain Object descriptor, e.g. create
inputOptions = input;
} else if (!is.defined(input) && is.object(containerOptions) && containerOptions.allowStream) {
// Stream
inputDescriptor.buffer = [];
@@ -23,9 +26,17 @@ const _createInputDescriptor = function _createInputDescriptor (input, inputOpti
throw new Error('Unsupported input ' + typeof input);
}
if (is.object(inputOptions)) {
// Fail on error
if (is.defined(inputOptions.failOnError)) {
if (is.bool(inputOptions.failOnError)) {
inputDescriptor.failOnError = inputOptions.failOnError;
} else {
throw new Error('Invalid failOnError (boolean) ' + inputOptions.failOnError);
}
}
// Density
if (is.defined(inputOptions.density)) {
if (is.integer(inputOptions.density) && is.inRange(inputOptions.density, 1, 2400)) {
if (is.inRange(inputOptions.density, 1, 2400)) {
inputDescriptor.density = inputOptions.density;
} else {
throw new Error('Invalid density (1 to 2400) ' + inputOptions.density);
@@ -35,8 +46,8 @@ const _createInputDescriptor = function _createInputDescriptor (input, inputOpti
if (is.defined(inputOptions.raw)) {
if (
is.object(inputOptions.raw) &&
is.integer(inputOptions.raw.width) && is.inRange(inputOptions.raw.width, 1, this.constructor.maximum.width) &&
is.integer(inputOptions.raw.height) && is.inRange(inputOptions.raw.height, 1, this.constructor.maximum.height) &&
is.integer(inputOptions.raw.width) && inputOptions.raw.width > 0 &&
is.integer(inputOptions.raw.height) && inputOptions.raw.height > 0 &&
is.integer(inputOptions.raw.channels) && is.inRange(inputOptions.raw.channels, 1, 4)
) {
inputDescriptor.rawWidth = inputOptions.raw.width;
@@ -46,11 +57,41 @@ const _createInputDescriptor = function _createInputDescriptor (input, inputOpti
throw new Error('Expected width, height and channels for raw pixel input');
}
}
// Page input for multi-page TIFF
if (is.defined(inputOptions.page)) {
if (is.integer(inputOptions.page) && is.inRange(inputOptions.page, 0, 100000)) {
inputDescriptor.page = inputOptions.page;
}
}
// Create new image
if (is.defined(inputOptions.create)) {
if (
is.object(inputOptions.create) &&
is.integer(inputOptions.create.width) && inputOptions.create.width > 0 &&
is.integer(inputOptions.create.height) && inputOptions.create.height > 0 &&
is.integer(inputOptions.create.channels) && is.inRange(inputOptions.create.channels, 3, 4) &&
is.defined(inputOptions.create.background)
) {
inputDescriptor.createWidth = inputOptions.create.width;
inputDescriptor.createHeight = inputOptions.create.height;
inputDescriptor.createChannels = inputOptions.create.channels;
const background = color(inputOptions.create.background);
inputDescriptor.createBackground = [
background.red(),
background.green(),
background.blue(),
Math.round(background.alpha() * 255)
];
delete inputDescriptor.buffer;
} else {
throw new Error('Expected width, height, channels and background to create a new input image');
}
}
} else if (is.defined(inputOptions)) {
throw new Error('Invalid input options ' + inputOptions);
}
return inputDescriptor;
};
}
/**
* Handle incoming Buffer chunk on Writable Stream.
@@ -59,11 +100,17 @@ const _createInputDescriptor = function _createInputDescriptor (input, inputOpti
* @param {String} encoding - unused
* @param {Function} callback
*/
const _write = function _write (chunk, encoding, callback) {
function _write (chunk, encoding, callback) {
/* istanbul ignore else */
if (Array.isArray(this.options.input.buffer)) {
/* istanbul ignore else */
if (is.buffer(chunk)) {
if (this.options.input.buffer.length === 0) {
const that = this;
this.on('finish', function () {
that.streamInFinished = true;
});
}
this.options.input.buffer.push(chunk);
callback();
} else {
@@ -72,26 +119,26 @@ const _write = function _write (chunk, encoding, callback) {
} else {
callback(new Error('Unexpected data on Writable Stream'));
}
};
}
/**
* Flattens the array of chunks accumulated in input.buffer.
* @private
*/
const _flattenBufferIn = function _flattenBufferIn () {
function _flattenBufferIn () {
if (this._isStreamInput()) {
this.options.input.buffer = Buffer.concat(this.options.input.buffer);
}
};
}
/**
* Are we expecting Stream-based input?
* @private
* @returns {Boolean}
*/
const _isStreamInput = function _isStreamInput () {
function _isStreamInput () {
return Array.isArray(this.options.input.buffer);
};
}
/**
* Take a "snapshot" of the Sharp instance, returning a new instance.
@@ -108,36 +155,41 @@ const _isStreamInput = function _isStreamInput () {
*
* @returns {Sharp}
*/
const clone = function clone () {
function clone () {
const that = this;
// Clone existing options
const clone = this.constructor.call();
util._extend(clone.options, this.options);
clone.options = Object.assign({}, this.options);
// Pass 'finish' event to clone for Stream-based input
this.on('finish', function () {
// Clone inherits input data
that._flattenBufferIn();
clone.options.bufferIn = that.options.bufferIn;
clone.emit('finish');
});
if (this._isStreamInput()) {
this.on('finish', function () {
// Clone inherits input data
that._flattenBufferIn();
clone.options.bufferIn = that.options.bufferIn;
clone.emit('finish');
});
}
return clone;
};
}
/**
* Fast access to image metadata without decoding any compressed image data.
* Fast access to (uncached) image metadata without decoding any compressed image data.
* A Promises/A+ promise is returned when `callback` is not provided.
*
* - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
* - `width`: Number of pixels wide
* - `height`: Number of pixels high
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
* - `width`: Number of pixels wide (EXIF orientation is not taken into consideration)
* - `height`: Number of pixels high (EXIF orientation is not taken into consideration)
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636)
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672)
* - `density`: Number of pixels per inch (DPI), if present
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
* - `orientation`: Number value of the EXIF Orientation header, if present
* - `exif`: Buffer containing raw EXIF data, if present
* - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
* - `iptc`: Buffer containing raw IPTC data, if present
* - `xmp`: Buffer containing raw XMP data, if present
*
* @example
* const image = sharp(inputJpg);
@@ -156,7 +208,7 @@ const clone = function clone () {
* @param {Function} [callback] - called with the arguments `(err, metadata)`
* @returns {Promise<Object>|Sharp}
*/
const metadata = function metadata (callback) {
function metadata (callback) {
const that = this;
if (is.fn(callback)) {
if (this._isStreamInput()) {
@@ -194,7 +246,76 @@ const metadata = function metadata (callback) {
});
}
}
};
}
/**
* Access to pixel-derived image statistics for every channel in the image.
* A Promise is returned when `callback` is not provided.
*
* - `channels`: Array of channel statistics for each channel in the image. Each channel statistic contains
* - `min` (minimum value in the channel)
* - `max` (maximum value in the channel)
* - `sum` (sum of all values in a channel)
* - `squaresSum` (sum of squared values in a channel)
* - `mean` (mean of the values in a channel)
* - `stdev` (standard deviation for the values in a channel)
* - `minX` (x-coordinate of one of the pixel where the minimum lies)
* - `minY` (y-coordinate of one of the pixel where the minimum lies)
* - `maxX` (x-coordinate of one of the pixel where the maximum lies)
* - `maxY` (y-coordinate of one of the pixel where the maximum lies)
* - `isOpaque`: Value to identify if the image is opaque or transparent, based on the presence and use of alpha channel
* - `entropy`: Histogram-based estimation of greyscale entropy, discarding alpha channel if any (experimental)
*
* @example
* const image = sharp(inputJpg);
* image
* .stats()
* .then(function(stats) {
* // stats contains the channel-wise statistics array and the isOpaque value
* });
*
* @param {Function} [callback] - called with the arguments `(err, stats)`
* @returns {Promise<Object>}
*/
function stats (callback) {
const that = this;
if (is.fn(callback)) {
if (this._isStreamInput()) {
this.on('finish', function () {
that._flattenBufferIn();
sharp.stats(that.options, callback);
});
} else {
sharp.stats(this.options, callback);
}
return this;
} else {
if (this._isStreamInput()) {
return new Promise(function (resolve, reject) {
that.on('finish', function () {
that._flattenBufferIn();
sharp.stats(that.options, function (err, stats) {
if (err) {
reject(err);
} else {
resolve(stats);
}
});
});
});
} else {
return new Promise(function (resolve, reject) {
sharp.stats(that.options, function (err, stats) {
if (err) {
reject(err);
} else {
resolve(stats);
}
});
});
}
}
}
/**
* Do not process input images where the number of pixels (width * height) exceeds this limit.
@@ -204,31 +325,34 @@ const metadata = function metadata (callback) {
* @returns {Sharp}
* @throws {Error} Invalid limit
*/
const limitInputPixels = function limitInputPixels (limit) {
function limitInputPixels (limit) {
// if we pass in false we represent the integer as 0 to disable
if (limit === false) {
limit = 0;
} else if (limit === true) {
limit = this.constructor.maximum.pixels;
limit = Math.pow(0x3FFF, 2);
}
if (is.integer(limit) && limit >= 0) {
this.options.limitInputPixels = limit;
} else {
throw new Error('Invalid pixel limit (0 to ' + this.constructor.maximum.pixels + ') ' + limit);
throw is.invalidParameterError('limitInputPixels', 'integer', limit);
}
return this;
};
}
/**
* An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
* This will reduce memory usage and can improve performance on some systems.
*
* The default behaviour *before* function call is `false`, meaning the libvips access method is not sequential.
*
* @param {Boolean} [sequentialRead=true]
* @returns {Sharp}
*/
const sequentialRead = function sequentialRead (sequentialRead) {
function sequentialRead (sequentialRead) {
this.options.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
return this;
};
}
/**
* Decorate the Sharp prototype with input-related functions.
@@ -244,6 +368,7 @@ module.exports = function (Sharp) {
// Public
clone,
metadata,
stats,
limitInputPixels,
sequentialRead
].forEach(function (f) {

View File

@@ -16,6 +16,14 @@ const object = function (val) {
return typeof val === 'object';
};
/**
* Is this value a plain object?
* @private
*/
const plainObject = function (val) {
return object(val) && Object.prototype.toString.call(val) === '[object Object]';
};
/**
* Is this value a function?
* @private
@@ -80,9 +88,25 @@ const inArray = function (val, list) {
return list.indexOf(val) !== -1;
};
/**
* Create an Error with a message relating to an invalid parameter.
*
* @param {String} name - parameter name.
* @param {String} expected - description of the type/value/range expected.
* @param {*} actual - the value received.
* @returns {Error} Containing the formatted message.
* @private
*/
const invalidParameterError = function (name, expected, actual) {
return new Error(
`Expected ${expected} for ${name} but received ${actual} of type ${typeof actual}`
);
};
module.exports = {
defined: defined,
object: object,
plainObject: plainObject,
fn: fn,
bool: bool,
buffer: buffer,
@@ -90,5 +114,6 @@ module.exports = {
number: number,
integer: integer,
inRange: inRange,
inArray: inArray
inArray: inArray,
invalidParameterError: invalidParameterError
};

89
lib/libvips.js Normal file
View File

@@ -0,0 +1,89 @@
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const spawnSync = require('child_process').spawnSync;
const semver = require('semver');
const platform = require('./platform');
const env = process.env;
const minimumLibvipsVersion = env.npm_package_config_libvips || require('../package.json').config.libvips;
const spawnSyncOptions = {
encoding: 'utf8',
shell: true
};
const mkdirSync = function (dirPath) {
try {
fs.mkdirSync(dirPath);
} catch (err) {
if (err.code !== 'EEXIST') {
throw err;
}
}
};
const cachePath = function () {
const npmCachePath = env.npm_config_cache || (env.APPDATA ? path.join(env.APPDATA, 'npm-cache') : path.join(os.homedir(), '.npm'));
mkdirSync(npmCachePath);
const libvipsCachePath = path.join(npmCachePath, '_libvips');
mkdirSync(libvipsCachePath);
return libvipsCachePath;
};
const globalLibvipsVersion = function () {
if (process.platform !== 'win32') {
const globalLibvipsVersion = spawnSync(`PKG_CONFIG_PATH="${pkgConfigPath()}" pkg-config --modversion vips-cpp`, spawnSyncOptions).stdout || '';
return globalLibvipsVersion.trim();
} else {
return '';
}
};
const hasVendoredLibvips = function () {
const currentPlatformId = platform();
let vendorPlatformId;
try {
vendorPlatformId = require(path.join(__dirname, '..', 'vendor', 'platform.json'));
} catch (err) {}
if (vendorPlatformId) {
if (currentPlatformId === vendorPlatformId) {
return true;
} else {
throw new Error(`'${vendorPlatformId}' binaries cannot be used on the '${currentPlatformId}' platform. Please remove the 'node_modules/sharp/vendor' directory and run 'npm install'.`);
}
}
return false;
};
const pkgConfigPath = function () {
if (process.platform !== 'win32') {
const brewPkgConfigPath = spawnSync('which brew >/dev/null 2>&1 && eval $(brew --env) && echo $PKG_CONFIG_LIBDIR', spawnSyncOptions).stdout || '';
return [brewPkgConfigPath.trim(), env.PKG_CONFIG_PATH, '/usr/local/lib/pkgconfig', '/usr/lib/pkgconfig']
.filter(function (p) { return !!p; })
.join(':');
} else {
return '';
}
};
const useGlobalLibvips = function () {
if (Boolean(env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
return false;
}
const globalVipsVersion = globalLibvipsVersion();
return !!globalVipsVersion && semver.gte(globalVipsVersion, minimumLibvipsVersion);
};
module.exports = {
minimumLibvipsVersion: minimumLibvipsVersion,
cachePath: cachePath,
globalLibvipsVersion: globalLibvipsVersion,
hasVendoredLibvips: hasVendoredLibvips,
pkgConfigPath: pkgConfigPath,
useGlobalLibvips: useGlobalLibvips,
mkdirSync: mkdirSync
};

View File

@@ -6,7 +6,10 @@ const is = require('./is');
* Rotate the output image by either an explicit angle
* or auto-orient based on the EXIF `Orientation` tag.
*
* Use this method without angle to determine the angle from EXIF data.
* If an angle is provided, it is converted to a valid 90/180/270deg rotation.
* For example, `-450` will produce a 270deg rotation.
*
* If no angle is provided, it is determined from the EXIF data.
* Mirroring is supported and may infer the use of a flip operation.
*
* The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
@@ -25,20 +28,20 @@ const is = require('./is');
* });
* readableStream.pipe(pipeline);
*
* @param {Number} [angle=auto] 0, 90, 180 or 270.
* @param {Number} [angle=auto] angle of rotation, must be a multiple of 90.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const rotate = function rotate (angle) {
function rotate (angle) {
if (!is.defined(angle)) {
this.options.angle = -1;
} else if (is.integer(angle) && is.inArray(angle, [0, 90, 180, 270])) {
this.options.useExifOrientation = true;
} else if (is.integer(angle) && !(angle % 90)) {
this.options.angle = angle;
} else {
throw new Error('Unsupported angle (0, 90, 180, 270) ' + angle);
throw new Error('Unsupported angle: angle must be a positive/negative multiple of 90 ' + angle);
}
return this;
};
}
/**
* Extract a region of the image.
@@ -70,7 +73,7 @@ const rotate = function rotate (angle) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const extract = function extract (options) {
function extract (options) {
const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
['left', 'top', 'width', 'height'].forEach(function (name) {
const value = options[name];
@@ -81,11 +84,11 @@ const extract = function extract (options) {
}
}, this);
// Ensure existing rotation occurs before pre-resize extraction
if (suffix === 'Pre' && this.options.angle !== 0) {
if (suffix === 'Pre' && ((this.options.angle % 360) !== 0 || this.options.useExifOrientation === true)) {
this.options.rotateBeforePreExtract = true;
}
return this;
};
}
/**
* Flip the image about the vertical Y axis. This always occurs after rotation, if any.
@@ -93,10 +96,10 @@ const extract = function extract (options) {
* @param {Boolean} [flip=true]
* @returns {Sharp}
*/
const flip = function flip (flip) {
function flip (flip) {
this.options.flip = is.bool(flip) ? flip : true;
return this;
};
}
/**
* Flop the image about the horizontal X axis. This always occurs after rotation, if any.
@@ -104,10 +107,10 @@ const flip = function flip (flip) {
* @param {Boolean} [flop=true]
* @returns {Sharp}
*/
const flop = function flop (flop) {
function flop (flop) {
this.options.flop = is.bool(flop) ? flop : true;
return this;
};
}
/**
* Sharpen the image.
@@ -121,7 +124,7 @@ const flop = function flop (flop) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const sharpen = function sharpen (sigma, flat, jagged) {
function sharpen (sigma, flat, jagged) {
if (!is.defined(sigma)) {
// No arguments: default to mild sharpen
this.options.sharpenSigma = -1;
@@ -151,7 +154,27 @@ const sharpen = function sharpen (sigma, flat, jagged) {
throw new Error('Invalid sharpen sigma (0.01 - 10000) ' + sigma);
}
return this;
};
}
/**
* Apply median filter.
* When used without parameters the default window is 3x3.
* @param {Number} [size=3] square mask size: size x size
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
function median (size) {
if (!is.defined(size)) {
// No arguments: default to 3x3
this.options.medianSize = 3;
} else if (is.integer(size) && is.inRange(size, 1, 1000)) {
// Numeric argument: specific sigma
this.options.medianSize = size;
} else {
throw new Error('Invalid median size ' + size);
}
return this;
}
/**
* Blur the image.
@@ -161,7 +184,7 @@ const sharpen = function sharpen (sigma, flat, jagged) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const blur = function blur (sigma) {
function blur (sigma) {
if (!is.defined(sigma)) {
// No arguments: default to mild blur
this.options.blurSigma = -1;
@@ -175,7 +198,7 @@ const blur = function blur (sigma) {
throw new Error('Invalid blur sigma (0.3 - 1000.0) ' + sigma);
}
return this;
};
}
/**
* Extends/pads the edges of the image with the colour provided to the `background` method.
@@ -186,7 +209,7 @@ const blur = function blur (sigma) {
* // to the top, left and right edges and 20 to the bottom edge
* sharp(input)
* .resize(140)
* .background({r: 0, g: 0, b: 0, a: 0})
* .background({r: 0, g: 0, b: 0, alpha: 0})
* .extend({top: 10, bottom: 20, left: 10, right: 10})
* ...
*
@@ -198,7 +221,7 @@ const blur = function blur (sigma) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const extend = function extend (extend) {
function extend (extend) {
if (is.integer(extend) && extend > 0) {
this.options.extendTop = extend;
this.options.extendBottom = extend;
@@ -219,17 +242,17 @@ const extend = function extend (extend) {
throw new Error('Invalid edge extension ' + extend);
}
return this;
};
}
/**
* Merge alpha transparency channel, if any, with `background`.
* @param {Boolean} [flatten=true]
* @returns {Sharp}
*/
const flatten = function flatten (flatten) {
function flatten (flatten) {
this.options.flatten = is.bool(flatten) ? flatten : true;
return this;
};
}
/**
* Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
@@ -237,7 +260,7 @@ const flatten = function flatten (flatten) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const trim = function trim (tolerance) {
function trim (tolerance) {
if (!is.defined(tolerance)) {
this.options.trimTolerance = 10;
} else if (is.integer(tolerance) && is.inRange(tolerance, 1, 99)) {
@@ -246,7 +269,7 @@ const trim = function trim (tolerance) {
throw new Error('Invalid trim tolerance (1 to 99) ' + tolerance);
}
return this;
};
}
/**
* Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`
@@ -258,7 +281,7 @@ const trim = function trim (tolerance) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const gamma = function gamma (gamma) {
function gamma (gamma) {
if (!is.defined(gamma)) {
// Default gamma correction of 2.2 (sRGB)
this.options.gamma = 2.2;
@@ -268,36 +291,36 @@ const gamma = function gamma (gamma) {
throw new Error('Invalid gamma correction (1.0 to 3.0) ' + gamma);
}
return this;
};
}
/**
* Produce the "negative" of the image.
* @param {Boolean} [negate=true]
* @returns {Sharp}
*/
const negate = function negate (negate) {
function negate (negate) {
this.options.negate = is.bool(negate) ? negate : true;
return this;
};
}
/**
* Enhance output image contrast by stretching its luminance to cover the full dynamic range.
* @param {Boolean} [normalise=true]
* @returns {Sharp}
*/
const normalise = function normalise (normalise) {
function normalise (normalise) {
this.options.normalise = is.bool(normalise) ? normalise : true;
return this;
};
}
/**
* Alternative spelling of normalise.
* @param {Boolean} [normalize=true]
* @returns {Sharp}
*/
const normalize = function normalize (normalize) {
function normalize (normalize) {
return this.normalise(normalize);
};
}
/**
* Convolve the image with the specified kernel.
@@ -324,12 +347,12 @@ const normalize = function normalize (normalize) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const convolve = function convolve (kernel) {
function convolve (kernel) {
if (!is.object(kernel) || !Array.isArray(kernel.kernel) ||
!is.integer(kernel.width) || !is.integer(kernel.height) ||
!is.inRange(kernel.width, 3, 1001) || !is.inRange(kernel.height, 3, 1001) ||
kernel.height * kernel.width !== kernel.kernel.length
) {
) {
// must pass in a kernel
throw new Error('Invalid convolution kernel');
}
@@ -348,7 +371,7 @@ const convolve = function convolve (kernel) {
}
this.options.convKernel = kernel;
return this;
};
}
/**
* Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
@@ -359,7 +382,7 @@ const convolve = function convolve (kernel) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const threshold = function threshold (threshold, options) {
function threshold (threshold, options) {
if (!is.defined(threshold)) {
this.options.threshold = 128;
} else if (is.bool(threshold)) {
@@ -375,7 +398,7 @@ const threshold = function threshold (threshold, options) {
this.options.thresholdGrayscale = false;
}
return this;
};
}
/**
* Perform a bitwise boolean operation with operand image.
@@ -393,7 +416,7 @@ const threshold = function threshold (threshold, options) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const boolean = function boolean (operand, operator, options) {
function boolean (operand, operator, options) {
this.options.boolean = this._createInputDescriptor(operand, options);
if (is.string(operator) && is.inArray(operator, ['and', 'or', 'eor'])) {
this.options.booleanOp = operator;
@@ -401,7 +424,34 @@ const boolean = function boolean (operand, operator, options) {
throw new Error('Invalid boolean operator ' + operator);
}
return this;
};
}
/**
* Apply the linear formula a * input + b to the image (levels adjustment)
* @param {Number} [a=1.0] multiplier
* @param {Number} [b=0.0] offset
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
function linear (a, b) {
if (!is.defined(a)) {
this.options.linearA = 1.0;
} else if (is.number(a)) {
this.options.linearA = a;
} else {
throw new Error('Invalid linear transform multiplier ' + a);
}
if (!is.defined(b)) {
this.options.linearB = 0.0;
} else if (is.number(b)) {
this.options.linearB = b;
} else {
throw new Error('Invalid linear transform offset ' + b);
}
return this;
}
/**
* Decorate the Sharp prototype with operation-related functions.
@@ -414,6 +464,7 @@ module.exports = function (Sharp) {
flip,
flop,
sharpen,
median,
blur,
extend,
flatten,
@@ -424,7 +475,8 @@ module.exports = function (Sharp) {
normalize,
convolve,
threshold,
boolean
boolean,
linear
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});

View File

@@ -1,6 +1,5 @@
'use strict';
const util = require('util');
const is = require('./is');
const sharp = require('../build/Release/sharp.node');
@@ -11,15 +10,27 @@ const sharp = require('../build/Release/sharp.node');
* with JPEG, PNG, WebP, TIFF, DZI, and libvips' V format supported.
* Note that raw pixel data is only supported for buffer output.
*
* A Promises/A+ promise is returned when `callback` is not provided.
* A `Promise` is returned when `callback` is not provided.
*
* @example
* sharp(input)
* .toFile('output.png', (err, info) => { ... });
*
* @example
* sharp(input)
* .toFile('output.png')
* .then(info => { ... })
* .catch(err => { ... });
*
* @param {String} fileOut - the path to write the image data to.
* @param {Function} [callback] - called on completion with two arguments `(err, info)`.
* `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
* `info` contains the output image `format`, `size` (bytes), `width`, `height`,
* `channels` and `premultiplied` (indicating if premultiplication was used).
* When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
* @returns {Promise<Object>} - when no callback is provided
* @throws {Error} Invalid parameters
*/
const toFile = function toFile (fileOut, callback) {
function toFile (fileOut, callback) {
if (!fileOut || fileOut.length === 0) {
const errOutputInvalid = new Error('Invalid output');
if (is.fn(callback)) {
@@ -41,36 +52,69 @@ const toFile = function toFile (fileOut, callback) {
}
}
return this;
};
}
/**
* Write output to a Buffer.
* JPEG, PNG, WebP, and RAW output are supported.
* JPEG, PNG, WebP, TIFF and RAW output are supported.
* By default, the format will match the input image, except GIF and SVG input which become PNG output.
*
* `callback`, if present, gets three arguments `(err, buffer, info)` where:
* - `err` is an error message, if any.
* - `buffer` is the output image data.
* - `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
* A Promises/A+ promise is returned when `callback` is not provided.
* `callback`, if present, gets three arguments `(err, data, info)` where:
* - `err` is an error, if any.
* - `data` is the output image data.
* - `info` contains the output image `format`, `size` (bytes), `width`, `height`,
* `channels` and `premultiplied` (indicating if premultiplication was used).
* When using a crop strategy also contains `cropOffsetLeft` and `cropOffsetTop`.
*
* A `Promise` is returned when `callback` is not provided.
*
* @example
* sharp(input)
* .toBuffer((err, data, info) => { ... });
*
* @example
* sharp(input)
* .toBuffer()
* .then(data => { ... })
* .catch(err => { ... });
*
* @example
* sharp(input)
* .toBuffer({ resolveWithObject: true })
* .then(({ data, info }) => { ... })
* .catch(err => { ... });
*
* @param {Object} [options]
* @param {Boolean} [options.resolveWithObject] Resolve the Promise with an Object containing `data` and `info` properties instead of resolving only with `data`.
* @param {Function} [callback]
* @returns {Promise<Buffer>} - when no callback is provided
*/
const toBuffer = function toBuffer (callback) {
return this._pipeline(callback);
};
function toBuffer (options, callback) {
if (is.object(options)) {
if (is.bool(options.resolveWithObject)) {
this.options.resolveWithObject = options.resolveWithObject;
}
}
return this._pipeline(is.fn(options) ? options : callback);
}
/**
* Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
* The default behaviour, when `withMetadata` is not used, is to strip all metadata and convert to the device-independent sRGB colour space.
* This will also convert to and add a web-friendly sRGB ICC profile.
*
* @example
* sharp('input.jpg')
* .withMetadata()
* .toFile('output-with-metadata.jpg')
* .then(info => { ... });
*
* @param {Object} [withMetadata]
* @param {Number} [withMetadata.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const withMetadata = function withMetadata (withMetadata) {
function withMetadata (withMetadata) {
this.options.withMetadata = is.bool(withMetadata) ? withMetadata : true;
if (is.object(withMetadata)) {
if (is.defined(withMetadata.orientation)) {
@@ -82,10 +126,20 @@ const withMetadata = function withMetadata (withMetadata) {
}
}
return this;
};
}
/**
* Use these JPEG options for output image.
*
* @example
* // Convert any input to very high quality JPEG output
* const data = await sharp(input)
* .jpeg({
* quality: 100,
* chromaSubsampling: '4:4:4'
* })
* .toBuffer();
*
* @param {Object} [options] - output options
* @param {Number} [options.quality=80] - quality, integer 1-100
* @param {Boolean} [options.progressive=false] - use progressive (interlace) scan
@@ -94,11 +148,15 @@ const withMetadata = function withMetadata (withMetadata) {
* @param {Boolean} [options.overshootDeringing=false] - apply overshoot deringing, requires mozjpeg
* @param {Boolean} [options.optimiseScans=false] - optimise progressive scans, forces progressive, requires mozjpeg
* @param {Boolean} [options.optimizeScans=false] - alternative spelling of optimiseScans
* @param {Boolean} [options.optimiseCoding=true] - optimise Huffman coding tables
* @param {Boolean} [options.optimizeCoding=true] - alternative spelling of optimiseCoding
* @param {Number} [options.quantisationTable=0] - quantization table to use, integer 0-8, requires mozjpeg
* @param {Number} [options.quantizationTable=0] - alternative spelling of quantisationTable
* @param {Boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format
* @returns {Sharp}
* @throws {Error} Invalid options
*/
const jpeg = function jpeg (options) {
function jpeg (options) {
if (is.object(options)) {
if (is.defined(options.quality)) {
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
@@ -131,21 +189,43 @@ const jpeg = function jpeg (options) {
this.options.jpegProgressive = true;
}
}
options.optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
if (is.defined(options.optimiseCoding)) {
this._setBooleanOption('jpegOptimiseCoding', options.optimiseCoding);
}
options.quantisationTable = is.number(options.quantizationTable) ? options.quantizationTable : options.quantisationTable;
if (is.defined(options.quantisationTable)) {
if (is.integer(options.quantisationTable) && is.inRange(options.quantisationTable, 0, 8)) {
this.options.jpegQuantisationTable = options.quantisationTable;
} else {
throw new Error('Invalid quantisation table (integer, 0-8) ' + options.quantisationTable);
}
}
}
return this._updateFormatOut('jpeg', options);
};
}
/**
* Use these PNG options for output image.
*
* PNG output is always full colour at 8 or 16 bits per pixel.
* Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel.
*
* @example
* // Convert any input to PNG output
* const data = await sharp(input)
* .png()
* .toBuffer();
*
* @param {Object} [options]
* @param {Boolean} [options.progressive=false] - use progressive (interlace) scan
* @param {Number} [options.compressionLevel=6] - zlib compression level
* @param {Boolean} [options.adaptiveFiltering=true] - use adaptive row filtering
* @param {Number} [options.compressionLevel=9] - zlib compression level, 0-9
* @param {Boolean} [options.adaptiveFiltering=false] - use adaptive row filtering
* @param {Boolean} [options.force=true] - force PNG output, otherwise attempt to use input format
* @returns {Sharp}
* @throws {Error} Invalid options
*/
const png = function png (options) {
function png (options) {
if (is.object(options)) {
if (is.defined(options.progressive)) {
this._setBooleanOption('pngProgressive', options.progressive);
@@ -162,17 +242,27 @@ const png = function png (options) {
}
}
return this._updateFormatOut('png', options);
};
}
/**
* Use these WebP options for output image.
*
* @example
* // Convert any input to lossless WebP output
* const data = await sharp(input)
* .webp({ lossless: true })
* .toBuffer();
*
* @param {Object} [options] - output options
* @param {Number} [options.quality=80] - quality, integer 1-100
* @param {Number} [options.alphaQuality=100] - quality of alpha layer, integer 0-100
* @param {Boolean} [options.lossless=false] - use lossless compression mode
* @param {Boolean} [options.nearLossless=false] - use near_lossless compression mode
* @param {Boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
* @returns {Sharp}
* @throws {Error} Invalid options
*/
const webp = function webp (options) {
function webp (options) {
if (is.object(options) && is.defined(options.quality)) {
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
this.options.webpQuality = options.quality;
@@ -180,18 +270,47 @@ const webp = function webp (options) {
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
}
}
if (is.object(options) && is.defined(options.alphaQuality)) {
if (is.integer(options.alphaQuality) && is.inRange(options.alphaQuality, 0, 100)) {
this.options.webpAlphaQuality = options.alphaQuality;
} else {
throw new Error('Invalid webp alpha quality (integer, 0-100) ' + options.alphaQuality);
}
}
if (is.object(options) && is.defined(options.lossless)) {
this._setBooleanOption('webpLossless', options.lossless);
}
if (is.object(options) && is.defined(options.nearLossless)) {
this._setBooleanOption('webpNearLossless', options.nearLossless);
}
return this._updateFormatOut('webp', options);
};
}
/**
* Use these TIFF options for output image.
*
* @example
* // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
* sharp('input.svg')
* .tiff({
* compression: 'lzw',
* squash: true
* })
* .toFile('1-bpp-output.tiff')
* .then(info => { ... });
*
* @param {Object} [options] - output options
* @param {Number} [options.quality=80] - quality, integer 1-100
* @param {Boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
* @param {Boolean} [options.compression='jpeg'] - compression options: lzw, deflate, jpeg, ccittfax4
* @param {Boolean} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
* @param {Number} [options.xres=1.0] - horizontal resolution in pixels/mm
* @param {Number} [options.yres=1.0] - vertical resolution in pixels/mm
* @param {Boolean} [options.squash=false] - squash 8-bit images down to 1 bit
* @returns {Sharp}
* @throws {Error} Invalid options
*/
const tiff = function tiff (options) {
function tiff (options) {
if (is.object(options) && is.defined(options.quality)) {
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
this.options.tiffQuality = options.quality;
@@ -199,39 +318,96 @@ const tiff = function tiff (options) {
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
}
}
if (is.object(options) && is.defined(options.squash)) {
if (is.bool(options.squash)) {
this.options.tiffSquash = options.squash;
} else {
throw new Error('Invalid Value for squash ' + options.squash + ' Only Boolean Values allowed for options.squash.');
}
}
// resolution
if (is.object(options) && is.defined(options.xres)) {
if (is.number(options.xres)) {
this.options.tiffXres = options.xres;
} else {
throw new Error('Invalid Value for xres ' + options.xres + ' Only numeric values allowed for options.xres');
}
}
if (is.object(options) && is.defined(options.yres)) {
if (is.number(options.yres)) {
this.options.tiffYres = options.yres;
} else {
throw new Error('Invalid Value for yres ' + options.yres + ' Only numeric values allowed for options.yres');
}
}
// compression
if (is.defined(options) && is.defined(options.compression)) {
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'ccittfax4', 'none'])) {
this.options.tiffCompression = options.compression;
} else {
const message = `Invalid compression option "${options.compression}". Should be one of: lzw, deflate, jpeg, ccittfax4, none`;
throw new Error(message);
}
}
// predictor
if (is.defined(options) && is.defined(options.predictor)) {
if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) {
this.options.tiffPredictor = options.predictor;
} else {
const message = `Invalid predictor option "${options.predictor}". Should be one of: none, horizontal, float`;
throw new Error(message);
}
}
return this._updateFormatOut('tiff', options);
};
}
/**
* Force output to be raw, uncompressed uint8 pixel data.
*
* @example
* // Extract raw RGB pixel data from JPEG input
* const { data, info } = await sharp('input.jpg')
* .raw()
* .toBuffer({ resolveWithObject: true });
*
* @returns {Sharp}
*/
const raw = function raw () {
function raw () {
return this._updateFormatOut('raw');
};
}
/**
* Force output to a given format.
*
* @example
* // Convert any input to PNG output
* const data = await sharp(input)
* .toFormat('png')
* .toBuffer();
*
* @param {(String|Object)} format - as a String or an Object with an 'id' attribute
* @param {Object} options - output options
* @returns {Sharp}
* @throws {Error} unsupported format or options
*/
const toFormat = function toFormat (format, options) {
function toFormat (format, options) {
if (is.object(format) && is.string(format.id)) {
format = format.id;
}
if (format === 'jpg') format = 'jpeg';
if (!is.inArray(format, ['jpeg', 'png', 'webp', 'tiff', 'raw'])) {
throw new Error('Unsupported output format ' + format);
}
return this[format](options);
};
}
/**
* Use tile-based deep zoom (image pyramid) output.
* Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions.
* Use a `.zip` or `.szi` file extension with `toFile` to write to a compressed archive file format.
*
* Warning: multiple sharp instances concurrently producing tile output can expose a possible race condition in some versions of libgsf.
*
* @example
* sharp('input.tiff')
* .png()
@@ -246,12 +422,14 @@ const toFormat = function toFormat (format, options) {
* @param {Object} [tile]
* @param {Number} [tile.size=256] tile size in pixels, a value between 1 and 8192.
* @param {Number} [tile.overlap=0] tile overlap in pixels, a value between 0 and 8192.
* @param {Number} [tile.angle=0] tile angle of rotation, must be a multiple of 90.
* @param {String} [tile.depth] how deep to make the pyramid, possible values are `onepixel`, `onetile` or `one`, default based on layout.
* @param {String} [tile.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
* @param {String} [tile.layout='dz'] filesystem layout, possible values are `dz`, `zoomify` or `google`.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const tile = function tile (tile) {
function tile (tile) {
if (is.object(tile)) {
// Size of square tiles, in pixels
if (is.defined(tile.size)) {
@@ -288,6 +466,24 @@ const tile = function tile (tile) {
throw new Error('Invalid tile layout ' + tile.layout);
}
}
// Angle of rotation,
if (is.defined(tile.angle)) {
if (is.integer(tile.angle) && !(tile.angle % 90)) {
this.options.tileAngle = tile.angle;
} else {
throw new Error('Unsupported angle: angle must be a positive/negative multiple of 90 ' + tile.angle);
}
}
// Depth of tiles
if (is.defined(tile.depth)) {
if (is.string(tile.depth) && is.inArray(tile.depth, ['onepixel', 'onetile', 'one'])) {
this.options.tileDepth = tile.depth;
} else {
throw new Error("Invalid tile depth '" + tile.depth + "', should be one of 'onepixel', 'onetile' or 'one'");
}
}
}
// Format
if (is.inArray(this.options.formatOut, ['jpeg', 'png', 'webp'])) {
@@ -295,8 +491,9 @@ const tile = function tile (tile) {
} else if (this.options.formatOut !== 'input') {
throw new Error('Invalid tile format ' + this.options.formatOut);
}
return this._updateFormatOut('dz');
};
}
/**
* Update the output format unless options.force is false,
@@ -307,10 +504,10 @@ const tile = function tile (tile) {
* @param {Boolean} [options.force=true] - force output format, otherwise attempt to use input format
* @returns {Sharp}
*/
const _updateFormatOut = function _updateFormatOut (formatOut, options) {
function _updateFormatOut (formatOut, options) {
this.options.formatOut = (is.object(options) && options.force === false) ? 'input' : formatOut;
return this;
};
}
/**
* Update a Boolean attribute of the this.options Object.
@@ -319,31 +516,31 @@ const _updateFormatOut = function _updateFormatOut (formatOut, options) {
* @param {Boolean} val
* @throws {Error} Invalid key
*/
const _setBooleanOption = function _setBooleanOption (key, val) {
function _setBooleanOption (key, val) {
if (is.bool(val)) {
this.options[key] = val;
} else {
throw new Error('Invalid ' + key + ' (boolean) ' + val);
}
};
}
/**
* Called by a WriteableStream to notify us it is ready for data.
* @private
*/
const _read = function _read () {
function _read () {
if (!this.options.streamOut) {
this.options.streamOut = true;
this._pipeline();
}
};
}
/**
* Invoke the C++ image processing pipeline
* Supports callback, stream and promise variants
* @private
*/
const _pipeline = function _pipeline (callback) {
function _pipeline (callback) {
const that = this;
if (typeof callback === 'function') {
// output=file/buffer
@@ -362,9 +559,9 @@ const _pipeline = function _pipeline (callback) {
// output=stream
if (this._isStreamInput()) {
// output=stream, input=stream
this.on('finish', function () {
that._flattenBufferIn();
sharp.pipeline(that.options, function (err, data, info) {
if (this.streamInFinished) {
this._flattenBufferIn();
sharp.pipeline(this.options, function (err, data, info) {
if (err) {
that.emit('error', err);
} else {
@@ -373,7 +570,20 @@ const _pipeline = function _pipeline (callback) {
}
that.push(null);
});
});
} else {
this.on('finish', function () {
that._flattenBufferIn();
sharp.pipeline(that.options, function (err, data, info) {
if (err) {
that.emit('error', err);
} else {
that.emit('info', info);
that.push(data);
}
that.push(null);
});
});
}
} else {
// output=stream, input=file/buffer
sharp.pipeline(this.options, function (err, data, info) {
@@ -394,11 +604,15 @@ const _pipeline = function _pipeline (callback) {
return new Promise(function (resolve, reject) {
that.on('finish', function () {
that._flattenBufferIn();
sharp.pipeline(that.options, function (err, data) {
sharp.pipeline(that.options, function (err, data, info) {
if (err) {
reject(err);
} else {
resolve(data);
if (that.options.resolveWithObject) {
resolve({ data: data, info: info });
} else {
resolve(data);
}
}
});
});
@@ -406,77 +620,21 @@ const _pipeline = function _pipeline (callback) {
} else {
// output=promise, input=file/buffer
return new Promise(function (resolve, reject) {
sharp.pipeline(that.options, function (err, data) {
sharp.pipeline(that.options, function (err, data, info) {
if (err) {
reject(err);
} else {
resolve(data);
if (that.options.resolveWithObject) {
resolve({ data: data, info: info });
} else {
resolve(data);
}
}
});
});
}
}
};
// Deprecated output options
/* istanbul ignore next */
const quality = util.deprecate(function (quality) {
const formatOut = this.options.formatOut;
const options = { quality: quality };
this.jpeg(options).webp(options).tiff(options);
this.options.formatOut = formatOut;
return this;
}, 'quality: use jpeg({ quality: ... }), webp({ quality: ... }) and/or tiff({ quality: ... }) instead');
/* istanbul ignore next */
const progressive = util.deprecate(function (progressive) {
const formatOut = this.options.formatOut;
const options = { progressive: (progressive !== false) };
this.jpeg(options).png(options);
this.options.formatOut = formatOut;
return this;
}, 'progressive: use jpeg({ progressive: ... }) and/or png({ progressive: ... }) instead');
/* istanbul ignore next */
const compressionLevel = util.deprecate(function (compressionLevel) {
const formatOut = this.options.formatOut;
this.png({ compressionLevel: compressionLevel });
this.options.formatOut = formatOut;
return this;
}, 'compressionLevel: use png({ compressionLevel: ... }) instead');
/* istanbul ignore next */
const withoutAdaptiveFiltering = util.deprecate(function (withoutAdaptiveFiltering) {
const formatOut = this.options.formatOut;
this.png({ adaptiveFiltering: (withoutAdaptiveFiltering === false) });
this.options.formatOut = formatOut;
return this;
}, 'withoutAdaptiveFiltering: use png({ adaptiveFiltering: ... }) instead');
/* istanbul ignore next */
const withoutChromaSubsampling = util.deprecate(function (withoutChromaSubsampling) {
const formatOut = this.options.formatOut;
this.jpeg({ chromaSubsampling: (withoutChromaSubsampling === false) ? '4:2:0' : '4:4:4' });
this.options.formatOut = formatOut;
return this;
}, 'withoutChromaSubsampling: use jpeg({ chromaSubsampling: "4:4:4" }) instead');
/* istanbul ignore next */
const trellisQuantisation = util.deprecate(function (trellisQuantisation) {
const formatOut = this.options.formatOut;
this.jpeg({ trellisQuantisation: (trellisQuantisation !== false) });
this.options.formatOut = formatOut;
return this;
}, 'trellisQuantisation: use jpeg({ trellisQuantisation: ... }) instead');
/* istanbul ignore next */
const overshootDeringing = util.deprecate(function (overshootDeringing) {
const formatOut = this.options.formatOut;
this.jpeg({ overshootDeringing: (overshootDeringing !== false) });
this.options.formatOut = formatOut;
return this;
}, 'overshootDeringing: use jpeg({ overshootDeringing: ... }) instead');
/* istanbul ignore next */
const optimiseScans = util.deprecate(function (optimiseScans) {
const formatOut = this.options.formatOut;
this.jpeg({ optimiseScans: (optimiseScans !== false) });
this.options.formatOut = formatOut;
return this;
}, 'optimiseScans: use jpeg({ optimiseScans: ... }) instead');
}
/**
* Decorate the Sharp prototype with output-related functions.
@@ -503,15 +661,4 @@ module.exports = function (Sharp) {
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});
// Deprecated
Sharp.prototype.quality = quality;
Sharp.prototype.progressive = progressive;
Sharp.prototype.compressionLevel = compressionLevel;
Sharp.prototype.withoutAdaptiveFiltering = withoutAdaptiveFiltering;
Sharp.prototype.withoutChromaSubsampling = withoutChromaSubsampling;
Sharp.prototype.trellisQuantisation = trellisQuantisation;
Sharp.prototype.trellisQuantization = trellisQuantisation;
Sharp.prototype.overshootDeringing = overshootDeringing;
Sharp.prototype.optimiseScans = optimiseScans;
Sharp.prototype.optimizeScans = optimiseScans;
};

15
lib/platform.js Normal file
View File

@@ -0,0 +1,15 @@
'use strict';
module.exports = function () {
const arch = process.env.npm_config_arch || process.arch;
const platform = process.env.npm_config_platform || process.platform;
const platformId = [platform];
if (arch === 'arm' || arch === 'armhf' || arch === 'arm64') {
const armVersion = (arch === 'arm64') ? '8' : process.env.npm_config_armv || process.config.variables.arm_version || '6';
platformId.push(`armv${armVersion}`);
} else {
platformId.push(arch);
}
return platformId.join('-');
};

View File

@@ -36,84 +36,59 @@ const strategy = {
* @private
*/
const kernel = {
nearest: 'nearest',
cubic: 'cubic',
lanczos2: 'lanczos2',
lanczos3: 'lanczos3'
};
/**
* Enlargement interpolators.
* @member
* @private
*/
const interpolator = {
nearest: 'nearest',
bilinear: 'bilinear',
bicubic: 'bicubic',
nohalo: 'nohalo',
lbb: 'lbb',
locallyBoundedBicubic: 'lbb',
vsqbs: 'vsqbs',
vertexSplitQuadraticBasisSpline: 'vsqbs'
};
/**
* Resize image to `width` x `height`.
* By default, the resized image is centre cropped to the exact size specified.
*
* Possible reduction kernels are:
* Possible kernels are:
* - `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
* - `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
*
* Possible enlargement interpolators are:
* - `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
* - `bilinear`: Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation), faster than bicubic but with less smooth results.
* - `vertexSplitQuadraticBasisSpline`: Use the smoother [VSQBS interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48) to prevent "staircasing" when enlarging.
* - `bicubic`: Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default).
* - `locallyBoundedBicubic`: Use [LBB interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100), which prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2.
* - `nohalo`: Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/), which prevents acutance but typically reduces performance by a factor of 3.
*
* @example
* sharp(inputBuffer)
* .resize(200, 300, {
* kernel: sharp.kernel.lanczos2,
* interpolator: sharp.interpolator.nohalo
* kernel: sharp.kernel.nearest
* })
* .background('white')
* .embed()
* .toFile('output.tiff')
* .then(function() {
* // output.tiff is a 200 pixels wide and 300 pixels high image
* // containing a lanczos2/nohalo scaled version, embedded on a white canvas,
* // containing a nearest-neighbour scaled version, embedded on a white canvas,
* // of the image data in inputBuffer
* });
*
* @param {Number} [width] - pixels wide the resultant image should be, between 1 and 16383 (0x3FFF). Use `null` or `undefined` to auto-scale the width to match the height.
* @param {Number} [height] - pixels high the resultant image should be, between 1 and 16383. Use `null` or `undefined` to auto-scale the height to match the width.
* @param {Number} [width] - pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
* @param {Number} [height] - pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
* @param {Object} [options]
* @param {String} [options.kernel='lanczos3'] - the kernel to use for image reduction.
* @param {String} [options.interpolator='bicubic'] - the interpolator to use for image enlargement.
* @param {Boolean} [options.centreSampling=false] - use *magick centre sampling convention instead of corner sampling.
* @param {Boolean} [options.centerSampling=false] - alternative spelling of centreSampling.
* @param {Boolean} [options.fastShrinkOnLoad=true] - take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern on some images.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const resize = function resize (width, height, options) {
function resize (width, height, options) {
if (is.defined(width)) {
if (is.integer(width) && is.inRange(width, 1, this.constructor.maximum.width)) {
if (is.integer(width) && width > 0) {
this.options.width = width;
} else {
throw new Error('Invalid width (1 to ' + this.constructor.maximum.width + ') ' + width);
throw is.invalidParameterError('width', 'positive integer', width);
}
} else {
this.options.width = -1;
}
if (is.defined(height)) {
if (is.integer(height) && is.inRange(height, 1, this.constructor.maximum.height)) {
if (is.integer(height) && height > 0) {
this.options.height = height;
} else {
throw new Error('Invalid height (1 to ' + this.constructor.maximum.height + ') ' + height);
throw is.invalidParameterError('height', 'positive integer', height);
}
} else {
this.options.height = -1;
@@ -124,25 +99,16 @@ const resize = function resize (width, height, options) {
if (is.string(kernel[options.kernel])) {
this.options.kernel = kernel[options.kernel];
} else {
throw new Error('Invalid kernel ' + options.kernel);
throw is.invalidParameterError('kernel', 'valid kernel name', options.kernel);
}
}
// Interpolator
if (is.defined(options.interpolator)) {
if (is.string(interpolator[options.interpolator])) {
this.options.interpolator = interpolator[options.interpolator];
} else {
throw new Error('Invalid interpolator ' + options.interpolator);
}
}
// Centre sampling
options.centreSampling = is.bool(options.centerSampling) ? options.centerSampling : options.centreSampling;
if (is.defined(options.centreSampling)) {
this._setBooleanOption('centreSampling', options.centreSampling);
// Shrink on load
if (is.defined(options.fastShrinkOnLoad)) {
this._setBooleanOption('fastShrinkOnLoad', options.fastShrinkOnLoad);
}
}
return this;
};
}
/**
* Crop the resized image to the exact size specified, the default behaviour.
@@ -170,7 +136,7 @@ const resize = function resize (width, height, options) {
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const crop = function crop (crop) {
function crop (crop) {
this.options.canvas = 'crop';
if (!is.defined(crop)) {
// Default
@@ -184,11 +150,14 @@ const crop = function crop (crop) {
} else if (is.integer(crop) && crop >= strategy.entropy) {
// Strategy
this.options.crop = crop;
} else if (is.string(crop) && is.integer(strategy[crop])) {
// Strategy (string)
this.options.crop = strategy[crop];
} else {
throw new Error('Unsupported crop ' + crop);
throw is.invalidParameterError('crop', 'valid crop id/name/strategy', crop);
}
return this;
};
}
/**
* Preserving aspect ratio, resize the image to the maximum `width` or `height` specified
@@ -200,7 +169,7 @@ const crop = function crop (crop) {
* @example
* sharp('input.gif')
* .resize(200, 300)
* .background({r: 0, g: 0, b: 0, a: 0})
* .background({r: 0, g: 0, b: 0, alpha: 0})
* .embed()
* .toFormat(sharp.format.webp)
* .toBuffer(function(err, outputBuffer) {
@@ -210,13 +179,28 @@ const crop = function crop (crop) {
* // outputBuffer contains WebP image data of a 200 pixels wide and 300 pixels high
* // containing a scaled version, embedded on a transparent canvas, of input.gif
* });
*
* @param {String} [embed='centre'] - A member of `sharp.gravity` to embed to an edge/corner.
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
const embed = function embed () {
function embed (embed) {
this.options.canvas = 'embed';
if (!is.defined(embed)) {
// Default
this.options.embed = gravity.center;
} else if (is.integer(embed) && is.inRange(embed, 0, 8)) {
// Gravity (numeric)
this.options.embed = embed;
} else if (is.string(embed) && is.integer(gravity[embed])) {
// Gravity (string)
this.options.embed = gravity[embed];
} else {
throw is.invalidParameterError('embed', 'valid embed id/name', embed);
}
return this;
};
}
/**
* Preserving aspect ratio, resize the image to be as large as possible
@@ -237,10 +221,10 @@ const embed = function embed () {
*
* @returns {Sharp}
*/
const max = function max () {
function max () {
this.options.canvas = 'max';
return this;
};
}
/**
* Preserving aspect ratio, resize the image to be as small as possible
@@ -250,32 +234,36 @@ const max = function max () {
*
* @returns {Sharp}
*/
const min = function min () {
function min () {
this.options.canvas = 'min';
return this;
};
}
/**
* Ignoring the aspect ratio of the input, stretch the image to
* the exact `width` and/or `height` provided via `resize`.
* @returns {Sharp}
*/
const ignoreAspectRatio = function ignoreAspectRatio () {
function ignoreAspectRatio () {
this.options.canvas = 'ignore_aspect';
return this;
};
}
/**
* Do not enlarge the output image if the input image width *or* height are already less than the required dimensions.
* This is equivalent to GraphicsMagick's `>` geometry option:
* "*change the dimensions of the image only if its width or height exceeds the geometry specification*".
* Use with `max()` to preserve the image's aspect ratio.
*
* The default behaviour *before* function call is `false`, meaning the image will be enlarged.
*
* @param {Boolean} [withoutEnlargement=true]
* @returns {Sharp}
*/
const withoutEnlargement = function withoutEnlargement (withoutEnlargement) {
function withoutEnlargement (withoutEnlargement) {
this.options.withoutEnlargement = is.bool(withoutEnlargement) ? withoutEnlargement : true;
return this;
};
}
/**
* Decorate the Sharp prototype with resize-related functions.
@@ -297,5 +285,4 @@ module.exports = function (Sharp) {
Sharp.gravity = gravity;
Sharp.strategy = strategy;
Sharp.kernel = kernel;
Sharp.interpolator = interpolator;
};

View File

@@ -4,7 +4,7 @@ const is = require('./is');
const sharp = require('../build/Release/sharp.node');
/**
* Gets, or when options are provided sets, the limits of _libvips'_ operation cache.
* Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
* Existing entries in the cache will be trimmed after any change in limits.
* This method always returns cache statistics,
* useful for determining how much working memory is required for a particular task.
@@ -16,13 +16,13 @@ const sharp = require('../build/Release/sharp.node');
* sharp.cache( { files: 0 } );
* sharp.cache(false);
*
* @param {Object|Boolean} options - Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching.
* @param {Object|Boolean} [options=true] - Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching
* @param {Number} [options.memory=50] - is the maximum memory in MB to use for this cache
* @param {Number} [options.files=20] - is the maximum number of files to hold open
* @param {Number} [options.items=100] - is the maximum number of operations to cache
* @returns {Object}
*/
const cache = function cache (options) {
function cache (options) {
if (is.bool(options)) {
if (options) {
// Default cache settings of 50MB, 20 files, 100 items
@@ -35,11 +35,11 @@ const cache = function cache (options) {
} else {
return sharp.cache();
}
};
}
cache(true);
/**
* Gets, or when a concurrency is provided sets,
* Gets or, when a concurrency is provided, sets
* the number of threads _libvips'_ should create to process each image.
* The default value is the number of CPU cores.
* A value of `0` will reset to this default.
@@ -57,9 +57,9 @@ cache(true);
* @param {Number} [concurrency]
* @returns {Number} concurrency
*/
const concurrency = function concurrency (concurrency) {
function concurrency (concurrency) {
return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
};
}
/**
* Provides access to internal task counters.
@@ -71,9 +71,9 @@ const concurrency = function concurrency (concurrency) {
*
* @returns {Object}
*/
const counters = function counters () {
function counters () {
return sharp.counters();
};
}
/**
* Get and set use of SIMD vector unit instructions.
@@ -95,9 +95,9 @@ const counters = function counters () {
* @param {Boolean} [simd=false]
* @returns {Boolean}
*/
const simd = function simd (simd) {
function simd (simd) {
return sharp.simd(is.bool(simd) ? simd : null);
};
}
simd(false);
/**

View File

@@ -1,14 +1,15 @@
site_name: sharp
site_url: http://sharp.dimens.io/
site_url: http://sharp.pixelplumbing.com/
repo_url: https://github.com/lovell/sharp
site_description: High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images
copyright: <a href="https://dimens.io/">dimens.io</a>
google_analytics: ['UA-13034748-12', 'sharp.dimens.io']
copyright: <a href="https://pixelplumbing.com/">pixelplumbing.com</a>
google_analytics: ['UA-13034748-12', 'sharp.pixelplumbing.com']
theme: readthedocs
extra_css:
- css/extra.css
markdown_extensions:
- toc:
permalink: True
dev_addr: 0.0.0.0:10101
pages:
- Home: index.md
- Installation: install.md

View File

@@ -1,8 +1,9 @@
{
"name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
"version": "0.17.0",
"version": "0.20.8",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp",
"contributors": [
"Pierre Inglebert <pierre.inglebert@gmail.com>",
"Jonathan Ong <jonathanrichardong@gmail.com>",
@@ -29,14 +30,39 @@
"Kleis Auke Wolthuizen <info@kleisauke.nl>",
"Matt Hirsch <mhirsch@media.mit.edu>",
"Matthias Thoemmes <thoemmes@gmail.com>",
"Patrick Paskaris <patrick@paskaris.gr>"
"Patrick Paskaris <patrick@paskaris.gr>",
"Jérémy Lal <kapouer@melix.org>",
"Rahul Nanwani <r.nanwani@gmail.com>",
"Alice Monday <alice0meta@gmail.com>",
"Kristo Jorgenson <kristo.jorgenson@gmail.com>",
"YvesBos <yves_bos@outlook.com>",
"Guy Maliar <guy@tailorbrands.com>",
"Nicolas Coden <nicolas@ncoden.fr>",
"Matt Parrish <matt.r.parrish@gmail.com>",
"Marcel Bretschneider <marcel.bretschneider@gmail.com>",
"Matthew McEachen <matthew+github@mceachen.org>",
"Jarda Kotěšovec <jarda.kotesovec@gmail.com>",
"Kenric D'Souza <kenric.dsouza@gmail.com>",
"Oleh Aleinyk <oleg.aleynik@gmail.com>",
"Marcel Bretschneider <marcel.bretschneider@gmail.com>",
"Andrea Bianco <andrea.bianco@unibas.ch>",
"Rik Heywood <rik@rik.org>",
"Thomas Parisot <hi@oncletom.io>",
"Nathan Graves <nathanrgraves+github@gmail.com>",
"Tom Lokhorst <tom@lokhorst.eu>",
"Espen Hovlandsdal <espen@hovlandsdal.com>",
"Sylvain Dumont <sylvain.dumont35@gmail.com>",
"Alun Davies <alun.owain.davies@googlemail.com>",
"Aidan Hoolachan <ajhoolachan21@gmail.com>",
"Axel Eirola <axel.eirola@iki.fi>"
],
"scripts": {
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
"test": "semistandard && cross-env VIPS_WARNING=0 nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
"test": "semistandard && cc && nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js && prebuild-ci",
"coverage": "./test/coverage/report.sh",
"test-leak": "./test/leak/leak.sh",
"test-packaging": "./packaging/test-linux-x64.sh",
"docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md lib/$m.js >docs/api-$m.md; done"
"docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done"
},
"main": "lib/index.js",
"repository": {
@@ -55,41 +81,56 @@
"resize",
"thumbnail",
"crop",
"embed",
"libvips",
"vips"
],
"dependencies": {
"caw": "^2.0.0",
"color": "^1.0.2",
"got": "^6.6.3",
"nan": "^2.4.0",
"semver": "^5.3.0",
"tar": "^2.2.1"
"color": "^3.0.0",
"detect-libc": "^1.0.3",
"nan": "^2.11.0",
"fs-copy-file-sync": "^1.1.1",
"npmlog": "^4.1.2",
"prebuild-install": "^4.0.0",
"semver": "^5.5.1",
"simple-get": "^2.8.1",
"tar": "^4.4.6",
"tunnel-agent": "^0.6.0"
},
"devDependencies": {
"async": "^2.1.4",
"bufferutil": "^1.3.0",
"cross-env": "^3.1.3",
"documentation": "^4.0.0-beta16",
"exif-reader": "^1.0.1",
"icc": "^0.0.2",
"mocha": "^3.2.0",
"node-cpplint": "^0.4.0",
"nyc": "^10.0.0",
"rimraf": "^2.5.4",
"semistandard": "^9.2.1",
"unzip": "^0.1.11"
"async": "^2.6.1",
"cc": "^1.0.2",
"decompress-zip": "^0.3.1",
"documentation": "^8.1.2",
"exif-reader": "^1.0.2",
"icc": "^1.0.0",
"mocha": "^5.2.0",
"mock-fs": "^4.6.0",
"nyc": "^12.0.1",
"prebuild": "^7.6.2",
"prebuild-ci": "^2.2.3",
"rimraf": "^2.6.2",
"semistandard": "^12.0.1"
},
"license": "Apache-2.0",
"config": {
"libvips": "8.4.2"
"libvips": "8.6.1"
},
"engines": {
"node": ">=4"
"node": ">=4.5.0"
},
"semistandard": {
"env": [
"mocha"
]
},
"cc": {
"linelength": "120",
"filter": [
"build/c++11",
"build/include",
"runtime/indentation_namespace",
"runtime/references"
]
}
}

View File

@@ -1,57 +0,0 @@
# Packaging scripts
libvips and its dependencies are provided as pre-compiled shared libraries
for the most common operating systems and CPU architectures.
During `npm install`, these binaries are fetched as tarballs from
[Bintray](https://dl.bintray.com/lovell/sharp/) via HTTPS
and stored locally within `node_modules/sharp`.
## Using a custom tarball
A custom tarball stored on the local filesystem can be used instead.
Place it in the following location, where `x.y.z` is the libvips version,
`platform` is the value of `process.platform` and
`arch` is the value of `process.arch` (plus the version number for ARM).
`node_modules/sharp/packaging/libvips-x.y.z-platform-arch.tar.gz`
For example, for libvips v8.3.3 on an ARMv6 Linux machine, use:
`node_modules/sharp/packaging/libvips-8.3.3-linux-armv6.tar.gz`
Remove any `sharp/lib` and `sharp/include` directories
before running `npm install` again.
## Creating a tarball
Most people will not need to do this; proceed with caution.
The `packaging` directory contains the top-level [build script](build.sh).
### Linux
One [build script](build/lin.sh) is used to (cross-)compile
the same shared libraries within multiple containers.
* [x64](linux-x64/Dockerfile)
* [ARMv6](linux-armv6/Dockerfile)
* [ARMv7-A](linux-armv7/Dockerfile)
* [ARMv8-A](linux-armv8/Dockerfile)
The QEMU user mode emulation binaries are required to build for
the ARMv6 platform as the Debian armhf cross-compiler erroneously
generates unsupported Thumb 2 instructions.
```sh
sudo apt-get install qemu-user-static
```
### Windows
The output of libvips' [build-win64](https://github.com/jcupitt/build-win64)
"web" target is [post-processed](build/win.sh) within a [container](win32-x64/Dockerfile).
### OS X
See [package-libvips-darwin](https://github.com/lovell/package-libvips-darwin).

View File

@@ -1,43 +0,0 @@
#!/bin/sh
set -e
if [ $# -lt 1 ]; then
echo
echo "Usage: $0 VERSION [PLATFORM]"
echo "Build shared libraries for libvips and its dependencies via containers"
echo
echo "Please specify the libvips VERSION, e.g. 8.3.3"
echo
echo "Optionally build for only one PLATFORM, defaults to building for all"
echo "Possible values for PLATFORM are: win32-x64, linux-x64, linux-armv6,"
echo "linux-armv7, linux-armv8"
echo
exit 1
fi
VERSION_VIPS="$1"
PLATFORM="${2:-all}"
# Is docker available?
if ! type docker >/dev/null; then
echo "Please install docker"
exit 1
fi
# Windows (x64)
if [ $PLATFORM = "all" ] || [ $PLATFORM = "win32-x64" ]; then
echo "Building win32-x64..."
docker build -t vips-dev-win32-x64 win32-x64
docker run --rm -e "VERSION_VIPS=${VERSION_VIPS}" -v $PWD:/packaging vips-dev-win32-x64 sh -c "/packaging/build/win.sh"
fi
# Linux (x64, ARMv6, ARMv7, ARMv8)
for flavour in linux-x64 linux-armv6 linux-armv7 linux-armv8; do
if [ $PLATFORM = "all" ] || [ $PLATFORM = $flavour ]; then
echo "Building $flavour..."
docker build -t vips-dev-$flavour $flavour
docker run --rm -e "VERSION_VIPS=${VERSION_VIPS}" -v $PWD:/packaging vips-dev-$flavour sh -c "/packaging/build/lin.sh"
fi
done
# Display checksums
sha256sum *.tar.gz

View File

@@ -1,239 +0,0 @@
#!/bin/sh
set -e
# Working directories
DEPS=/deps
TARGET=/target
mkdir ${DEPS}
mkdir ${TARGET}
# Common build paths and flags
export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:${TARGET}/lib/pkgconfig"
export PATH="${PATH}:${TARGET}/bin"
export CPPFLAGS="-I${TARGET}/include"
export LDFLAGS="-L${TARGET}/lib"
export CFLAGS="${FLAGS}"
export CXXFLAGS="${FLAGS}"
# Dependency version numbers
VERSION_ZLIB=1.2.8
VERSION_FFI=3.2.1
VERSION_GLIB=2.50.1
VERSION_XML2=2.9.4
VERSION_GSF=1.14.40
VERSION_EXIF=0.6.21
VERSION_LCMS2=2.8
VERSION_JPEG=1.5.1
VERSION_PNG16=1.6.25
VERSION_WEBP=0.5.1
VERSION_TIFF=4.0.6
VERSION_ORC=0.4.26
VERSION_GDKPIXBUF=2.36.0
VERSION_FREETYPE=2.7
VERSION_FONTCONFIG=2.12.1
VERSION_HARFBUZZ=1.3.2
VERSION_PIXMAN=0.34.0
VERSION_CAIRO=1.14.6
VERSION_PANGO=1.40.3
VERSION_CROCO=0.6.11
VERSION_SVG=2.40.16
VERSION_GIF=5.1.4
# Least out-of-sync Sourceforge mirror
SOURCEFORGE_MIRROR=netix
mkdir ${DEPS}/zlib
curl -Ls http://zlib.net/zlib-${VERSION_ZLIB}.tar.xz | tar xJC ${DEPS}/zlib --strip-components=1
cd ${DEPS}/zlib
./configure --prefix=${TARGET} --uname=linux
make install
rm ${TARGET}/lib/libz.a
mkdir ${DEPS}/ffi
curl -Ls ftp://sourceware.org/pub/libffi/libffi-${VERSION_FFI}.tar.gz | tar xzC ${DEPS}/ffi --strip-components=1
cd ${DEPS}/ffi
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-builddir
make install-strip
mkdir ${DEPS}/glib
curl -Ls https://download.gnome.org/sources/glib/2.50/glib-${VERSION_GLIB}.tar.xz | tar xJC ${DEPS}/glib --strip-components=1
cd ${DEPS}/glib
echo glib_cv_stack_grows=no >>glib.cache
echo glib_cv_uscore=no >>glib.cache
./configure --cache-file=glib.cache --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --with-pcre=internal --disable-libmount
make install-strip
mkdir ${DEPS}/xml2
curl -Ls http://xmlsoft.org/sources/libxml2-${VERSION_XML2}.tar.gz | tar xzC ${DEPS}/xml2 --strip-components=1
cd ${DEPS}/xml2
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking \
--without-python --without-debug --without-docbook --without-ftp --without-html --without-legacy \
--without-pattern --without-push --without-regexps --without-schemas --without-schematron --with-zlib=${TARGET}
make install-strip
mkdir ${DEPS}/gsf
curl -Ls https://download.gnome.org/sources/libgsf/1.14/libgsf-${VERSION_GSF}.tar.xz | tar xJC ${DEPS}/gsf --strip-components=1
cd ${DEPS}/gsf
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/exif
curl -Ls http://${SOURCEFORGE_MIRROR}.dl.sourceforge.net/project/libexif/libexif/${VERSION_EXIF}/libexif-${VERSION_EXIF}.tar.bz2 | tar xjC ${DEPS}/exif --strip-components=1
cd ${DEPS}/exif
autoreconf -fiv
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/lcms2
curl -Ls http://${SOURCEFORGE_MIRROR}.dl.sourceforge.net/project/lcms/lcms/${VERSION_LCMS2}/lcms2-${VERSION_LCMS2}.tar.gz | tar xzC ${DEPS}/lcms2 --strip-components=1
cd ${DEPS}/lcms2
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/jpeg
curl -Ls https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${VERSION_JPEG}.tar.gz | tar xzC ${DEPS}/jpeg --strip-components=1
cd ${DEPS}/jpeg
autoreconf -fiv
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --with-jpeg8 --without-turbojpeg
make install-strip
mkdir ${DEPS}/png16
curl -Ls http://${SOURCEFORGE_MIRROR}.dl.sourceforge.net/project/libpng/libpng16/${VERSION_PNG16}/libpng-${VERSION_PNG16}.tar.xz | tar xJC ${DEPS}/png16 --strip-components=1
cd ${DEPS}/png16
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/webp
curl -Ls http://downloads.webmproject.org/releases/webp/libwebp-${VERSION_WEBP}.tar.gz | tar xzC ${DEPS}/webp --strip-components=1
cd ${DEPS}/webp
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-neon
make install-strip
mkdir ${DEPS}/tiff
curl -Ls http://download.osgeo.org/libtiff/tiff-${VERSION_TIFF}.tar.gz | tar xzC ${DEPS}/tiff --strip-components=1
cd ${DEPS}/tiff
# Apply patches for various libtiff security vulnerabilities reported since v4.0.6
VERSION_TIFF_GIT_MASTER_SHA=$(curl -Ls https://api.github.com/repos/vadz/libtiff/git/refs/heads/master | jq -r '.object.sha' | head -c7)
curl -Ls https://github.com/vadz/libtiff/compare/Release-v4-0-6...master.patch | patch -p1 -t || true
if [ -n "${CHOST}" ]; then autoreconf -fiv; fi
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-mdi --disable-pixarlog --disable-cxx
make install-strip
mkdir ${DEPS}/orc
curl -Ls http://gstreamer.freedesktop.org/data/src/orc/orc-${VERSION_ORC}.tar.xz | tar xJC ${DEPS}/orc --strip-components=1
cd ${DEPS}/orc
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
cd ${TARGET}/lib
rm -rf liborc-test-*
mkdir ${DEPS}/gdkpixbuf
curl -Ls https://download.gnome.org/sources/gdk-pixbuf/2.36/gdk-pixbuf-${VERSION_GDKPIXBUF}.tar.xz | tar xJC ${DEPS}/gdkpixbuf --strip-components=1
cd ${DEPS}/gdkpixbuf
LD_LIBRARY_PATH=${TARGET}/lib \
./configure --cache-file=gdkpixbuf.cache --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-introspection --disable-modules --disable-gio-sniffing --without-libtiff --without-gdiplus --with-included-loaders=png,jpeg
make install-strip
mkdir ${DEPS}/freetype
curl -Ls http://${SOURCEFORGE_MIRROR}.dl.sourceforge.net/project/freetype/freetype2/${VERSION_FREETYPE}/freetype-${VERSION_FREETYPE}.tar.gz | tar xzC ${DEPS}/freetype --strip-components=1
cd ${DEPS}/freetype
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static
make install
mkdir ${DEPS}/fontconfig
curl -Ls https://www.freedesktop.org/software/fontconfig/release/fontconfig-${VERSION_FONTCONFIG}.tar.bz2 | tar xjC ${DEPS}/fontconfig --strip-components=1
cd ${DEPS}/fontconfig
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --enable-libxml2 --sysconfdir=/etc
make install-strip
mkdir ${DEPS}/harfbuzz
curl -Ls https://www.freedesktop.org/software/harfbuzz/release/harfbuzz-${VERSION_HARFBUZZ}.tar.bz2 | tar xjC ${DEPS}/harfbuzz --strip-components=1
cd ${DEPS}/harfbuzz
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/pixman
curl -Ls http://cairographics.org/releases/pixman-${VERSION_PIXMAN}.tar.gz | tar xzC ${DEPS}/pixman --strip-components=1
cd ${DEPS}/pixman
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-libpng --disable-arm-iwmmxt
make install-strip
mkdir ${DEPS}/cairo
curl -Ls http://cairographics.org/releases/cairo-${VERSION_CAIRO}.tar.xz | tar xJC ${DEPS}/cairo --strip-components=1
cd ${DEPS}/cairo
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking \
--disable-xlib --disable-xcb --disable-quartz --disable-win32 --disable-egl --disable-glx --disable-wgl \
--disable-script --disable-ps --disable-gobject --disable-trace --disable-interpreter
make install-strip
mkdir ${DEPS}/pango
curl -Ls https://download.gnome.org/sources/pango/1.40/pango-${VERSION_PANGO}.tar.xz | tar xJC ${DEPS}/pango --strip-components=1
cd ${DEPS}/pango
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/croco
curl -Ls https://download.gnome.org/sources/libcroco/0.6/libcroco-${VERSION_CROCO}.tar.xz | tar xJC ${DEPS}/croco --strip-components=1
cd ${DEPS}/croco
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/svg
curl -Ls https://download.gnome.org/sources/librsvg/2.40/librsvg-${VERSION_SVG}.tar.xz | tar xJC ${DEPS}/svg --strip-components=1
cd ${DEPS}/svg
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking --disable-introspection --disable-tools --disable-pixbuf-loader
make install-strip
mkdir ${DEPS}/gif
curl -Ls http://${SOURCEFORGE_MIRROR}.dl.sourceforge.net/project/giflib/giflib-${VERSION_GIF}.tar.gz | tar xzC ${DEPS}/gif --strip-components=1
cd ${DEPS}/gif
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking
make install-strip
mkdir ${DEPS}/vips
curl -Ls http://www.vips.ecs.soton.ac.uk/supported/8.4/vips-${VERSION_VIPS}.tar.gz | tar xzC ${DEPS}/vips --strip-components=1
cd ${DEPS}/vips
./configure --host=${CHOST} --prefix=${TARGET} --enable-shared --disable-static --disable-dependency-tracking \
--disable-debug --disable-introspection --without-python --without-fftw \
--without-magick --without-pangoft2 --without-ppm --without-analyze --without-radiance \
--with-zip-includes=${TARGET}/include --with-zip-libraries=${TARGET}/lib \
--with-jpeg-includes=${TARGET}/include --with-jpeg-libraries=${TARGET}/lib
make install-strip
# Remove the old C++ bindings
cd ${TARGET}/include
rm -rf vips/vipsc++.h vips/vipscpp.h
cd ${TARGET}/lib
rm -rf pkgconfig .libs *.la libvipsCC*
# Create JSON file of version numbers
cd ${TARGET}
echo "{\n\
\"cairo\": \"${VERSION_CAIRO}\",\n\
\"croco\": \"${VERSION_CROCO}\",\n\
\"exif\": \"${VERSION_EXIF}\",\n\
\"ffi\": \"${VERSION_FFI}\",\n\
\"fontconfig\": \"${VERSION_FONTCONFIG}\",\n\
\"freetype\": \"${VERSION_FREETYPE}\",\n\
\"gdkpixbuf\": \"${VERSION_GDKPIXBUF}\",\n\
\"gif\": \"${VERSION_GIF}\",\n\
\"glib\": \"${VERSION_GLIB}\",\n\
\"gsf\": \"${VERSION_GSF}\",\n\
\"harfbuzz\": \"${VERSION_HARFBUZZ}\",\n\
\"jpeg\": \"${VERSION_JPEG}\",\n\
\"lcms\": \"${VERSION_LCMS2}\",\n\
\"orc\": \"${VERSION_ORC}\",\n\
\"pango\": \"${VERSION_PANGO}\",\n\
\"pixman\": \"${VERSION_PIXMAN}\",\n\
\"png\": \"${VERSION_PNG16}\",\n\
\"svg\": \"${VERSION_SVG}\",\n\
\"tiff\": \"${VERSION_TIFF}-${VERSION_TIFF_GIT_MASTER_SHA}\",\n\
\"vips\": \"${VERSION_VIPS}\",\n\
\"webp\": \"${VERSION_WEBP}\",\n\
\"xml\": \"${VERSION_XML2}\",\n\
\"zlib\": \"${VERSION_ZLIB}\"\n\
}" >lib/versions.json
# Create .tar.gz
tar czf /packaging/libvips-${VERSION_VIPS}-${PLATFORM}.tar.gz include lib
advdef --recompress --shrink-insane /packaging/libvips-${VERSION_VIPS}-${PLATFORM}.tar.gz

View File

@@ -1,22 +0,0 @@
#!/bin/sh
set -e
# Fetch and unzip
mkdir /vips
cd /vips
curl -L -O https://github.com/lovell/build-win64/releases/download/v${VERSION_VIPS}/vips-dev-w64-web-${VERSION_VIPS}.zip
unzip vips-dev-w64-web-${VERSION_VIPS}.zip
# Clean and zip
cd /vips/vips-dev-8.4
rm bin/libvipsCC-42.dll bin/libvips-cpp-42.dll bin/libgsf-win32-1-114.dll
cp bin/*.dll lib/
cp -r lib64/* lib/
# Temp patch for __declspec ordering
curl -L -o include/vips/VImage8.h https://raw.githubusercontent.com/lovell/libvips/e1aef0445bf123d2de000bc7f2ef97b9f788eea0/cplusplus/include/vips/VImage8.h
echo "Creating tarball"
tar czf /packaging/libvips-${VERSION_VIPS}-${PLATFORM}.tar.gz include lib/glib-2.0 lib/libvips.lib lib/libglib-2.0.lib lib/libgobject-2.0.lib lib/*.dll
echo "Shrinking tarball"
advdef --recompress --shrink-insane /packaging/libvips-${VERSION_VIPS}-${PLATFORM}.tar.gz

View File

@@ -1,15 +0,0 @@
FROM socialdefect/raspbian-jessie-core
MAINTAINER Lovell Fuller <npm@lovell.info>
# Create Rasbian-based container suitable for compiling Linux ARMv6 binaries
# Requires the QEMU user mode emulation binaries on the host machine
# Build dependencies
RUN \
apt-get update && \
apt-get install -y build-essential curl autoconf libtool nasm gtk-doc-tools texinfo advancecomp libglib2.0-dev jq
# Compiler settings
ENV \
PLATFORM=linux-armv6 \
FLAGS="-Os"

View File

@@ -1,20 +0,0 @@
FROM debian:jessie
MAINTAINER Lovell Fuller <npm@lovell.info>
# Create Debian-based container suitable for cross-compiling Linux ARMv7-A binaries
# Build dependencies
RUN \
apt-get update && \
apt-get install -y curl && \
echo "deb http://emdebian.org/tools/debian/ jessie main" | tee /etc/apt/sources.list.d/crosstools.list && \
curl http://emdebian.org/tools/debian/emdebian-toolchain-archive.key | apt-key add - && \
dpkg --add-architecture armhf && \
apt-get update && \
apt-get install -y crossbuild-essential-armhf autoconf libtool nasm gtk-doc-tools texinfo advancecomp libglib2.0-dev jq
# Compiler settings
ENV \
PLATFORM=linux-armv7 \
CHOST=arm-linux-gnueabihf \
FLAGS="-marm -march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard -Os"

View File

@@ -1,18 +0,0 @@
FROM debian:stretch
MAINTAINER Lovell Fuller <npm@lovell.info>
# Create Debian-based container suitable for cross-compiling Linux ARMv8-A binaries
# Build dependencies
RUN \
apt-get update && \
apt-get install -y curl && \
dpkg --add-architecture arm64 && \
apt-get update && \
apt-get install -y crossbuild-essential-arm64 autoconf libtool nasm gtk-doc-tools texinfo advancecomp libglib2.0-dev jq
# Compiler settings
ENV \
PLATFORM=linux-armv8 \
CHOST=aarch64-linux-gnu \
FLAGS="-march=armv8-a -Os"

View File

@@ -1,16 +0,0 @@
FROM debian:wheezy
MAINTAINER Lovell Fuller <npm@lovell.info>
# Create Debian-based container suitable for building Linux x64 binaries
# Build dependencies
RUN \
echo "deb http://ftp.debian.org/debian wheezy-backports main" | tee /etc/apt/sources.list.d/wheezy-backports.list && \
apt-get update && \
apt-get install -y build-essential autoconf libtool nasm gtk-doc-tools texinfo advancecomp && \
apt-get -t wheezy-backports install -y jq
# Compiler settings
ENV \
PLATFORM="linux-x64" \
FLAGS="-O3"

View File

@@ -1,28 +0,0 @@
#!/bin/sh
if [ $# -lt 1 ]; then
echo "Usage: $0 IP"
echo "Test sharp on ARM using Docker, where IP is"
echo "the address of a Raspberry Pi running HypriotOS"
exit 1
fi
IP="$1"
echo "Verifying connectivity to $IP"
if ! ping -c 1 $IP; then
echo "Could not connect to $IP"
exit 1
fi
if ! type sshpass >/dev/null; then
echo "Please install sshpass"
exit 1
fi
export SSHPASS=hypriot
echo "Copying sharp source to device"
sshpass -e scp -o PreferredAuthentications=password -r ../../sharp pirate@${IP}:/home/pirate/sharp
echo "Compile and test within container"
sshpass -e ssh -o PreferredAuthentications=password -t pirate@${IP} "docker run --rm -v \${PWD}/sharp:/s hypriot/rpi-node:6 sh -c 'cd /s && npm install --unsafe-perm && npm test'"

View File

@@ -1,56 +0,0 @@
#!/bin/sh
# Verify docker is available
if ! type docker >/dev/null; then
echo "Please install docker"
exit 1
fi
version_node=6.3.0
test="npm run clean; npm install --unsafe-perm; npm test"
# Debian 7, 8
# Ubuntu 14.04
for dist in wheezy jessie trusty; do
echo "Testing $dist..."
if docker run -i -t --rm -v $PWD:/v -e "NODE_ENV=development" nodesource/$dist:$version_node >packaging/$dist.log 2>&1 sh -c "cd /v; ./packaging/test/debian.sh; $test";
then echo "$dist OK"
else echo "$dist fail" && cat packaging/$dist.log
fi
done
# Centos 7
echo "Testing centos7..."
if docker run -i -t --rm -v $PWD:/v -e "NODE_ENV=development" nodesource/centos7:$version_node >packaging/$dist.log 2>&1 sh -c "cd /v; $test";
then echo "centos7 OK"
else echo "centos7 fail" && cat packaging/$dist.log
fi
# Fedora 22
echo "Testing fedora22..."
if docker run -i -t --rm -v $PWD:/v -e "NODE_ENV=development" nodesource/fedora22:$version_node >packaging/$dist.log 2>&1 sh -c "cd /v; $test";
then echo "fedora22 OK"
else echo "fedora22 fail" && cat packaging/$dist.log
fi
# openSUSE 13.2
echo "Testing opensuse..."
if docker run -i -t --rm -v $PWD:/v opensuse:13.2 >packaging/opensuse.log 2>&1 /bin/sh -c "cd /v; ./packaging/test/opensuse.sh; $test";
then echo "opensuse OK"
else echo "opensuse fail" && cat packaging/opensuse.log
fi
# Archlinux 2015.06.01
echo "Testing archlinux..."
if docker run -i -t --rm -v $PWD:/v pritunl/archlinux:latest >packaging/archlinux.log 2>&1 sh -c "cd /v; ./packaging/test/archlinux.sh; $test";
then echo "archlinux OK"
else echo "archlinux fail" && cat packaging/archlinux.log
fi
# Alpine
echo "Testing alpine..."
if docker run -i -t --rm -v $PWD:/v -e "SHARP_TEST_WITHOUT_CACHE=0" alpine:edge >packaging/alpine.log 2>&1 sh -c "cd /v; ./packaging/test/alpine.sh; $test";
then echo "alpine OK"
else echo "alpine fail" && cat packaging/alpine.log
fi

View File

@@ -1,7 +0,0 @@
#!/bin/sh
# Install build dependencies
apk add --update make gcc g++ python nodejs
# Install libvips from aports/testing
apk add --update --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing vips-dev

View File

@@ -1,5 +0,0 @@
#!/bin/sh
# Install Node.js on Archlinux
pacman -Sy --noconfirm gcc make python2 nodejs npm | cat
ln -s /usr/bin/python2 /usr/bin/python

View File

@@ -1,5 +0,0 @@
#!/bin/sh
# Install pkg-config on Debian/Ubuntu
apt-get update
apt-get install -y pkg-config

View File

@@ -1,7 +0,0 @@
#!/bin/sh
# Install Node.js on openSUSE 13.2
zypper addrepo http://download.opensuse.org/repositories/devel:languages:nodejs/openSUSE_13.2/devel:languages:nodejs.repo
zypper --gpg-auto-import-keys refresh
zypper --non-interactive install gcc-c++ make nodejs-devel npm
npm install -g npm

View File

@@ -1,8 +0,0 @@
FROM debian:jessie
MAINTAINER Lovell Fuller <npm@lovell.info>
# Create Debian-based container suitable for post-processing Windows x64 binaries
RUN apt-get update && apt-get install -y curl zip advancecomp
ENV PLATFORM=win32-x64

View File

@@ -1,316 +0,0 @@
#!/bin/sh
# Use of this script is deprecated
echo
echo "WARNING: THIS SCRIPT WILL STOP WORKING AT THE END OF 2016"
echo
echo "WARNING: THIS SCRIPT IS NO LONGER REQUIRED ON MOST 64-BIT LINUX SYSTEMS WHEN USING SHARP V0.12.0+"
echo
echo "See http://sharp.dimens.io/page/install#linux"
echo
echo "If you really, really need this script, it will attempt"
echo "to globally install libvips if not already available."
echo
sleep 5
vips_version_minimum=8.4.2
vips_version_latest_major_minor=8.4
vips_version_latest_patch=2
openslide_version_minimum=3.4.0
openslide_version_latest_major_minor=3.4
openslide_version_latest_patch=1
install_libvips_from_source() {
echo "Compiling libvips $vips_version_latest_major_minor.$vips_version_latest_patch from source"
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
tar zvxf vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
cd vips-$vips_version_latest_major_minor.$vips_version_latest_patch
CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" ./configure --disable-debug --disable-docs --disable-static --disable-introspection --disable-dependency-tracking --enable-cxx=yes --without-python --without-orc --without-fftw $1
make
make install
cd ..
rm -rf vips-$vips_version_latest_major_minor.$vips_version_latest_patch
rm vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
ldconfig
echo "Installed libvips $(PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig pkg-config --modversion vips)"
}
install_libopenslide_from_source() {
echo "Compiling openslide $openslide_version_latest_major_minor.$openslide_version_latest_patch from source"
curl -O -L https://github.com/openslide/openslide/releases/download/v$openslide_version_latest_major_minor.$openslide_version_latest_patch/openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
tar xzvf openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
cd openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch
PKG_CONFIG_PATH=$pkg_config_path ./configure $1
make
make install
cd ..
rm -rf openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch
rm openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
ldconfig
echo "Installed libopenslide $openslide_version_latest_major_minor.$openslide_version_latest_patch"
}
sorry() {
echo "Sorry, I don't yet know how to install lib$1 on $2"
exit 1
}
pkg_config_path="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
check_if_library_exists() {
PKG_CONFIG_PATH=$pkg_config_path pkg-config --exists $1
if [ $? -eq 0 ]; then
version_found=$(PKG_CONFIG_PATH=$pkg_config_path pkg-config --modversion $1)
PKG_CONFIG_PATH=$pkg_config_path pkg-config --atleast-version=$2 $1
if [ $? -eq 0 ]; then
# Found suitable version of libvips
echo "Found lib$1 $version_found"
return 1
fi
echo "Found lib$1 $version_found but require $2"
else
echo "Could not find lib$1 using a PKG_CONFIG_PATH of '$pkg_config_path'"
fi
return 0
}
enable_openslide=0
# Is libvips already installed, and is it at least the minimum required version?
if [ $# -eq 1 ]; then
if [ "$1" = "--with-openslide" ]; then
echo "Installing vips with openslide support"
enable_openslide=1
else
echo "Sorry, $1 is not supported. Did you mean --with-openslide?"
exit 1
fi
fi
if ! type pkg-config >/dev/null; then
sorry "vips" "a system without pkg-config"
fi
openslide_exists=0
if [ $enable_openslide -eq 1 ]; then
check_if_library_exists "openslide" "$openslide_version_minimum"
openslide_exists=$?
fi
check_if_library_exists "vips" "$vips_version_minimum"
vips_exists=$?
if [ $vips_exists -eq 1 ] && [ $enable_openslide -eq 1 ]; then
if [ $openslide_exists -eq 1 ]; then
# Check if vips compiled with openslide support
vips_with_openslide=`vips list classes | grep -i opensli`
if [ -z $vips_with_openslide ]; then
echo "Vips compiled without openslide support."
else
exit 0
fi
fi
elif [ $vips_exists -eq 1 ] && [ $enable_openslide -eq 0 ]; then
exit 0
fi
# Verify root/sudo access
if [ "$(id -u)" -ne "0" ]; then
echo "Sorry, I need root/sudo access to continue"
exit 1
fi
# Deprecation warning
if [ "$(arch)" == "x86_64" ]; then
echo "This script is no longer required on most 64-bit Linux systems when using sharp v0.12.0+"
fi
# OS-specific installations of libopenslide follows
# Either openslide does not exist, or vips is installed without openslide support
if [ $enable_openslide -eq 1 ] && [ -z $vips_with_openslide ] && [ $openslide_exists -eq 0 ]; then
if [ -f /etc/debian_version ]; then
# Debian Linux
DISTRO=$(lsb_release -c -s)
echo "Detected Debian Linux '$DISTRO'"
case "$DISTRO" in
jessie|vivid|wily|xenial)
# Debian 8, Ubuntu 15
echo "Installing libopenslide via apt-get"
apt-get install -y libopenslide-dev
;;
trusty|utopic|qiana|rebecca|rafaela|freya)
# Ubuntu 14, Mint 17
echo "Installing libopenslide dependencies via apt-get"
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
install_libopenslide_from_source
;;
precise|wheezy|maya)
# Debian 7, Ubuntu 12.04, Mint 13
echo "Installing libopenslide dependencies via apt-get"
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
install_libopenslide_from_source
;;
*)
# Unsupported Debian-based OS
sorry "openslide" "Debian-based $DISTRO"
;;
esac
elif [ -f /etc/redhat-release ]; then
# Red Hat Linux
RELEASE=$(cat /etc/redhat-release)
echo "Detected Red Hat Linux '$RELEASE'"
case $RELEASE in
"Red Hat Enterprise Linux release 7."*|"CentOS Linux release 7."*|"Scientific Linux release 7."*)
# RHEL/CentOS 7
echo "Installing libopenslide dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl libpng-devel libjpeg-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel gdk-pixbuf2-devel sqlite-devel cairo-devel glib2-devel
install_libopenslide_from_source "--prefix=/usr"
;;
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
# RHEL/CentOS 6
echo "Installing libopenslide dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl libpng-devel libjpeg-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel gdk-pixbuf2-devel sqlite-devel cairo-devel glib2-devel
install_libopenslide_from_source "--prefix=/usr"
;;
"Fedora release 21 "*|"Fedora release 22 "*)
# Fedora 21, 22
echo "Installing libopenslide via yum"
yum install -y openslide-devel
;;
*)
# Unsupported RHEL-based OS
sorry "openslide" "$RELEASE"
;;
esac
elif [ -f /etc/os-release ]; then
RELEASE=$(cat /etc/os-release | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.2"*)
echo "Installing libopenslide via zypper"
zypper --gpg-auto-import-keys install -y libopenslide-devel
;;
esac
elif [ -f /etc/SuSE-brand ]; then
RELEASE=$(cat /etc/SuSE-brand | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.1")
echo "Installing libopenslide dependencies via zypper"
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
zypper --gpg-auto-import-keys install -y tar curl libpng16-devel libjpeg-turbo libjpeg8-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel libgdk_pixbuf-2_0-0 sqlite3-devel cairo-devel glib2-devel
install_libopenslide_from_source
;;
esac
else
# Unsupported OS
sorry "openslide" "$(uname -a)"
fi
fi
# OS-specific installations of libvips follows
if [ -f /etc/debian_version ]; then
# Debian Linux
DISTRO=$(lsb_release -c -s)
echo "Detected Debian Linux '$DISTRO'"
case "$DISTRO" in
jessie|trusty|utopic|vivid|wily|xenial|qiana|rebecca|rafaela|freya)
# Debian 8, Ubuntu 14.04+, Mint 17
echo "Installing libvips dependencies via apt-get"
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
install_libvips_from_source
;;
precise|wheezy|maya)
# Debian 7, Ubuntu 12.04, Mint 13
echo "Installing libvips dependencies via apt-get"
add-apt-repository -y ppa:lyrasis/precise-backports
apt-get update
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
install_libvips_from_source
;;
*)
# Unsupported Debian-based OS
sorry "vips" "Debian-based $DISTRO"
;;
esac
elif [ -f /etc/redhat-release ]; then
# Red Hat Linux
RELEASE=$(cat /etc/redhat-release)
echo "Detected Red Hat Linux '$RELEASE'"
case $RELEASE in
"Red Hat Enterprise Linux release 7."*|"CentOS Linux release 7."*|"Scientific Linux release 7."*)
# RHEL/CentOS 7
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
install_libvips_from_source "--prefix=/usr"
;;
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
# RHEL/CentOS 6
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel
yum install -y http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm
yum install -y --enablerepo=nux-dextop gobject-introspection-devel
yum install -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
yum install -y --enablerepo=remi libwebp-devel
install_libvips_from_source "--prefix=/usr"
;;
"Fedora"*)
# Fedora 21, 22, 23
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y gcc-c++ gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
install_libvips_from_source "--prefix=/usr"
;;
*)
# Unsupported RHEL-based OS
sorry "vips" "$RELEASE"
;;
esac
elif [ -f /etc/system-release ]; then
# Probably Amazon Linux
RELEASE=$(cat /etc/system-release)
case $RELEASE in
"Amazon Linux AMI release 2015.03"|"Amazon Linux AMI release 2015.09")
# Amazon Linux
echo "Detected '$RELEASE'"
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
install_libvips_from_source "--prefix=/usr"
;;
*)
# Unsupported Amazon Linux version
sorry "vips" "$RELEASE"
;;
esac
elif [ -f /etc/os-release ]; then
RELEASE=$(cat /etc/os-release | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.2"*)
echo "Installing libvips dependencies via zypper"
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
zypper --gpg-auto-import-keys install -y tar curl gtk-doc libxml2-devel libjpeg-turbo libjpeg8-devel libpng16-devel libtiff-devel libexif-devel liblcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
install_libvips_from_source
;;
esac
elif [ -f /etc/SuSE-brand ]; then
RELEASE=$(cat /etc/SuSE-brand | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.1")
echo "Installing libvips dependencies via zypper"
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
zypper --gpg-auto-import-keys install -y tar curl gtk-doc libxml2-devel libjpeg-turbo libjpeg8-devel libpng16-devel libtiff-devel libexif-devel liblcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
install_libvips_from_source
;;
esac
else
# Unsupported OS
sorry "vips" "$(uname -a)"
fi

View File

@@ -1,12 +1,29 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdlib>
#include <string>
#include <string.h>
#include <vector>
#include <queue>
#include <mutex>
#include <node.h>
#include <node_buffer.h>
#include <nan.h>
#include <vips/vips8>
#include "nan.h"
#include "common.h"
using vips::VImage;
@@ -23,21 +40,22 @@ namespace sharp {
// Create an InputDescriptor instance from a v8::Object describing an input image
InputDescriptor* CreateInputDescriptor(
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> buffersToPersist
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist
) {
Nan::HandleScope();
InputDescriptor *descriptor = new InputDescriptor;
if (HasAttr(input, "file")) {
descriptor->file = AttrAsStr(input, "file");
} else {
} else if (HasAttr(input, "buffer")) {
v8::Local<v8::Object> buffer = AttrAs<v8::Object>(input, "buffer");
descriptor->bufferLength = node::Buffer::Length(buffer);
descriptor->buffer = node::Buffer::Data(buffer);
buffersToPersist.push_back(buffer);
}
descriptor->failOnError = AttrTo<bool>(input, "failOnError");
// Density for vector-based input
if (HasAttr(input, "density")) {
descriptor->density = AttrTo<uint32_t>(input, "density");
descriptor->density = AttrTo<double>(input, "density");
}
// Raw pixel input
if (HasAttr(input, "rawChannels")) {
@@ -45,6 +63,20 @@ namespace sharp {
descriptor->rawWidth = AttrTo<uint32_t>(input, "rawWidth");
descriptor->rawHeight = AttrTo<uint32_t>(input, "rawHeight");
}
// Page input for multi-page TIFF
if (HasAttr(input, "page")) {
descriptor->page = AttrTo<uint32_t>(input, "page");
}
// Create new image
if (HasAttr(input, "createChannels")) {
descriptor->createChannels = AttrTo<uint32_t>(input, "createChannels");
descriptor->createWidth = AttrTo<uint32_t>(input, "createWidth");
descriptor->createHeight = AttrTo<uint32_t>(input, "createHeight");
v8::Local<v8::Object> createBackground = AttrAs<v8::Object>(input, "createBackground");
for (unsigned int i = 0; i < 4; i++) {
descriptor->createBackground[i] = AttrTo<double>(createBackground, i);
}
}
return descriptor;
}
@@ -177,7 +209,6 @@ namespace sharp {
VImage image;
ImageType imageType;
if (descriptor->buffer != nullptr) {
// From buffer
if (descriptor->rawChannels > 0) {
// Raw, uncompressed pixel data
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
@@ -193,13 +224,18 @@ namespace sharp {
imageType = DetermineImageType(descriptor->buffer, descriptor->bufferLength);
if (imageType != ImageType::UNKNOWN) {
try {
vips::VOption *option = VImage::option()->set("access", accessMethod);
vips::VOption *option = VImage::option()
->set("access", accessMethod)
->set("fail", descriptor->failOnError);
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
option->set("dpi", static_cast<double>(descriptor->density));
option->set("dpi", descriptor->density);
}
if (imageType == ImageType::MAGICK) {
option->set("density", std::to_string(descriptor->density).data());
}
if (imageType == ImageType::TIFF) {
option->set("page", descriptor->page);
}
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
SetDensity(image, descriptor->density);
@@ -212,26 +248,46 @@ namespace sharp {
}
}
} else {
// From filesystem
imageType = DetermineImageType(descriptor->file.data());
if (imageType != ImageType::UNKNOWN) {
try {
vips::VOption *option = VImage::option()->set("access", accessMethod);
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
option->set("dpi", static_cast<double>(descriptor->density));
}
if (imageType == ImageType::MAGICK) {
option->set("density", std::to_string(descriptor->density).data());
}
image = VImage::new_from_file(descriptor->file.data(), option);
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
SetDensity(image, descriptor->density);
}
} catch (...) {
throw vips::VError("Input file has corrupt header");
if (descriptor->createChannels > 0) {
// Create new image
std::vector<double> background = {
descriptor->createBackground[0],
descriptor->createBackground[1],
descriptor->createBackground[2]
};
if (descriptor->createChannels == 4) {
background.push_back(descriptor->createBackground[3]);
}
image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background);
image.get_image()->Type = VIPS_INTERPRETATION_sRGB;
imageType = ImageType::RAW;
} else {
throw vips::VError("Input file is missing or of an unsupported image format");
// From filesystem
imageType = DetermineImageType(descriptor->file.data());
if (imageType != ImageType::UNKNOWN) {
try {
vips::VOption *option = VImage::option()
->set("access", accessMethod)
->set("fail", descriptor->failOnError);
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
option->set("dpi", descriptor->density);
}
if (imageType == ImageType::MAGICK) {
option->set("density", std::to_string(descriptor->density).data());
}
if (imageType == ImageType::TIFF) {
option->set("page", descriptor->page);
}
image = VImage::new_from_file(descriptor->file.data(), option);
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
SetDensity(image, descriptor->density);
}
} catch (...) {
throw vips::VError("Input file has corrupt header");
}
} else {
throw vips::VError("Input file is missing or of an unsupported image format");
}
}
}
return std::make_tuple(image, imageType);
@@ -254,8 +310,7 @@ namespace sharp {
return (
(bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) ||
(bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) ||
(bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK)
);
(bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK));
}
/*
@@ -300,13 +355,32 @@ namespace sharp {
/*
Set pixels/mm resolution based on a pixels/inch density.
*/
void SetDensity(VImage image, const int density) {
const double pixelsPerMm = static_cast<double>(density) / 25.4;
void SetDensity(VImage image, const double density) {
const double pixelsPerMm = density / 25.4;
image.set("Xres", pixelsPerMm);
image.set("Yres", pixelsPerMm);
image.set(VIPS_META_RESOLUTION_UNIT, "in");
}
/*
Check the proposed format supports the current dimensions.
*/
void AssertImageTypeDimensions(VImage image, ImageType const imageType) {
if (imageType == ImageType::JPEG) {
if (image.width() > 65535 || image.height() > 65535) {
throw vips::VError("Processed image is too large for the JPEG format");
}
} else if (imageType == ImageType::PNG) {
if (image.width() > 2147483647 || image.height() > 2147483647) {
throw vips::VError("Processed image is too large for the PNG format");
}
} else if (imageType == ImageType::WEBP) {
if (image.width() > 16383 || image.height() > 16383) {
throw vips::VError("Processed image is too large for the WebP format");
}
}
}
/*
Called when a Buffer undergoes GC, required to support mixed runtime libraries in Windows
*/
@@ -316,9 +390,91 @@ namespace sharp {
}
}
/*
Temporary buffer of warnings
*/
std::queue<std::string> vipsWarnings;
std::mutex vipsWarningsMutex;
/*
Called with warnings from the glib-registered "VIPS" domain
*/
void VipsWarningCallback(char const* log_domain, GLogLevelFlags log_level, char const* message, void* ignore) {
std::lock_guard<std::mutex> lock(vipsWarningsMutex);
vipsWarnings.emplace(message);
}
/*
Pop the oldest warning message from the queue
*/
std::string VipsWarningPop() {
std::string warning;
std::lock_guard<std::mutex> lock(vipsWarningsMutex);
if (!vipsWarnings.empty()) {
warning = vipsWarnings.front();
vipsWarnings.pop();
}
return warning;
}
/*
Calculate the (left, top) coordinates of the output image
within the input image, applying the given gravity.
within the input image, applying the given gravity during an embed.
@Azurebyte: We are basically swapping the inWidth and outWidth, inHeight and outHeight from the CalculateCrop function.
*/
std::tuple<int, int> CalculateEmbedPosition(int const inWidth, int const inHeight,
int const outWidth, int const outHeight, int const gravity) {
int left = 0;
int top = 0;
switch (gravity) {
case 1:
// North
left = (outWidth - inWidth) / 2;
break;
case 2:
// East
left = outWidth - inWidth;
top = (outHeight - inHeight) / 2;
break;
case 3:
// South
left = (outWidth - inWidth) / 2;
top = outHeight - inHeight;
break;
case 4:
// West
top = (outHeight - inHeight) / 2;
break;
case 5:
// Northeast
left = outWidth - inWidth;
break;
case 6:
// Southeast
left = outWidth - inWidth;
top = outHeight - inHeight;
break;
case 7:
// Southwest
top = outHeight - inHeight;
break;
case 8:
// Northwest
// Which is the default is 0,0 so we do not assign anything here.
break;
default:
// Centre
left = (outWidth - inWidth) / 2;
top = (outHeight - inHeight) / 2;
}
return std::make_tuple(left, top);
}
/*
Calculate the (left, top) coordinates of the output image
within the input image, applying the given gravity during a crop.
*/
std::tuple<int, int> CalculateCrop(int const inWidth, int const inHeight,
int const outWidth, int const outHeight, int const gravity) {
@@ -352,9 +508,11 @@ namespace sharp {
// Southeast
left = inWidth - outWidth;
top = inHeight - outHeight;
break;
case 7:
// Southwest
top = inHeight - outHeight;
break;
case 8:
// Northwest
break;
@@ -378,23 +536,23 @@ namespace sharp {
int top = 0;
// assign only if valid
if(x >= 0 && x < (inWidth - outWidth)) {
if (x >= 0 && x < (inWidth - outWidth)) {
left = x;
} else if(x >= (inWidth - outWidth)) {
} else if (x >= (inWidth - outWidth)) {
left = inWidth - outWidth;
}
if(y >= 0 && y < (inHeight - outHeight)) {
if (y >= 0 && y < (inHeight - outHeight)) {
top = y;
} else if(y >= (inHeight - outHeight)) {
} else if (y >= (inHeight - outHeight)) {
top = inHeight - outHeight;
}
// the resulting left and top could have been outside the image after calculation from bottom/right edges
if(left < 0) {
if (left < 0) {
left = 0;
}
if(top < 0) {
if (top < 0) {
top = 0;
}
@@ -421,8 +579,7 @@ namespace sharp {
*/
VipsOperationBoolean GetBooleanOperation(std::string const opStr) {
return static_cast<VipsOperationBoolean>(
vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data())
);
vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data()));
}
/*
@@ -430,8 +587,7 @@ namespace sharp {
*/
VipsInterpretation GetInterpretation(std::string const typeStr) {
return static_cast<VipsInterpretation>(
vips_enum_from_nick(nullptr, VIPS_TYPE_INTERPRETATION, typeStr.data())
);
vips_enum_from_nick(nullptr, VIPS_TYPE_INTERPRETATION, typeStr.data()));
}
/*

View File

@@ -1,27 +1,41 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_COMMON_H_
#define SRC_COMMON_H_
#include <string>
#include <tuple>
#include <vector>
#include <node.h>
#include <nan.h>
#include <vips/vips8>
#include "nan.h"
// Verify platform and compiler compatibility
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 4))
#error libvips version 8.4.x required - see sharp.dimens.io/page/install
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 6))
#error libvips version 8.6.1+ is required - see sharp.pixelplumbing.com/page/install
#endif
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
#error GCC version 4.6+ is required for C++11 features - see sharp.dimens.io/page/install#prerequisites
#error GCC version 4.6+ is required for C++11 features - see sharp.pixelplumbing.com/page/install#prerequisites
#endif
#if (defined(__clang__) && defined(__has_feature))
#if (!__has_feature(cxx_range_for))
#error clang version 3.0+ is required for C++11 features - see sharp.dimens.io/page/install#prerequisites
#error clang version 3.0+ is required for C++11 features - see sharp.pixelplumbing.com/page/install#prerequisites
#endif
#endif
@@ -33,19 +47,35 @@ namespace sharp {
std::string name;
std::string file;
char *buffer;
bool failOnError;
size_t bufferLength;
int density;
double density;
int rawChannels;
int rawWidth;
int rawHeight;
int page;
int createChannels;
int createWidth;
int createHeight;
double createBackground[4];
InputDescriptor():
buffer(nullptr),
failOnError(FALSE),
bufferLength(0),
density(72),
density(72.0),
rawChannels(0),
rawWidth(0),
rawHeight(0) {}
rawHeight(0),
page(0),
createChannels(0),
createWidth(0),
createHeight(0) {
createBackground[0] = 0.0;
createBackground[1] = 0.0;
createBackground[2] = 0.0;
createBackground[3] = 255.0;
}
};
// Convenience methods to access the attributes of a v8::Object
@@ -63,8 +93,7 @@ namespace sharp {
// Create an InputDescriptor instance from a v8::Object describing an input image
InputDescriptor* CreateInputDescriptor(
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> buffersToPersist
);
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist);
enum class ImageType {
JPEG,
@@ -157,13 +186,35 @@ namespace sharp {
/*
Set pixels/mm resolution based on a pixels/inch density.
*/
void SetDensity(VImage image, const int density);
void SetDensity(VImage image, const double density);
/*
Check the proposed format supports the current dimensions.
*/
void AssertImageTypeDimensions(VImage image, ImageType const imageType);
/*
Called when a Buffer undergoes GC, required to support mixed runtime libraries in Windows
*/
void FreeCallback(char* data, void* hint);
/*
Called with warnings from the glib-registered "VIPS" domain
*/
void VipsWarningCallback(char const* log_domain, GLogLevelFlags log_level, char const* message, void* ignore);
/*
Pop the oldest warning message from the queue
*/
std::string VipsWarningPop();
/*
Calculate the (left, top) coordinates of the output image
within the input image, applying the given gravity during an embed.
*/
std::tuple<int, int> CalculateEmbedPosition(int const inWidth, int const inHeight,
int const outWidth, int const outHeight, int const gravity);
/*
Calculate the (left, top) coordinates of the output image
within the input image, applying the given gravity.

View File

@@ -205,6 +205,30 @@ VOption::set( const char *name, std::vector<double> value )
return( this );
}
// input int array
VOption *
VOption::set( const char *name, std::vector<int> value )
{
Pair *pair = new Pair( name );
int *array;
unsigned int i;
pair->input = true;
g_value_init( &pair->value, VIPS_TYPE_ARRAY_INT );
vips_value_set_array_int( &pair->value, NULL,
static_cast< int >( value.size() ) );
array = vips_value_get_array_int( &pair->value, NULL );
for( i = 0; i < value.size(); i++ )
array[i] = value[i];
options.push_back( pair );
return( this );
}
// input image array
VOption *
VOption::set( const char *name, std::vector<VImage> value )
@@ -350,7 +374,7 @@ set_property( VipsObject *object, const char *name, const GValue *value )
if( vips_object_get_argument( object, name,
&pspec, &argument_class, &argument_instance ) ) {
vips_warn( NULL, "%s", vips_error_buffer() );
g_warning( "%s", vips_error_buffer() );
vips_error_clear();
return;
}
@@ -364,7 +388,7 @@ set_property( VipsObject *object, const char *name, const GValue *value )
if( (enum_value = vips_enum_from_nick( object_class->nickname,
pspec_type, g_value_get_string( value ) )) < 0 ) {
vips_warn( NULL, "%s", vips_error_buffer() );
g_warning( "%s", vips_error_buffer() );
vips_error_clear();
return;
}
@@ -465,8 +489,7 @@ VImage::call_option_string( const char *operation_name,
operation_name );
if( !(operation = vips_operation_new( operation_name )) ) {
if( options )
delete options;
delete options;
throw( VError() );
}
@@ -565,34 +588,6 @@ VImage::new_from_buffer( void *buf, size_t len, const char *option_string,
return( out );
}
VImage
VImage::new_from_image( std::vector<double> pixel )
{
VImage onepx = VImage::black( 1, 1,
VImage::option()->set( "bands", bands() ) );
onepx = (onepx + pixel).cast( format() );
VImage big = onepx.embed( 0, 0, width(), height(),
VImage::option()->set( "extend", VIPS_EXTEND_COPY ) );
big = big.copy(
VImage::option()->
set( "interpretation", interpretation() )->
set( "xres", xres() )->
set( "yres", yres() )->
set( "xoffset", xres() )->
set( "yoffset", yres() ) );
return( big );
}
VImage
VImage::new_from_image( double pixel )
{
return( new_from_image( to_vectorv( 1, pixel ) ) );
}
VImage
VImage::new_matrix( int width, int height )
{
@@ -693,10 +688,21 @@ VImage::bandsplit( VOption *options )
VImage
VImage::bandjoin( VImage other, VOption *options )
{
VImage v[2] = { *this, other };
std::vector<VImage> vec( v, v + VIPS_NUMBER( v ) );
VImage v[2] = { *this, other };
std::vector<VImage> vec( v, v + VIPS_NUMBER( v ) );
return( bandjoin( vec, options ) );
return( bandjoin( vec, options ) );
}
VImage
VImage::composite( VImage other, VipsBlendMode mode, VOption *options )
{
VImage v[2] = { *this, other };
std::vector<VImage> ivec( v, v + VIPS_NUMBER( v ) );
int m[1] = { static_cast<int>( mode ) };
std::vector<int> mvec( m, m + VIPS_NUMBER( m ) );
return( composite( ivec, mvec, options ) );
}
std::complex<double>
@@ -770,19 +776,19 @@ operator+( VImage a, std::vector<double> b )
}
VImage &
operator+=( VImage a, const VImage b )
operator+=( VImage &a, const VImage b )
{
return( a = a + b );
}
VImage &
operator+=( VImage a, const double b )
operator+=( VImage &a, const double b )
{
return( a = a + b );
}
VImage &
operator+=( VImage a, std::vector<double> b )
operator+=( VImage &a, std::vector<double> b )
{
return( a = a + b );
}
@@ -818,19 +824,19 @@ operator-( VImage a, std::vector<double> b )
}
VImage &
operator-=( VImage a, const VImage b )
operator-=( VImage &a, const VImage b )
{
return( a = a - b );
}
VImage &
operator-=( VImage a, const double b )
operator-=( VImage &a, const double b )
{
return( a = a - b );
}
VImage &
operator-=( VImage a, std::vector<double> b )
operator-=( VImage &a, std::vector<double> b )
{
return( a = a - b );
}
@@ -872,19 +878,19 @@ operator*( VImage a, std::vector<double> b )
}
VImage &
operator*=( VImage a, const VImage b )
operator*=( VImage &a, const VImage b )
{
return( a = a * b );
}
VImage &
operator*=( VImage a, const double b )
operator*=( VImage &a, const double b )
{
return( a = a * b );
}
VImage &
operator*=( VImage a, std::vector<double> b )
operator*=( VImage &a, std::vector<double> b )
{
return( a = a * b );
}
@@ -920,19 +926,19 @@ operator/( VImage a, std::vector<double> b )
}
VImage &
operator/=( VImage a, const VImage b )
operator/=( VImage &a, const VImage b )
{
return( a = a / b );
}
VImage &
operator/=( VImage a, const double b )
operator/=( VImage &a, const double b )
{
return( a = a / b );
}
VImage &
operator/=( VImage a, std::vector<double> b )
operator/=( VImage &a, std::vector<double> b )
{
return( a = a / b );
}
@@ -956,19 +962,19 @@ operator%( VImage a, std::vector<double> b )
}
VImage &
operator%=( VImage a, const VImage b )
operator%=( VImage &a, const VImage b )
{
return( a = a % b );
}
VImage &
operator%=( VImage a, const double b )
operator%=( VImage &a, const double b )
{
return( a = a % b );
}
VImage &
operator%=( VImage a, std::vector<double> b )
operator%=( VImage &a, std::vector<double> b )
{
return( a = a % b );
}
@@ -982,29 +988,29 @@ operator<( VImage a, VImage b )
VImage
operator<( double a, VImage b )
{
return( b.relational_const( to_vector( a ),
VIPS_OPERATION_RELATIONAL_MORE ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
to_vector( a ) ) );
}
VImage
operator<( VImage a, double b )
{
return( a.relational_const( to_vector( b ),
VIPS_OPERATION_RELATIONAL_LESS ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
to_vector( b ) ) );
}
VImage
operator<( std::vector<double> a, VImage b )
{
return( b.relational_const( a,
VIPS_OPERATION_RELATIONAL_MORE ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
a ) );
}
VImage
operator<( VImage a, std::vector<double> b )
{
return( a.relational_const( b,
VIPS_OPERATION_RELATIONAL_LESS ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
b ) );
}
VImage
@@ -1016,29 +1022,29 @@ operator<=( VImage a, VImage b )
VImage
operator<=( double a, VImage b )
{
return( b.relational_const( to_vector( a ),
VIPS_OPERATION_RELATIONAL_MOREEQ ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
to_vector( a ) ) );
}
VImage
operator<=( VImage a, double b )
{
return( a.relational_const( to_vector( b ),
VIPS_OPERATION_RELATIONAL_LESSEQ ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
to_vector( b ) ) );
}
VImage
operator<=( std::vector<double> a, VImage b )
{
return( b.relational_const( a,
VIPS_OPERATION_RELATIONAL_MOREEQ ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
a ) );
}
VImage
operator<=( VImage a, std::vector<double> b )
{
return( a.relational_const( b,
VIPS_OPERATION_RELATIONAL_LESSEQ ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
b ) );
}
VImage
@@ -1050,29 +1056,29 @@ operator>( VImage a, VImage b )
VImage
operator>( double a, VImage b )
{
return( b.relational_const( to_vector( a ),
VIPS_OPERATION_RELATIONAL_LESS ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
to_vector( a ) ) );
}
VImage
operator>( VImage a, double b )
{
return( a.relational_const( to_vector( b ),
VIPS_OPERATION_RELATIONAL_MORE ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
to_vector( b ) ) );
}
VImage
operator>( std::vector<double> a, VImage b )
{
return( b.relational_const( a,
VIPS_OPERATION_RELATIONAL_LESS ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESS,
a ) );
}
VImage
operator>( VImage a, std::vector<double> b )
{
return( a.relational_const( b,
VIPS_OPERATION_RELATIONAL_MORE ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_MORE,
b ) );
}
VImage
@@ -1084,29 +1090,29 @@ operator>=( VImage a, VImage b )
VImage
operator>=( double a, VImage b )
{
return( b.relational_const( to_vector( a ),
VIPS_OPERATION_RELATIONAL_LESSEQ ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
to_vector( a ) ) );
}
VImage
operator>=( VImage a, double b )
{
return( a.relational_const( to_vector( b ),
VIPS_OPERATION_RELATIONAL_MOREEQ ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
to_vector( b ) ) );
}
VImage
operator>=( std::vector<double> a, VImage b )
{
return( b.relational_const( a,
VIPS_OPERATION_RELATIONAL_LESSEQ ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_LESSEQ,
a ) );
}
VImage
operator>=( VImage a, std::vector<double> b )
{
return( a.relational_const( b,
VIPS_OPERATION_RELATIONAL_MOREEQ ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_MOREEQ,
b ) );
}
VImage
@@ -1118,29 +1124,29 @@ operator==( VImage a, VImage b )
VImage
operator==( double a, VImage b )
{
return( b.relational_const( to_vector( a ),
VIPS_OPERATION_RELATIONAL_EQUAL ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
to_vector( a ) ) );
}
VImage
operator==( VImage a, double b )
{
return( a.relational_const( to_vector( b ),
VIPS_OPERATION_RELATIONAL_EQUAL ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
to_vector( b ) ) );
}
VImage
operator==( std::vector<double> a, VImage b )
{
return( b.relational_const( a,
VIPS_OPERATION_RELATIONAL_EQUAL ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
a ) );
}
VImage
operator==( VImage a, std::vector<double> b )
{
return( a.relational_const( b,
VIPS_OPERATION_RELATIONAL_EQUAL ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_EQUAL,
b ) );
}
VImage
@@ -1152,29 +1158,29 @@ operator!=( VImage a, VImage b )
VImage
operator!=( double a, VImage b )
{
return( b.relational_const( to_vector( a ),
VIPS_OPERATION_RELATIONAL_NOTEQ ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
to_vector( a ) ) );
}
VImage
operator!=( VImage a, double b )
{
return( a.relational_const( to_vector( b ),
VIPS_OPERATION_RELATIONAL_NOTEQ ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
to_vector( b ) ) );
}
VImage
operator!=( std::vector<double> a, VImage b )
{
return( b.relational_const( a,
VIPS_OPERATION_RELATIONAL_NOTEQ ) );
return( b.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
a ) );
}
VImage
operator!=( VImage a, std::vector<double> b )
{
return( a.relational_const( b,
VIPS_OPERATION_RELATIONAL_NOTEQ ) );
return( a.relational_const( VIPS_OPERATION_RELATIONAL_NOTEQ,
b ) );
}
VImage
@@ -1186,43 +1192,43 @@ operator&( VImage a, VImage b )
VImage
operator&( double a, VImage b )
{
return( b.boolean_const( to_vector( a ),
VIPS_OPERATION_BOOLEAN_AND ) );
return( b.boolean_const( VIPS_OPERATION_BOOLEAN_AND,
to_vector( a ) ) );
}
VImage
operator&( VImage a, double b )
{
return( a.boolean_const( to_vector( b ),
VIPS_OPERATION_BOOLEAN_AND ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_AND,
to_vector( b ) ) );
}
VImage
operator&( std::vector<double> a, VImage b )
{
return( b.boolean_const( a, VIPS_OPERATION_BOOLEAN_AND ) );
return( b.boolean_const( VIPS_OPERATION_BOOLEAN_AND, a ) );
}
VImage
operator&( VImage a, std::vector<double> b )
{
return( a.boolean_const( b, VIPS_OPERATION_BOOLEAN_AND ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_AND, b ) );
}
VImage &
operator&=( VImage a, const VImage b )
operator&=( VImage &a, const VImage b )
{
return( a = a & b );
}
VImage &
operator&=( VImage a, const double b )
operator&=( VImage &a, const double b )
{
return( a = a & b );
}
VImage &
operator&=( VImage a, std::vector<double> b )
operator&=( VImage &a, std::vector<double> b )
{
return( a = a & b );
}
@@ -1236,43 +1242,45 @@ operator|( VImage a, VImage b )
VImage
operator|( double a, VImage b )
{
return( b.boolean_const( to_vector( a ),
VIPS_OPERATION_BOOLEAN_OR ) );
return( b.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
to_vector( a ) ) );
}
VImage
operator|( VImage a, double b )
{
return( a.boolean_const( to_vector( b ),
VIPS_OPERATION_BOOLEAN_OR ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
to_vector( b ) ) );
}
VImage
operator|( std::vector<double> a, VImage b )
{
return( b.boolean_const( a, VIPS_OPERATION_BOOLEAN_OR ) );
return( b.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
a ) );
}
VImage
operator|( VImage a, std::vector<double> b )
{
return( a.boolean_const( b, VIPS_OPERATION_BOOLEAN_OR ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_OR,
b ) );
}
VImage &
operator|=( VImage a, const VImage b )
operator|=( VImage &a, const VImage b )
{
return( a = a | b );
}
VImage &
operator|=( VImage a, const double b )
operator|=( VImage &a, const double b )
{
return( a = a | b );
}
VImage &
operator|=( VImage a, std::vector<double> b )
operator|=( VImage &a, std::vector<double> b )
{
return( a = a | b );
}
@@ -1286,43 +1294,45 @@ operator^( VImage a, VImage b )
VImage
operator^( double a, VImage b )
{
return( b.boolean_const( to_vector( a ),
VIPS_OPERATION_BOOLEAN_EOR ) );
return( b.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
to_vector( a ) ) );
}
VImage
operator^( VImage a, double b )
{
return( a.boolean_const( to_vector( b ),
VIPS_OPERATION_BOOLEAN_EOR ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
to_vector( b ) ) );
}
VImage
operator^( std::vector<double> a, VImage b )
{
return( b.boolean_const( a, VIPS_OPERATION_BOOLEAN_EOR ) );
return( b.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
a ) );
}
VImage
operator^( VImage a, std::vector<double> b )
{
return( a.boolean_const( b, VIPS_OPERATION_BOOLEAN_EOR ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_EOR,
b ) );
}
VImage &
operator^=( VImage a, const VImage b )
operator^=( VImage &a, const VImage b )
{
return( a = a ^ b );
}
VImage &
operator^=( VImage a, const double b )
operator^=( VImage &a, const double b )
{
return( a = a ^ b );
}
VImage &
operator^=( VImage a, std::vector<double> b )
operator^=( VImage &a, std::vector<double> b )
{
return( a = a ^ b );
}
@@ -1336,30 +1346,31 @@ operator<<( VImage a, VImage b )
VImage
operator<<( VImage a, double b )
{
return( a.boolean_const( to_vector( b ),
VIPS_OPERATION_BOOLEAN_LSHIFT ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_LSHIFT,
to_vector( b ) ) );
}
VImage
operator<<( VImage a, std::vector<double> b )
{
return( a.boolean_const( b, VIPS_OPERATION_BOOLEAN_LSHIFT ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_LSHIFT,
b ) );
}
VImage &
operator<<=( VImage a, const VImage b )
operator<<=( VImage &a, const VImage b )
{
return( a = a << b );
}
VImage &
operator<<=( VImage a, const double b )
operator<<=( VImage &a, const double b )
{
return( a = a << b );
}
VImage &
operator<<=( VImage a, std::vector<double> b )
operator<<=( VImage &a, std::vector<double> b )
{
return( a = a << b );
}
@@ -1373,30 +1384,31 @@ operator>>( VImage a, VImage b )
VImage
operator>>( VImage a, double b )
{
return( a.boolean_const( to_vector( b ),
VIPS_OPERATION_BOOLEAN_RSHIFT ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_RSHIFT,
to_vector( b ) ) );
}
VImage
operator>>( VImage a, std::vector<double> b )
{
return( a.boolean_const( b, VIPS_OPERATION_BOOLEAN_RSHIFT ) );
return( a.boolean_const( VIPS_OPERATION_BOOLEAN_RSHIFT,
b ) );
}
VImage &
operator>>=( VImage a, const VImage b )
operator>>=( VImage &a, const VImage b )
{
return( a = a << b );
}
VImage &
operator>>=( VImage a, const double b )
operator>>=( VImage &a, const double b )
{
return( a = a << b );
}
VImage &
operator>>=( VImage a, std::vector<double> b )
operator>>=( VImage &a, std::vector<double> b )
{
return( a = a << b );
}

View File

@@ -1,5 +1,5 @@
// bodies for vips operations
// Thu 18 Aug 16:01:57 BST 2016
// Sun 26 Nov 17:44:23 GMT 2017
// this file is generated automatically, do not edit!
void VImage::system( char * cmd_format , VOption *options )
@@ -231,7 +231,7 @@ VImage VImage::round( VipsOperationRound round , VOption *options )
return( out );
}
VImage VImage::relational_const( std::vector<double> c , VipsOperationRelational relational , VOption *options )
VImage VImage::relational_const( VipsOperationRelational relational , std::vector<double> c , VOption *options )
{
VImage out;
@@ -239,8 +239,8 @@ VImage VImage::relational_const( std::vector<double> c , VipsOperationRelational
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "c", c ) ->
set( "relational", relational ) );
set( "relational", relational ) ->
set( "c", c ) );
return( out );
}
@@ -258,7 +258,7 @@ VImage VImage::remainder_const( std::vector<double> c , VOption *options )
return( out );
}
VImage VImage::boolean_const( std::vector<double> c , VipsOperationBoolean boolean , VOption *options )
VImage VImage::boolean_const( VipsOperationBoolean boolean , std::vector<double> c , VOption *options )
{
VImage out;
@@ -266,13 +266,13 @@ VImage VImage::boolean_const( std::vector<double> c , VipsOperationBoolean boole
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "c", c ) ->
set( "boolean", boolean ) );
set( "boolean", boolean ) ->
set( "c", c ) );
return( out );
}
VImage VImage::math2_const( std::vector<double> c , VipsOperationMath2 math2 , VOption *options )
VImage VImage::math2_const( VipsOperationMath2 math2 , std::vector<double> c , VOption *options )
{
VImage out;
@@ -280,8 +280,8 @@ VImage VImage::math2_const( std::vector<double> c , VipsOperationMath2 math2 , V
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "c", c ) ->
set( "math2", math2 ) );
set( "math2", math2 ) ->
set( "c", c ) );
return( out );
}
@@ -487,14 +487,29 @@ std::vector<double> VImage::getpoint( int x , int y , VOption *options )
return( out_array );
}
int VImage::find_trim( int * top , int * width , int * height , VOption *options )
{
int left;
call( "find_trim" ,
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "left", &left ) ->
set( "top", top ) ->
set( "width", width ) ->
set( "height", height ) );
return( left );
}
VImage VImage::copy( VOption *options )
{
VImage out;
call( "copy" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -505,8 +520,8 @@ VImage VImage::tilecache( VOption *options )
call( "tilecache" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -517,8 +532,8 @@ VImage VImage::linecache( VOption *options )
call( "linecache" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -529,8 +544,8 @@ VImage VImage::sequential( VOption *options )
call( "sequential" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -541,8 +556,8 @@ VImage VImage::cache( VOption *options )
call( "cache" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -563,14 +578,29 @@ VImage VImage::embed( int x , int y , int width , int height , VOption *options
return( out );
}
VImage VImage::gravity( VipsCompassDirection direction , int width , int height , VOption *options )
{
VImage out;
call( "gravity" ,
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "direction", direction ) ->
set( "width", width ) ->
set( "height", height ) );
return( out );
}
VImage VImage::flip( VipsDirection direction , VOption *options )
{
VImage out;
call( "flip" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "direction", direction ) );
return( out );
@@ -633,6 +663,20 @@ VImage VImage::extract_area( int left , int top , int width , int height , VOpti
return( out );
}
VImage VImage::smartcrop( int width , int height , VOption *options )
{
VImage out;
call( "smartcrop" ,
(options ? options : VImage::option()) ->
set( "input", *this ) ->
set( "out", &out ) ->
set( "width", width ) ->
set( "height", height ) );
return( out );
}
VImage VImage::extract_band( int band , VOption *options )
{
VImage out;
@@ -728,8 +772,8 @@ VImage VImage::cast( VipsBandFormat format , VOption *options )
call( "cast" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "format", format ) );
return( out );
@@ -741,8 +785,8 @@ VImage VImage::rot( VipsAngle angle , VOption *options )
call( "rot" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "angle", angle ) );
return( out );
@@ -754,8 +798,8 @@ VImage VImage::rot45( VOption *options )
call( "rot45" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -766,8 +810,8 @@ VImage VImage::autorot( VOption *options )
call( "autorot" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -805,8 +849,8 @@ VImage VImage::bandfold( VOption *options )
call( "bandfold" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -817,8 +861,8 @@ VImage VImage::bandunfold( VOption *options )
call( "bandunfold" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -829,8 +873,8 @@ VImage VImage::flatten( VOption *options )
call( "flatten" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -841,8 +885,8 @@ VImage VImage::premultiply( VOption *options )
call( "premultiply" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -853,8 +897,8 @@ VImage VImage::unpremultiply( VOption *options )
call( "unpremultiply" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -865,8 +909,8 @@ VImage VImage::grid( int tile_height , int across , int down , VOption *options
call( "grid" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "tile-height", tile_height ) ->
set( "across", across ) ->
set( "down", down ) );
@@ -880,8 +924,8 @@ VImage VImage::scale( VOption *options )
call( "scale" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -892,8 +936,8 @@ VImage VImage::wrap( VOption *options )
call( "wrap" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -944,8 +988,8 @@ VImage VImage::byteswap( VOption *options )
call( "byteswap" ,
(options ? options : VImage::option()) ->
set( "out", &out ) ->
set( "in", *this ) );
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
@@ -974,6 +1018,19 @@ VImage VImage::gamma( VOption *options )
return( out );
}
VImage VImage::composite( std::vector<VImage> in , std::vector<int> mode , VOption *options )
{
VImage out;
call( "composite" ,
(options ? options : VImage::option()) ->
set( "in", in ) ->
set( "out", &out ) ->
set( "mode", mode ) );
return( out );
}
VImage VImage::black( int width , int height , VOption *options )
{
VImage out;
@@ -1757,6 +1814,18 @@ void VImage::dzsave( char * filename , VOption *options )
set( "filename", filename ) );
}
VipsBlob * VImage::dzsave_buffer( VOption *options )
{
VipsBlob * buffer;
call( "dzsave_buffer" ,
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "buffer", &buffer ) );
return( buffer );
}
void VImage::pngsave( char * filename , VOption *options )
{
call( "pngsave" ,
@@ -1832,6 +1901,18 @@ void VImage::tiffsave( char * filename , VOption *options )
set( "filename", filename ) );
}
VipsBlob * VImage::tiffsave_buffer( VOption *options )
{
VipsBlob * buffer;
call( "tiffsave_buffer" ,
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "buffer", &buffer ) );
return( buffer );
}
void VImage::fitssave( char * filename , VOption *options )
{
call( "fitssave" ,
@@ -1840,6 +1921,45 @@ void VImage::fitssave( char * filename , VOption *options )
set( "filename", filename ) );
}
VImage VImage::thumbnail( char * filename , int width , VOption *options )
{
VImage out;
call( "thumbnail" ,
(options ? options : VImage::option()) ->
set( "filename", filename ) ->
set( "out", &out ) ->
set( "width", width ) );
return( out );
}
VImage VImage::thumbnail_buffer( VipsBlob * buffer , int width , VOption *options )
{
VImage out;
call( "thumbnail_buffer" ,
(options ? options : VImage::option()) ->
set( "buffer", buffer ) ->
set( "out", &out ) ->
set( "width", width ) );
return( out );
}
VImage VImage::thumbnail_image( int width , VOption *options )
{
VImage out;
call( "thumbnail_image" ,
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "out", &out ) ->
set( "width", width ) );
return( out );
}
VImage VImage::mapim( VImage index , VOption *options )
{
VImage out;
@@ -2758,6 +2878,18 @@ VImage VImage::labelregions( VOption *options )
return( mask );
}
VImage VImage::fill_nearest( VOption *options )
{
VImage out;
call( "fill_nearest" ,
(options ? options : VImage::option()) ->
set( "in", *this ) ->
set( "out", &out ) );
return( out );
}
void VImage::draw_rect( std::vector<double> ink , int left , int top , int width , int height , VOption *options )
{
call( "draw_rect" ,

View File

@@ -1,25 +1,41 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <numeric>
#include <vector>
#include <node.h>
#include <nan.h>
#include <vips/vips8>
#include "nan.h"
#include "common.h"
#include "metadata.h"
class MetadataWorker : public Nan::AsyncWorker {
public:
MetadataWorker(
Nan::Callback *callback, MetadataBaton *baton,
std::vector<v8::Local<v8::Object>> const buffersToPersist
) : Nan::AsyncWorker(callback), baton(baton), buffersToPersist(buffersToPersist) {
Nan::Callback *callback, MetadataBaton *baton, Nan::Callback *debuglog,
std::vector<v8::Local<v8::Object>> const buffersToPersist) :
Nan::AsyncWorker(callback, "sharp:MetadataWorker"),
baton(baton), debuglog(debuglog),
buffersToPersist(buffersToPersist) {
// Protect Buffer objects from GC, keyed on index
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
SaveToPersistent(index, buffer);
return index + 1;
}
);
});
}
~MetadataWorker() {}
@@ -42,6 +58,7 @@ class MetadataWorker : public Nan::AsyncWorker {
baton->height = image.height();
baton->space = vips_enum_nick(VIPS_TYPE_INTERPRETATION, image.interpretation());
baton->channels = image.bands();
baton->depth = vips_enum_nick(VIPS_TYPE_BAND_FORMAT, image.format());
if (sharp::HasDensity(image)) {
baton->density = sharp::GetDensity(image);
}
@@ -65,6 +82,22 @@ class MetadataWorker : public Nan::AsyncWorker {
memcpy(baton->icc, icc, iccLength);
baton->iccLength = iccLength;
}
// IPTC
if (image.get_typeof(VIPS_META_IPTC_NAME) == VIPS_TYPE_BLOB) {
size_t iptcLength;
void const *iptc = image.get_blob(VIPS_META_IPTC_NAME, &iptcLength);
baton->iptc = static_cast<char *>(g_malloc(iptcLength));
memcpy(baton->iptc, iptc, iptcLength);
baton->iptcLength = iptcLength;
}
// XMP
if (image.get_typeof(VIPS_META_XMP_NAME) == VIPS_TYPE_BLOB) {
size_t xmpLength;
void const *xmp = image.get_blob(VIPS_META_XMP_NAME, &xmpLength);
baton->xmp = static_cast<char *>(g_malloc(xmpLength));
memcpy(baton->xmp, xmp, xmpLength);
baton->xmpLength = xmpLength;
}
}
// Clean up
@@ -72,7 +105,7 @@ class MetadataWorker : public Nan::AsyncWorker {
vips_thread_shutdown();
}
void HandleOKCallback () {
void HandleOKCallback() {
using Nan::New;
using Nan::Set;
Nan::HandleScope();
@@ -88,6 +121,7 @@ class MetadataWorker : public Nan::AsyncWorker {
Set(info, New("height").ToLocalChecked(), New<v8::Uint32>(baton->height));
Set(info, New("space").ToLocalChecked(), New<v8::String>(baton->space).ToLocalChecked());
Set(info, New("channels").ToLocalChecked(), New<v8::Uint32>(baton->channels));
Set(info, New("depth").ToLocalChecked(), New<v8::String>(baton->depth).ToLocalChecked());
if (baton->density > 0) {
Set(info, New("density").ToLocalChecked(), New<v8::Uint32>(baton->density));
}
@@ -99,14 +133,22 @@ class MetadataWorker : public Nan::AsyncWorker {
if (baton->exifLength > 0) {
Set(info,
New("exif").ToLocalChecked(),
Nan::NewBuffer(baton->exif, baton->exifLength, sharp::FreeCallback, nullptr).ToLocalChecked()
);
Nan::NewBuffer(baton->exif, baton->exifLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
if (baton->iccLength > 0) {
Set(info,
New("icc").ToLocalChecked(),
Nan::NewBuffer(baton->icc, baton->iccLength, sharp::FreeCallback, nullptr).ToLocalChecked()
);
Nan::NewBuffer(baton->icc, baton->iccLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
if (baton->iptcLength > 0) {
Set(info,
New("iptc").ToLocalChecked(),
Nan::NewBuffer(baton->iptc, baton->iptcLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
if (baton->xmpLength > 0) {
Set(info,
New("xmp").ToLocalChecked(),
Nan::NewBuffer(baton->xmp, baton->xmpLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
argv[1] = info;
}
@@ -116,17 +158,25 @@ class MetadataWorker : public Nan::AsyncWorker {
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
GetFromPersistent(index);
return index + 1;
}
);
});
delete baton->input;
delete baton;
// Handle warnings
std::string warning = sharp::VipsWarningPop();
while (!warning.empty()) {
v8::Local<v8::Value> message[1] = { New(warning).ToLocalChecked() };
debuglog->Call(1, message, async_resource);
warning = sharp::VipsWarningPop();
}
// Return to JavaScript
callback->Call(2, argv);
callback->Call(2, argv, async_resource);
}
private:
MetadataBaton* baton;
Nan::Callback *debuglog;
std::vector<v8::Local<v8::Object>> buffersToPersist;
};
@@ -144,9 +194,12 @@ NAN_METHOD(metadata) {
// Input
baton->input = sharp::CreateInputDescriptor(sharp::AttrAs<v8::Object>(options, "input"), buffersToPersist);
// Function to notify of libvips warnings
Nan::Callback *debuglog = new Nan::Callback(sharp::AttrAs<v8::Function>(options, "debuglog"));
// Join queue for worker thread
Nan::Callback *callback = new Nan::Callback(info[1].As<v8::Function>());
Nan::AsyncQueueWorker(new MetadataWorker(callback, baton, buffersToPersist));
Nan::AsyncQueueWorker(new MetadataWorker(callback, baton, debuglog, buffersToPersist));
// Increment queued task counter
g_atomic_int_inc(&sharp::counterQueue);

View File

@@ -1,8 +1,24 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_METADATA_H_
#define SRC_METADATA_H_
#include "nan.h"
#include "common.h"
#include <string>
#include <nan.h>
#include "./common.h"
struct MetadataBaton {
// Input
@@ -13,6 +29,7 @@ struct MetadataBaton {
int height;
std::string space;
int channels;
std::string depth;
int density;
bool hasProfile;
bool hasAlpha;
@@ -21,6 +38,10 @@ struct MetadataBaton {
size_t exifLength;
char *icc;
size_t iccLength;
char *iptc;
size_t iptcLength;
char *xmp;
size_t xmpLength;
std::string err;
MetadataBaton():
@@ -35,7 +56,11 @@ struct MetadataBaton {
exif(nullptr),
exifLength(0),
icc(nullptr),
iccLength(0) {}
iccLength(0),
iptc(nullptr),
iptcLength(0),
xmp(nullptr),
xmpLength(0) {}
};
NAN_METHOD(metadata);

View File

@@ -1,7 +1,23 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <functional>
#include <memory>
#include <tuple>
#include <vector>
#include <vips/vips8>
#include "common.h"
@@ -13,69 +29,42 @@ using vips::VError;
namespace sharp {
/*
Alpha composite src over dst with given gravity.
Assumes alpha channels are already premultiplied and will be unpremultiplied after.
Removes alpha channel, if any.
*/
VImage RemoveAlpha(VImage image) {
if (HasAlpha(image)) {
image = image.extract_band(0, VImage::option()->set("n", image.bands() - 1));
}
return image;
}
/*
Composite overlayImage over image at given position
Assumes alpha channels are already premultiplied and will be unpremultiplied after
*/
VImage Composite(VImage src, VImage dst, const int gravity) {
if(IsInputValidForComposition(src, dst)) {
// Enlarge overlay src, if required
if (src.width() < dst.width() || src.height() < dst.height()) {
// Calculate the (left, top) coordinates of the output image within the input image, applying the given gravity.
int left;
int top;
std::tie(left, top) = CalculateCrop(dst.width(), dst.height(), src.width(), src.height(), gravity);
// Embed onto transparent background
std::vector<double> background { 0.0, 0.0, 0.0, 0.0 };
src = src.embed(left, top, dst.width(), dst.height(), VImage::option()
VImage Composite(VImage image, VImage overlayImage, int const left, int const top) {
if (HasAlpha(overlayImage)) {
// Alpha composite
if (overlayImage.width() < image.width() || overlayImage.height() < image.height()) {
// Enlarge overlay
std::vector<double> const background { 0.0, 0.0, 0.0, 0.0 };
overlayImage = overlayImage.embed(left, top, image.width(), image.height(), VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background)
);
->set("background", background));
}
return CompositeImage(src, dst);
}
// If the input was not valid for composition the return the input image itself
return dst;
}
VImage Composite(VImage src, VImage dst, const int x, const int y) {
if(IsInputValidForComposition(src, dst)) {
// Enlarge overlay src, if required
if (src.width() < dst.width() || src.height() < dst.height()) {
// Calculate the (left, top) coordinates of the output image within the input image, applying the given gravity.
int left;
int top;
std::tie(left, top) = CalculateCrop(dst.width(), dst.height(), src.width(), src.height(), x, y);
// Embed onto transparent background
std::vector<double> background { 0.0, 0.0, 0.0, 0.0 };
src = src.embed(left, top, dst.width(), dst.height(), VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background)
);
return AlphaComposite(image, overlayImage);
} else {
if (HasAlpha(image)) {
// Add alpha channel to overlayImage so channels match
double const multiplier = sharp::Is16Bit(overlayImage.interpretation()) ? 256.0 : 1.0;
overlayImage = overlayImage.bandjoin(
VImage::new_matrix(overlayImage.width(), overlayImage.height()).new_from_image(255 * multiplier));
}
return CompositeImage(src, dst);
return image.insert(overlayImage, left, top);
}
// If the input was not valid for composition the return the input image itself
return dst;
}
bool IsInputValidForComposition(VImage src, VImage dst) {
using sharp::CalculateCrop;
using sharp::HasAlpha;
if (!HasAlpha(src)) {
throw VError("Overlay image must have an alpha channel");
}
if (!HasAlpha(dst)) {
throw VError("Image to be overlaid must have an alpha channel");
}
if (src.width() > dst.width() || src.height() > dst.height()) {
throw VError("Overlay image must have same dimensions or smaller");
}
return true;
}
VImage CompositeImage(VImage src, VImage dst) {
VImage AlphaComposite(VImage dst, VImage src) {
// Split src into non-alpha and alpha channels
VImage srcWithoutAlpha = src.extract_band(0, VImage::option()->set("n", src.bands() - 1));
VImage srcAlpha = src[src.bands() - 1] * (1.0 / 255.0);
@@ -145,12 +134,11 @@ namespace sharp {
std::vector<double> background { 0.0, 0.0, 0.0, 0.0 };
mask = mask.embed(left, top, dst.width(), dst.height(), VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background)
);
->set("background", background));
}
// we use the mask alpha if it has alpha
if(maskHasAlpha) {
if (maskHasAlpha) {
mask = mask.extract_band(mask.bands() - 1, VImage::option()->set("n", 1));;
}
@@ -174,6 +162,33 @@ namespace sharp {
return dst.bandjoin(mask.cast(dst.format()));
}
/*
* Tint an image using the specified chroma, preserving the original image luminance
*/
VImage Tint(VImage image, double const a, double const b) {
// Get original colourspace
VipsInterpretation typeBeforeTint = image.interpretation();
if (typeBeforeTint == VIPS_INTERPRETATION_RGB) {
typeBeforeTint = VIPS_INTERPRETATION_sRGB;
}
// Extract luminance
VImage luminance = image.colourspace(VIPS_INTERPRETATION_LAB)[0];
// Create the tinted version by combining the L from the original and the chroma from the tint
std::vector<double> chroma {a, b};
VImage tinted = luminance
.bandjoin(chroma)
.copy(VImage::option()->set("interpretation", VIPS_INTERPRETATION_LAB))
.colourspace(typeBeforeTint);
// Attach original alpha channel, if any
if (HasAlpha(image)) {
// Extract original alpha channel
VImage alpha = image[image.bands() - 1];
// Join alpha channel to normalised image
tinted = tinted.bandjoin(alpha);
}
return tinted;
}
/*
* Stretch luminance to cover full dynamic range.
*/
@@ -218,10 +233,8 @@ namespace sharp {
VImage Gamma(VImage image, double const exponent) {
if (HasAlpha(image)) {
// Separate alpha channel
VImage imageWithoutAlpha = image.extract_band(0,
VImage::option()->set("n", image.bands() - 1));
VImage alpha = image[image.bands() - 1];
return imageWithoutAlpha.gamma(VImage::option()->set("exponent", exponent)).bandjoin(alpha);
return RemoveAlpha(image).gamma(VImage::option()->set("exponent", exponent)).bandjoin(alpha);
} else {
return image.gamma(VImage::option()->set("exponent", exponent));
}
@@ -284,143 +297,13 @@ namespace sharp {
colourspaceBeforeSharpen = VIPS_INTERPRETATION_sRGB;
}
return image.sharpen(
VImage::option()->set("sigma", sigma)->set("m1", flat)->set("m2", jagged)
).colourspace(colourspaceBeforeSharpen);
VImage::option()->set("sigma", sigma)->set("m1", flat)->set("m2", jagged))
.colourspace(colourspaceBeforeSharpen);
}
}
/*
Calculate the Shannon entropy
*/
double EntropyStrategy::operator()(VImage image) {
return image.hist_find().hist_entropy();
}
/*
Calculate the intensity of edges, skin tone and saturation
*/
double AttentionStrategy::operator()(VImage image) {
// Flatten RGBA onto a mid-grey background
if (image.bands() == 4 && HasAlpha(image)) {
double const midgrey = sharp::Is16Bit(image.interpretation()) ? 32768.0 : 128.0;
std::vector<double> background { midgrey, midgrey, midgrey };
image = image.flatten(VImage::option()->set("background", background));
}
// Convert to LAB colourspace
VImage lab = image.colourspace(VIPS_INTERPRETATION_LAB);
VImage l = lab[0];
VImage a = lab[1];
VImage b = lab[2];
// Edge detect luminosity with the Sobel operator
VImage sobel = vips::VImage::new_matrixv(3, 3,
-1.0, 0.0, 1.0,
-2.0, 0.0, 2.0,
-1.0, 0.0, 1.0);
VImage edges = l.conv(sobel).abs() + l.conv(sobel.rot90()).abs();
// Skin tone chroma thresholds trained with http://humanae.tumblr.com/
VImage skin = (a >= 3) & (a <= 22) & (b >= 4) & (b <= 31);
// Chroma >~50% saturation
VImage lch = lab.colourspace(VIPS_INTERPRETATION_LCH);
VImage c = lch[1];
VImage saturation = c > 60;
// Find maximum in combined saliency mask
VImage mask = edges + skin + saturation;
return mask.max();
}
/*
Calculate crop area based on image entropy
*/
std::tuple<int, int> Crop(
VImage image, int const outWidth, int const outHeight, std::function<double(VImage)> strategy
) {
int left = 0;
int top = 0;
int const inWidth = image.width();
int const inHeight = image.height();
if (inWidth > outWidth) {
// Reduce width by repeated removing slices from edge with lowest score
int width = inWidth;
double leftScore = 0.0;
double rightScore = 0.0;
// Max width of each slice
int const maxSliceWidth = static_cast<int>(ceil((inWidth - outWidth) / 8.0));
while (width > outWidth) {
// Width of current slice
int const slice = std::min(width - outWidth, maxSliceWidth);
if (leftScore == 0.0) {
// Update score of left slice
leftScore = strategy(image.extract_area(left, 0, slice, inHeight));
}
if (rightScore == 0.0) {
// Update score of right slice
rightScore = strategy(image.extract_area(width - slice - 1, 0, slice, inHeight));
}
// Keep slice with highest score
if (leftScore >= rightScore) {
// Discard right slice
rightScore = 0.0;
} else {
// Discard left slice
leftScore = 0.0;
left = left + slice;
}
width = width - slice;
}
}
if (inHeight > outHeight) {
// Reduce height by repeated removing slices from edge with lowest score
int height = inHeight;
double topScore = 0.0;
double bottomScore = 0.0;
// Max height of each slice
int const maxSliceHeight = static_cast<int>(ceil((inHeight - outHeight) / 8.0));
while (height > outHeight) {
// Height of current slice
int const slice = std::min(height - outHeight, maxSliceHeight);
if (topScore == 0.0) {
// Update score of top slice
topScore = strategy(image.extract_area(0, top, inWidth, slice));
}
if (bottomScore == 0.0) {
// Update score of bottom slice
bottomScore = strategy(image.extract_area(0, height - slice - 1, inWidth, slice));
}
// Keep slice with highest score
if (topScore >= bottomScore) {
// Discard bottom slice
bottomScore = 0.0;
} else {
// Discard top slice
topScore = 0.0;
top = top + slice;
}
height = height - slice;
}
}
return std::make_tuple(left, top);
}
/*
Insert a tile cache to prevent over-computation of any previous operations in the pipeline
*/
VImage TileCache(VImage image, double const factor) {
int tile_width;
int tile_height;
int scanline_count;
vips_get_tile_size(image.get_image(), &tile_width, &tile_height, &scanline_count);
double const need_lines = 1.2 * scanline_count / factor;
return image.tilecache(VImage::option()
->set("tile_width", image.width())
->set("tile_height", 10)
->set("max_tiles", static_cast<int>(round(1.0 + need_lines / 10.0)))
->set("access", VIPS_ACCESS_SEQUENTIAL)
->set("threaded", TRUE)
);
}
VImage Threshold(VImage image, double const threshold, bool const thresholdGrayscale) {
if(!thresholdGrayscale) {
if (!thresholdGrayscale) {
return image >= threshold;
}
return image.colourspace(VIPS_INTERPRETATION_B_W) >= threshold;
@@ -485,7 +368,7 @@ namespace sharp {
int width = right - left;
int height = bottom - top;
if(width <= 0 || height <= 0) {
if (width <= 0 || height <= 0) {
throw VError("Unexpected error while trimming. Try to lower the tolerance");
}
@@ -493,4 +376,16 @@ namespace sharp {
return image.extract_area(left, top, width, height);
}
/*
* Calculate (a * in + b)
*/
VImage Linear(VImage image, double const a, double const b) {
if (HasAlpha(image)) {
// Separate alpha channel
VImage alpha = image[image.bands() - 1];
return RemoveAlpha(image).linear(a, b).bandjoin(alpha);
} else {
return image.linear(a, b);
}
}
} // namespace sharp

View File

@@ -1,3 +1,17 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_OPERATIONS_H_
#define SRC_OPERATIONS_H_
@@ -11,6 +25,11 @@ using vips::VImage;
namespace sharp {
/*
Removes alpha channel, if any.
*/
VImage RemoveAlpha(VImage image);
/*
Alpha composite src over dst with given gravity.
Assumes alpha channels are already premultiplied and will be unpremultiplied after.
@@ -18,26 +37,25 @@ namespace sharp {
VImage Composite(VImage src, VImage dst, const int gravity);
/*
Alpha composite src over dst with given x and y offsets.
Assumes alpha channels are already premultiplied and will be unpremultiplied after.
Composite overlayImage over image at given position
*/
VImage Composite(VImage src, VImage dst, const int x, const int y);
VImage Composite(VImage image, VImage overlayImage, int const x, int const y);
/*
Check if the src and dst Images for composition operation are valid
Alpha composite overlayImage over image, assumes matching dimensions
*/
bool IsInputValidForComposition(VImage src, VImage dst);
/*
Given a valid src and dst, returns the composite of the two images
*/
VImage CompositeImage(VImage src, VImage dst);
VImage AlphaComposite(VImage image, VImage overlayImage);
/*
Cutout src over dst with given gravity.
*/
VImage Cutout(VImage src, VImage dst, const int gravity);
/*
* Tint an image using the specified chroma, preserving the original image luminance
*/
VImage Tint(VImage image, double const a, double const b);
/*
* Stretch luminance to cover full dynamic range.
*/
@@ -64,28 +82,6 @@ namespace sharp {
*/
VImage Sharpen(VImage image, double const sigma, double const flat, double const jagged);
/*
Crop strategy functors
*/
struct EntropyStrategy {
double operator()(VImage image);
};
struct AttentionStrategy {
double operator()(VImage image);
};
/*
Calculate crop area based on given strategy (Entropy, Attention)
*/
std::tuple<int, int> Crop(
VImage image, int const outWidth, int const outHeight, std::function<double(VImage)> strategy
);
/*
Insert a tile cache to prevent over-computation of any previous operations in the pipeline
*/
VImage TileCache(VImage image, double const factor);
/*
Threshold an image
*/
@@ -106,6 +102,11 @@ namespace sharp {
*/
VImage Trim(VImage image, int const tolerance);
/*
* Linear adjustment (a * in + b)
*/
VImage Linear(VImage image, double const a, double const b);
} // namespace sharp
#endif // SRC_OPERATIONS_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,28 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_PIPELINE_H_
#define SRC_PIPELINE_H_
#include <memory>
#include <string>
#include <vector>
#include <nan.h>
#include <vips/vips8>
#include "nan.h"
#include "common.h"
#include "./common.h"
NAN_METHOD(pipeline);
@@ -46,24 +62,32 @@ struct PipelineBaton {
int channels;
Canvas canvas;
int crop;
int cropCalcLeft;
int cropCalcTop;
int embed;
bool hasCropOffset;
int cropOffsetLeft;
int cropOffsetTop;
bool premultiplied;
std::string kernel;
std::string interpolator;
bool centreSampling;
bool fastShrinkOnLoad;
double background[4];
double tintA;
double tintB;
bool flatten;
bool negate;
double blurSigma;
int medianSize;
double sharpenSigma;
double sharpenFlat;
double sharpenJagged;
int threshold;
bool thresholdGrayscale;
int trimTolerance;
double linearA;
double linearB;
double gamma;
bool greyscale;
bool normalise;
bool useExifOrientation;
int angle;
bool rotateBeforePreExtract;
bool flip;
@@ -78,13 +102,23 @@ struct PipelineBaton {
bool jpegProgressive;
std::string jpegChromaSubsampling;
bool jpegTrellisQuantisation;
int jpegQuantisationTable;
bool jpegOvershootDeringing;
bool jpegOptimiseScans;
bool jpegOptimiseCoding;
bool pngProgressive;
int pngCompressionLevel;
bool pngAdaptiveFiltering;
int webpQuality;
int webpAlphaQuality;
bool webpNearLossless;
bool webpLossless;
int tiffQuality;
VipsForeignTiffCompression tiffCompression;
VipsForeignTiffPredictor tiffPredictor;
bool tiffSquash;
double tiffXres;
double tiffYres;
std::string err;
bool withMetadata;
int withMetadataOrientation;
@@ -97,12 +131,15 @@ struct PipelineBaton {
VipsOperationBoolean booleanOp;
VipsOperationBoolean bandBoolOp;
int extractChannel;
bool removeAlpha;
VipsInterpretation colourspace;
int tileSize;
int tileOverlap;
VipsForeignDzContainer tileContainer;
VipsForeignDzLayout tileLayout;
std::string tileFormat;
int tileAngle;
VipsForeignDzDepth tileDepth;
PipelineBaton():
input(nullptr),
@@ -119,21 +156,29 @@ struct PipelineBaton {
channels(0),
canvas(Canvas::CROP),
crop(0),
cropCalcLeft(-1),
cropCalcTop(-1),
centreSampling(false),
embed(0),
hasCropOffset(false),
cropOffsetLeft(0),
cropOffsetTop(0),
premultiplied(false),
tintA(128.0),
tintB(128.0),
flatten(false),
negate(false),
blurSigma(0.0),
medianSize(0),
sharpenSigma(0.0),
sharpenFlat(1.0),
sharpenJagged(2.0),
threshold(0),
thresholdGrayscale(true),
trimTolerance(0),
linearA(1.0),
linearB(0.0),
gamma(0.0),
greyscale(false),
normalise(false),
useExifOrientation(false),
angle(0),
flip(false),
flop(false),
@@ -146,13 +191,20 @@ struct PipelineBaton {
jpegProgressive(false),
jpegChromaSubsampling("4:2:0"),
jpegTrellisQuantisation(false),
jpegQuantisationTable(0),
jpegOvershootDeringing(false),
jpegOptimiseScans(false),
jpegOptimiseCoding(true),
pngProgressive(false),
pngCompressionLevel(6),
pngAdaptiveFiltering(true),
pngCompressionLevel(9),
pngAdaptiveFiltering(false),
webpQuality(80),
tiffQuality(80),
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
tiffSquash(false),
tiffXres(1.0),
tiffYres(1.0),
withMetadata(false),
withMetadataOrientation(-1),
convKernelWidth(0),
@@ -163,11 +215,14 @@ struct PipelineBaton {
booleanOp(VIPS_OPERATION_BOOLEAN_LAST),
bandBoolOp(VIPS_OPERATION_BOOLEAN_LAST),
extractChannel(-1),
removeAlpha(false),
colourspace(VIPS_INTERPRETATION_LAST),
tileSize(256),
tileOverlap(0),
tileContainer(VIPS_FOREIGN_DZ_CONTAINER_FS),
tileLayout(VIPS_FOREIGN_DZ_LAYOUT_DZ) {
tileLayout(VIPS_FOREIGN_DZ_LAYOUT_DZ),
tileAngle(0),
tileDepth(VIPS_FOREIGN_DZ_DEPTH_LAST){
background[0] = 0.0;
background[1] = 0.0;
background[2] = 0.0;

View File

@@ -1,16 +1,33 @@
#include <node.h>
#include <vips/vips8>
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "nan.h"
#include <node.h>
#include <nan.h>
#include <vips/vips8>
#include "common.h"
#include "metadata.h"
#include "pipeline.h"
#include "utilities.h"
#include "stats.h"
NAN_MODULE_INIT(init) {
vips_init("sharp");
g_log_set_handler("VIPS", static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING),
static_cast<GLogFunc>(sharp::VipsWarningCallback), nullptr);
// Methods available to JavaScript
Nan::Set(target, Nan::New("metadata").ToLocalChecked(),
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(metadata)).ToLocalChecked());
@@ -30,6 +47,8 @@ NAN_MODULE_INIT(init) {
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(format)).ToLocalChecked());
Nan::Set(target, Nan::New("_maxColourDistance").ToLocalChecked(),
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(_maxColourDistance)).ToLocalChecked());
Nan::Set(target, Nan::New("stats").ToLocalChecked(),
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(stats)).ToLocalChecked());
}
NODE_MODULE(sharp, init)

192
src/stats.cc Normal file
View File

@@ -0,0 +1,192 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <numeric>
#include <vector>
#include <iostream>
#include <node.h>
#include <nan.h>
#include <vips/vips8>
#include "common.h"
#include "stats.h"
class StatsWorker : public Nan::AsyncWorker {
public:
StatsWorker(
Nan::Callback *callback, StatsBaton *baton, Nan::Callback *debuglog,
std::vector<v8::Local<v8::Object>> const buffersToPersist) :
Nan::AsyncWorker(callback, "sharp:StatsWorker"),
baton(baton), debuglog(debuglog),
buffersToPersist(buffersToPersist) {
// Protect Buffer objects from GC, keyed on index
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
SaveToPersistent(index, buffer);
return index + 1;
});
}
~StatsWorker() {}
const int STAT_MIN_INDEX = 0;
const int STAT_MAX_INDEX = 1;
const int STAT_SUM_INDEX = 2;
const int STAT_SQ_SUM_INDEX = 3;
const int STAT_MEAN_INDEX = 4;
const int STAT_STDEV_INDEX = 5;
const int STAT_MINX_INDEX = 6;
const int STAT_MINY_INDEX = 7;
const int STAT_MAXX_INDEX = 8;
const int STAT_MAXY_INDEX = 9;
void Execute() {
// Decrement queued task counter
g_atomic_int_dec_and_test(&sharp::counterQueue);
using Nan::New;
using Nan::Set;
using sharp::MaximumImageAlpha;
vips::VImage image;
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
try {
std::tie(image, imageType) = OpenInput(baton->input, baton->accessMethod);
} catch (vips::VError const &err) {
(baton->err).append(err.what());
}
if (imageType != sharp::ImageType::UNKNOWN) {
try {
vips::VImage stats = image.stats();
int const bands = image.bands();
for (int b = 1; b <= bands; b++) {
ChannelStats cStats(static_cast<int>(stats.getpoint(STAT_MIN_INDEX, b).front()),
static_cast<int>(stats.getpoint(STAT_MAX_INDEX, b).front()),
stats.getpoint(STAT_SUM_INDEX, b).front(), stats.getpoint(STAT_SQ_SUM_INDEX, b).front(),
stats.getpoint(STAT_MEAN_INDEX, b).front(), stats.getpoint(STAT_STDEV_INDEX, b).front(),
static_cast<int>(stats.getpoint(STAT_MINX_INDEX, b).front()),
static_cast<int>(stats.getpoint(STAT_MINY_INDEX, b).front()),
static_cast<int>(stats.getpoint(STAT_MAXX_INDEX, b).front()),
static_cast<int>(stats.getpoint(STAT_MAXY_INDEX, b).front()));
baton->channelStats.push_back(cStats);
}
// Image is not opaque when alpha layer is present and contains a non-mamixa value
if (sharp::HasAlpha(image)) {
double const minAlpha = static_cast<double>(stats.getpoint(STAT_MIN_INDEX, bands).front());
if (minAlpha != MaximumImageAlpha(image.interpretation())) {
baton->isOpaque = false;
}
}
// Estimate entropy via histogram of greyscale value frequency
baton->entropy = std::abs(image.colourspace(VIPS_INTERPRETATION_B_W)[0].hist_find().hist_entropy());
} catch (vips::VError const &err) {
(baton->err).append(err.what());
}
}
// Clean up
vips_error_clear();
vips_thread_shutdown();
}
void HandleOKCallback() {
using Nan::New;
using Nan::Set;
Nan::HandleScope();
v8::Local<v8::Value> argv[2] = { Nan::Null(), Nan::Null() };
if (!baton->err.empty()) {
argv[0] = Nan::Error(baton->err.data());
} else {
// Stats Object
v8::Local<v8::Object> info = New<v8::Object>();
v8::Local<v8::Array> channels = New<v8::Array>();
std::vector<ChannelStats>::iterator it;
int i = 0;
for (it=baton->channelStats.begin() ; it < baton->channelStats.end(); it++, i++) {
v8::Local<v8::Object> channelStat = New<v8::Object>();
Set(channelStat, New("min").ToLocalChecked(), New<v8::Number>(it->min));
Set(channelStat, New("max").ToLocalChecked(), New<v8::Number>(it->max));
Set(channelStat, New("sum").ToLocalChecked(), New<v8::Number>(it->sum));
Set(channelStat, New("squaresSum").ToLocalChecked(), New<v8::Number>(it->squaresSum));
Set(channelStat, New("mean").ToLocalChecked(), New<v8::Number>(it->mean));
Set(channelStat, New("stdev").ToLocalChecked(), New<v8::Number>(it->stdev));
Set(channelStat, New("minX").ToLocalChecked(), New<v8::Number>(it->minX));
Set(channelStat, New("minY").ToLocalChecked(), New<v8::Number>(it->minY));
Set(channelStat, New("maxX").ToLocalChecked(), New<v8::Number>(it->maxX));
Set(channelStat, New("maxY").ToLocalChecked(), New<v8::Number>(it->maxY));
channels->Set(i, channelStat);
}
Set(info, New("channels").ToLocalChecked(), channels);
Set(info, New("isOpaque").ToLocalChecked(), New<v8::Boolean>(baton->isOpaque));
Set(info, New("entropy").ToLocalChecked(), New<v8::Number>(baton->entropy));
argv[1] = info;
}
// Dispose of Persistent wrapper around input Buffers so they can be garbage collected
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
GetFromPersistent(index);
return index + 1;
});
delete baton->input;
delete baton;
// Handle warnings
std::string warning = sharp::VipsWarningPop();
while (!warning.empty()) {
v8::Local<v8::Value> message[1] = { New(warning).ToLocalChecked() };
debuglog->Call(1, message, async_resource);
warning = sharp::VipsWarningPop();
}
// Return to JavaScript
callback->Call(2, argv, async_resource);
}
private:
StatsBaton* baton;
Nan::Callback *debuglog;
std::vector<v8::Local<v8::Object>> buffersToPersist;
};
/*
stats(options, callback)
*/
NAN_METHOD(stats) {
using sharp::AttrTo;
// Input Buffers must not undergo GC compaction during processing
std::vector<v8::Local<v8::Object>> buffersToPersist;
// V8 objects are converted to non-V8 types held in the baton struct
StatsBaton *baton = new StatsBaton;
v8::Local<v8::Object> options = info[0].As<v8::Object>();
// Input
baton->input = sharp::CreateInputDescriptor(sharp::AttrAs<v8::Object>(options, "input"), buffersToPersist);
baton->accessMethod = AttrTo<bool>(options, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
// Function to notify of libvips warnings
Nan::Callback *debuglog = new Nan::Callback(sharp::AttrAs<v8::Function>(options, "debuglog"));
// Join queue for worker thread
Nan::Callback *callback = new Nan::Callback(info[1].As<v8::Function>());
Nan::AsyncQueueWorker(new StatsWorker(callback, baton, debuglog, buffersToPersist));
// Increment queued task counter
g_atomic_int_inc(&sharp::counterQueue);
}

67
src/stats.h Normal file
View File

@@ -0,0 +1,67 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_STATS_H_
#define SRC_STATS_H_
#include <string>
#include <nan.h>
#include "./common.h"
struct ChannelStats {
// stats per channel
int min;
int max;
double sum;
double squaresSum;
double mean;
double stdev;
int minX;
int minY;
int maxX;
int maxY;
ChannelStats():
min(0), max(0), sum(0), squaresSum(0), mean(0), stdev(0)
, minX(0), minY(0), maxX(0), maxY(0) {}
ChannelStats(int minVal, int maxVal, double sumVal, double squaresSumVal,
double meanVal, double stdevVal, int minXVal, int minYVal, int maxXVal, int maxYVal):
min(minVal), max(maxVal), sum(sumVal), squaresSum(squaresSumVal),
mean(meanVal), stdev(stdevVal), minX(minXVal), minY(minYVal), maxX(maxXVal), maxY(maxYVal) {}
};
struct StatsBaton {
// Input
sharp::InputDescriptor *input;
VipsAccess accessMethod;
// Output
std::vector<ChannelStats> channelStats;
bool isOpaque;
double entropy;
std::string err;
StatsBaton():
input(nullptr),
isOpaque(true),
entropy(0.0)
{}
};
NAN_METHOD(stats);
#endif // SRC_STATS_H_

View File

@@ -1,10 +1,25 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath>
#include <string>
#include <node.h>
#include <nan.h>
#include <vips/vips8>
#include <vips/vector.h>
#include "nan.h"
#include "common.h"
#include "operations.h"
#include "utilities.h"
@@ -45,14 +60,11 @@ NAN_METHOD(cache) {
// Get memory stats
Local<Object> memory = New<Object>();
Set(memory, New("current").ToLocalChecked(),
New<Integer>(static_cast<int>(round(vips_tracked_get_mem() / 1048576)))
);
New<Integer>(static_cast<int>(round(vips_tracked_get_mem() / 1048576))));
Set(memory, New("high").ToLocalChecked(),
New<Integer>(static_cast<int>(round(vips_tracked_get_mem_highwater() / 1048576)))
);
New<Integer>(static_cast<int>(round(vips_tracked_get_mem_highwater() / 1048576))));
Set(memory, New("max").ToLocalChecked(),
New<Integer>(static_cast<int>(round(vips_cache_get_max_mem() / 1048576)))
);
New<Integer>(static_cast<int>(round(vips_cache_get_max_mem() / 1048576))));
// Get file stats
Local<Object> files = New<Object>();
Set(files, New("current").ToLocalChecked(), New<Integer>(vips_tracked_get_files()));

View File

@@ -1,7 +1,21 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_UTILITIES_H_
#define SRC_UTILITIES_H_
#include "nan.h"
#include <nan.h>
NAN_METHOD(cache);
NAN_METHOD(concurrency);

View File

@@ -5,18 +5,19 @@
"author": "Lovell Fuller <npm@lovell.info>",
"description": "Benchmark and performance tests for sharp",
"scripts": {
"test": "VIPS_WARNING=0 node perf && node random && node parallel"
"test": "node perf && node random && node parallel"
},
"devDependencies": {
"async": "^2.1.4",
"benchmark": "^2.1.2",
"gm": "^1.23.0",
"async": "^2.6.0",
"benchmark": "^2.1.4",
"gm": "^1.23.1",
"imagemagick": "^0.1.3",
"imagemagick-native": "^1.9.3",
"jimp": "^0.2.27",
"lwip": "^0.0.9",
"mapnik": "^3.5.14",
"semver": "^5.3.0"
"images": "^3.0.1",
"jimp": "^0.2.28",
"mapnik": "^3.6.2",
"pajk-lwip": "^0.2.0",
"semver": "^5.4.1"
},
"license": "Apache-2.0",
"engines": {

View File

@@ -31,6 +31,7 @@ async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64], function (parallelism, next) {
function (err, ids) {
assert(!err);
assert(ids.length === parallelism);
ids.sort();
const mean = ids.reduce(function (a, b) {
return a + b;
}) / ids.length;

View File

@@ -7,11 +7,17 @@ const assert = require('assert');
const Benchmark = require('benchmark');
// Contenders
const sharp = require('../../');
const gm = require('gm');
const imagemagick = require('imagemagick');
const mapnik = require('mapnik');
const jimp = require('jimp');
const sharp = require('../../');
let images;
try {
images = require('images');
} catch (err) {
console.log('Excluding node-images');
}
let imagemagickNative;
try {
imagemagickNative = require('imagemagick-native');
@@ -20,7 +26,7 @@ try {
}
let lwip;
try {
lwip = require('lwip');
lwip = require('pajk-lwip');
} catch (err) {
console.log('Excluding lwip');
}
@@ -145,7 +151,7 @@ async.series({
}).add('mapnik-buffer-buffer', {
defer: true,
fn: function (deferred) {
mapnik.Image.fromBytes(inputJpgBuffer, function (err, img) {
mapnik.Image.fromBytes(inputJpgBuffer, { max_size: 3000 }, function (err, img) {
if (err) throw err;
img
.resize(width, height, {
@@ -266,6 +272,14 @@ async.series({
});
}
});
// images
if (typeof images !== 'undefined') {
jpegSuite.add('images-file-file', function () {
images(fixtures.inputJpg)
.resize(width, height)
.save(fixtures.outputJpg, { quality: 80 });
});
}
// sharp
jpegSuite.add('sharp-buffer-file', {
defer: true,
@@ -587,7 +601,7 @@ async.series({
callback(null, this.filter('fastest').map('name'));
}).run();
},
// Comparitive speed of kernels
// Comparative speed of kernels
kernels: function (callback) {
const inputJpgBuffer = fs.readFileSync(fixtures.inputJpg);
(new Benchmark.Suite('kernels')).add('sharp-cubic', {
@@ -733,7 +747,7 @@ async.series({
}).add('mapnik-buffer-buffer', {
defer: true,
fn: function (deferred) {
mapnik.Image.fromBytes(inputPngBuffer, function (err, img) {
mapnik.Image.fromBytes(inputPngBuffer, { max_size: 3000 }, function (err, img) {
if (err) throw err;
img.premultiply(function (err, img) {
if (err) throw err;
@@ -819,6 +833,14 @@ async.series({
});
}
});
// images
if (typeof images !== 'undefined') {
pngSuite.add('images-file-file', function () {
images(fixtures.inputPng)
.resize(width, height)
.save(fixtures.outputPng);
});
}
// sharp
pngSuite.add('sharp-buffer-file', {
defer: true,
@@ -889,12 +911,12 @@ async.series({
}
});
}
}).add('sharp-withoutAdaptiveFiltering', {
}).add('sharp-adaptiveFiltering', {
defer: true,
fn: function (deferred) {
sharp(inputPngBuffer)
.resize(width, height)
.png({ adaptiveFiltering: false })
.png({ adaptiveFiltering: true })
.toBuffer(function (err, buffer) {
if (err) {
throw err;
@@ -957,7 +979,7 @@ async.series({
}).add('sharp-file-buffer', {
defer: true,
fn: function (deferred) {
sharp(fixtures.inputWebp)
sharp(fixtures.inputWebP)
.resize(width, height)
.toBuffer(function (err, buffer) {
if (err) {

View File

@@ -15,7 +15,7 @@ const min = 320;
const max = 960;
const randomDimension = function () {
return Math.ceil(Math.random() * (max - min) + min);
return Math.ceil((Math.random() * (max - min)) + min);
};
new Benchmark.Suite('random').add('imagemagick', {

6
test/coverage/report.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
CPPFLAGS="--coverage" LDFLAGS="--coverage" npm rebuild
npm test
geninfo --no-external --base-directory src --output-file coverage/sharp.info build/Release/obj.target/sharp/src
genhtml --title sharp --demangle-cpp --output-directory coverage/sharp coverage/*.info

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 MiB

BIN
test/fixtures/320x240.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
test/fixtures/8bit_depth.tiff vendored Normal file

Binary file not shown.

BIN
test/fixtures/G31D_MULTI.TIF vendored Normal file

Binary file not shown.

BIN
test/fixtures/Landscape_9.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
test/fixtures/alpha-layer-2-ink.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
test/fixtures/centered_image.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
test/fixtures/embedgravitybird.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
test/fixtures/expected/create-rgb.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

BIN
test/fixtures/expected/create-rgba.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

After

Width:  |  Height:  |  Size: 392 B

Some files were not shown because too many files have changed in this diff Show More