Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with resizing rgb16 png images when embed() function is used #325

Closed
janaz opened this issue Dec 20, 2015 · 7 comments
Closed

Problem with resizing rgb16 png images when embed() function is used #325

janaz opened this issue Dec 20, 2015 · 7 comments
Labels
Milestone

Comments

@janaz
Copy link
Contributor

janaz commented Dec 20, 2015

Sharp 0.12.1 is incorrectly resizing the following PNG image when embed() function is used and the output image has different aspect ratio than the original image.

It seems that only rgb16 png images are affected by this issue.

I'm using vips 8.1.1 with libpng 1.5.13.

the original image

Metadata: format=png, width=600, height=600, space=rgb16, channels=4, hasProfile=false, hasAlpha=true

##### the result of img.embed().resize(200, 201)

##### the result of img.embed().resize(200, 200)

##### the result of img.resize(200, 201)

##### Steps to reproduce: 1. Download the source image
curl -O http://i.imgur.com/9Y6MLBf.png
  1. Execute the following Node.js script

    var sharp = require('sharp');
    
    var img = sharp('9Y6MLBf.png');
    img.embed().resize(200,201).toFile('resized-200x201-embed.png');
    
    img = sharp('9Y6MLBf.png');
    img.resize(200,201).toFile('resized-200x201-noembed.png');
    
    img = sharp('9Y6MLBf.png');
    img.embed().resize(200,200).toFile('resized-200x200-embed.png');
@lovell
Copy link
Owner

lovell commented Dec 20, 2015

Hi Tomasz, thanks for the detailed report.

I think the problem here is that the background "colour" we're attempting to embed a 16-bit image onto is only 8-bit. It looks like libvips (correctly) assumes 8-bit output for this operation, so all 16-bit values >255 are clipped and hence the output is mostly white.

I should be able to fix this fairly easily and you've provided a great test case to use to ensure it doesn't occur again, thank you.

@lovell lovell added the bug label Dec 20, 2015
@lovell
Copy link
Owner

lovell commented Dec 21, 2015

I've been able to reproduce and apply a quick-fix for this problem locally but it'll probably be a couple of days before I have the chance to address it properly.

@janaz
Copy link
Contributor Author

janaz commented Dec 21, 2015

Thanks Lovell for a quick response.

I have a workaround that calls .flatten() when the colorspace is rgb16. The downside of this workaround is that I'm losing the transparency data.

Great to hear that the fix is coming soon!

@lovell
Copy link
Owner

lovell commented Dec 23, 2015

Commit 61b8674 should now allow for the use of the embed option with 16-bit PNGs, plus adds a test case that would previously have failed.

@lovell lovell added this to the v0.12.2 milestone Dec 23, 2015
@lovell
Copy link
Owner

lovell commented Jan 16, 2016

This fix is in v0.12.2 now available via npm - thanks again for reporting this!

@lovell lovell closed this as completed Jan 16, 2016
@janaz
Copy link
Contributor Author

janaz commented Jan 17, 2016

Hi Lovell,

I confirm that the reported issue is fixed. However my workaround (.flatten() call) started producing an unexpected result (completely transparent image) after the upgrade.

The following scenario worked in 0.12.1 and stopped working in 0.12.2 (when the background is set to a transparent color and the aspect ratio is different than the original)
img.flatten().embed().background({r:0, b:0, g:0, a:0}).resize(200,201)

The following script is showing the behaviour for different combinations of the background colors and aspect ratios:

I also noticed that the .normalize() function is broken for the 16-bit png (was broken in 0.12.1 and still is in 0.12.2 - see the last scenario in the script below).

var sharp = require('sharp');

// Note: transparent color
var transparent = {r:0, b:0, g:0, a:0};
var opaque = {r:0, b:0, g:0, a:1};

// Scenario 1
//  - Output Aspect Ratio == Input Aspect Ratio
//  - transparent background
// Result: (sharp 0.12.1) OK
// Result: (sharp 0.12.2) OK
var img = sharp('9Y6MLBf.png');
img.flatten().embed().background(transparent).resize(200,200).toFile('resized-flatten-transparent-200x200-embed.png');

// Scenario 2
//  - Output Aspect Ratio != Input Aspect Ratio
//  - transparent background
// Result: (sharp 0.12.1) OK
// Result: (sharp 0.12.2) transparent image, colors lost
img = sharp('9Y6MLBf.png');
img.flatten().embed().background(transparent).resize(200,201).toFile('resized-flatten-transparent-200x201-embed.png');

// Scenario 3
//  - Output Aspect Ratio != Input Aspect Ratio
//  - opaque background
// Result: (sharp 0.12.1) OK
// Result: (sharp 0.12.2) OK
img = sharp('9Y6MLBf.png');
img.flatten().embed().background(opaque).resize(200,201).toFile('resized-flatten-opaque-200x201-embed.png');

// Scenario 4
//  - .normalize() called
// Result: (sharp 0.12.1) b&w gradient, colors lost
// Result: (sharp 0.12.2) b&w gradient, colors lost
img = sharp('9Y6MLBf.png');
img.normalize().toFile('normalize.png');

@lovell
Copy link
Owner

lovell commented Jan 17, 2016

@janaz Excellent detailed reports there, as always, thank you. I've split these as #339 and #340. I don't think the normalise operation has ever been tested with 16-bit input so thanks for blazing that trail!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants