Comments (4)
My best guess would be that this relates to (a lack of) gamut.
Does the following change help? It should ensure the input CMYK profile is respected when present, preventing the narrower, built-in CMYK profile being introduced and therefore allow the removal of pipelineColourspace()
, which is hopefully a bit simpler (and matches your "Attempt 1" example).
--- a/src/pipeline.cc
+++ b/src/pipeline.cc
@@ -348,6 +348,7 @@ class PipelineWorker : public Napi::AsyncWorker {
baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK
) {
image = image.icc_transform(processingProfile, VImage::option()
+ ->set("embedded", TRUE)
->set("input_profile", "cmyk")
->set("intent", VIPS_INTENT_PERCEPTUAL));
}
It's also possible that Photoshop's idea of inverting CMYK values is different to libvips. In addition sharp always tells the underlying lcms to use perceptual rendering intent, which might differ from Photoshop's treatment.
from sharp.
Thanks for the suggestion. I've did some tests without negating to see if the built-in CMYK profile is introduced by comparing with the output from vips
.
Attached a 1000x1000 tiff file with all pixels set to 0 / 100 / 100 / 0
with embedded profile Coated Fogra39
.
# Get source pixel value (output: 0 255 255 0)
vips getpoint fogra.tif 0 0
# Convert to U.S. Web Coated (SWOP) v2
vips icc_transform fogra.tif swop.tif swop.icc
# Get destination pixel valuex (output: 10 255 255 1)
vips getpoint swop.tif 0 0
The destination pixels match exactly those of Photoshop when converting to the SWOP profile using relative colorimetric intent and black point compensation turned off (= the defaults of vips icc_transform
).
I did the same icc transform using sharp with every combination oftoColourspace
and pipelineColourspace
:
await sharp('fogra.tif').toColourspace('cmyk').pipelineColourspace('cmyk').withIccProfile('swop.icc').toFile('swop1.tif');
await sharp('fogra.tif').toColourspace('cmyk').withIccProfile('swop.icc').toFile('swop2.tif');
await sharp('fogra.tif').pipelineColourspace('cmyk').withIccProfile('swop.icc').toFile('swop3.tif');
await sharp('fogra.tif').withIccProfile('swop.icc').toFile('swop4.tif');
Here's the output pixel values:
Test | Output |
---|---|
vips icc_transform fogra.tif swop.tif swop.icc && vips getpoint swop.tif 0 0 |
10 255 255 1 |
vips getpoint swop1.tif 0 0 |
25 255 255 4 |
vips getpoint swop2.tif 0 0 |
23 244 238 3 |
vips getpoint swop3.tif 0 0 |
24 251 247 3 |
vips getpoint swop4.tif 0 0 |
25 255 255 4 |
After applying your code change in pipeline.cc
, I see no change in these output values so I suspect the built-in CMYK profile is still being introduced somehow.
Happy to test any other suggestion.
from sharp.
Thank you, this is useful info, and points to the difference being rendering intent:
$ vips icc_transform fogra.tif swop.tif swop.icc --intent=perceptual
$ vips getpoint swop.tif 0 0
25 255 255 4
sharp uses perceptual intent to try to avoid too much visually-obvious gamut clipping, but this can come at the cost of saturation levels, which from these examples appears to adversely affect CMYK-to-CMYK transformations.
Maybe we should switch to always using relative intent when transforming CMYK images?
from sharp.
Thank you for taking a look at this. I have tested the initial bug and played around in pipeline.cc by moving the image.icc_transform
which is triggered by the withIccProfile
parameter to the beginning of the pipeline.
It seems that when the conversion happens before the negate
that the right result is produced.
So in the case below, when withIccProfile
is set on the sharp instance before the negate. I think the conversion should happen before the negate operation is executed.
await sharp('tiger-cmyk-fogra.tif')
.toColourspace('cmyk')
.pipelineColourspace('cmyk')
.withIccProfile(swopPath)
.negate()
.toFile('tiger-cmyk-swop-inverted-attempt4.tif');
Place in the pipeline where the conversion to ICC happens:
Line 810 in 52b9dc0
Negate works when moved to:
Line 359 in 52b9dc0
I hope this helps! Thanks again for your help.
from sharp.
Related Issues (20)
- Enhancement: provide API overview in docs HOT 4
- `resize()` does not properly handle `orientation` metadata HOT 5
- Image darkening after updating to 0.32.6 HOT 3
- heif: Unsupported feature: Unsupported codec (4.3000) HOT 20
- png resize artefacts related to premultiplication rounding? HOT 8
- Does not produce image with desired font HOT 3
- Installing sharp with yarn causes "Could not load the "sharp" module using the linuxmusl-x64 runtime" HOT 2
- pnpm installation - Cannot find sharp module in Alpine Linux container HOT 2
- [Feature Request] Support for jpegli HOT 1
- Bun 1.1.1 Sharp 0.33.3 -- Error: Could not load the "sharp" module using the darwin-arm64 runtime HOT 4
- jpg convert to webp and toFile, missing all metadata. HOT 2
- Uncaught ReferenceError: require is not defined HOT 1
- JPEG files from Chrome/Safari on iPhone, autoconverted from HEIC has rotation issues HOT 2
- Provide more robust way to enforce custom libvips dependency HOT 6
- Improve resize kernel docs and expose missing (bi)linear kernel HOT 3
- Trying not to loose stream data on "Input buffer contains unsupported image format" HOT 4
- Weird artifacts when encoding PNG HOT 7
- How can one remove the background of an image by changing its alpha channel? HOT 2
- error /home/node/app/node_modules/payload/node_modules/sharp: Command failed HOT 1
- Image is blurry after resizing puppeteer screenshot HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sharp.