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

feat: strip alpha channel in vips image processor #42

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

knarewski
Copy link
Contributor

Background

GdkPixbuf-based image processing can take over 1GB of memory for processing a single high-resolution photo. We've decided to introduce another processor, hoping that it'll improve Morandi's memory profile and performance.

Problems

By default vips handles transparency differently to pixbuf when saving to jpeg.

  • GdkPixbuf discards alpha channel (ie treats all pixels as opaque)
  • Vips flattens the image with black background (ie composes image with black, adjusting RGB values to account for transparency)

Example:

require 'morandi'
GdkPixbuf::Pixbuf.new(file: 'spec/fixtures/match-with-transparency.png').save('tmp/pixbuf_output.jpg', 'jpeg', quality: '97')
Vips::Image.new_from_file('spec/fixtures/match-with-transparency.png').write_to_file('tmp/vips_output.jpg', Q: 97)
Comparison of transparent images saved using both libraries (left - pixbuf, right - vips)

Both processors have some exceptions, where transparency is handled inconsistently, eg:

  • When cropping outside the images boundaries, both processors flatten the transparent image against a white background
  • When straightening, Pixbuf-based processor flattens the image

Solution

Discard alpha when processing with Vips to increase the consistency when saving to jpeg.

Decision

  • It feels that flattening alpha on white would be the closest to the expected outcome, but I decided to discard it ATM to better match current GdkPixbuf's behaviour when saving to jpeg
  • Saving to PNG via GdkPixbuf retains alpha; since that operation is not part of Morandi.process's public interface and VipsProcessor doesn't expose writing to png at all, I ignored consistency in that area for now
  • Stripping alpha as a last step gives two benefits: 1. the quality of processing should be slightly better (as RGBA holds more information than RGB), 2. the benchmarks are more relevant, as they account for processing all the channels

Pixbuf vs Vips comparison

Processing a transparent image with gamma+sepia+crop (left - pixbuf, right - vips), mean average error: 0.000500558 - that's how transparency is handled by GdkPixbuf-based processor for most operations
Processing a transparent image with gamma+sepia+crop+straighten (left - pixbuf, right - vips), mean average error: 0.0422601
the incosistent pixbuf processor's behaviour; transparency is deliberately stripped in Vips to increase consistency

That's how most operations of the GdkPixbuf-based image processor work when saving to jpeg.

- match-multiple-operations - MAE (Mean Average Error): 0.000500558
- match-multiple-operations-and-straighten - MAE (Mean Average Error): 0.0422601
MAE 0.04 comes from improving consistency in vips implementation. When saving to jpeg, Pixbuf handled transparency
differently depending on whether straighten option was used (flattening alpha) or not (discarding alpha).
Vips is currently always discarding. Long-term it feels that flattening is more desired, but I'm trying to avoid
changing too much at once.
@knarewski knarewski requested a review from a team December 10, 2024 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant