Imagesharp: Saving Gray8 image as jpeg results in 24 bit image

Created on 12 Jan 2019  路  10Comments  路  Source: SixLabors/ImageSharp

Prerequisites

  • [x] I have written a descriptive issue title
  • [x] I have verified that I am running the latest version of ImageSharp
  • [x] I have verified if the problem exist in both DEBUG and RELEASE mode
  • [x] I have searched open and closed issues to ensure it has not already been reported

I found this:
https://github.com/SixLabors/ImageSharp/issues/672#issuecomment-411172998

@jherby2k in our current design Image does not preserve the bit rate / color model of the original encoded data.

And this:

https://stackoverflow.com/questions/52407878/load-and-save-opaque-8-bit-png-files-using-imagesharp

Note. The png encoder by default will save the image in the input color type and bit depth. If you want to encode the image in a different color type you will need to new up an PngEncoder instance with the ColorType and BitDepth properties set.

Description

I am loading/resize an 8 bit png, however I want to save as .jpg

JpegEncoder does not have ColorType or BitDepth

Steps to Reproduce

Input Image:
201812211019388645_validpos_19 19875_21 285_439_12

private static void resizeUsingImageSharp(byte[] bytes, MemoryStream output)
        {
            var encoder = new JpegEncoder();
            encoder.Quality = 10;

            var decoder = new PngDecoder();
            decoder.IgnoreMetadata = true;

            var image = Image.Load<Gray8>(bytes, decoder);

            image.Mutate(ctx => ctx.Resize(96, 96));
            // Using .Grayscale() makes no difference, still saves 24 bit image

            // encoder.Encode<Gray8>(image, output); also doesn't work

            image.SaveAsJpeg(output, encoder);
        }

Output Image:
imagesharp

System Configuration

  • ImageSharp version:
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-dev002321" />
<PackageReference Include="SkiaSharp" Version="1.68.0" />
  • Environment (Operating system, version and so on):
    Window 10
  • .NET Framework version:
    netcoreapp3.0
  • Additional information:

Most helpful comment

@CoenraadS Jpegs are 24 bit (8 bits per channel). You are never going to be able to save an 8bit jpeg.

The difference in size is probably due to a combination of different output quality, metadata preservation and resampling algorithm.

The performance difference in Resize is dubious, like-for-like benchmarks show that we normally come out on top and also produce higher quality output. This does depend on many factors, CPU etc. If you're saving at 10% quality you should be using Nearest Neighbor for resizing as it's way faster.

SkiaSharp decodes and encode jpegs faster because they use libjpeg-turbo under the hood. We do not have the SIMD tools available yet to allow faster decoding but we can probably speed up encoding a lot by optimizing our color transforms (It's on the TODO list).

Once you align the output quality you'll find the performance much closer.

Anyway it's milliseconds and our API is an order of magnitude nice to use.

All 10 comments

I'm currently evaluating this library against our current solution of SkiaSharp. The current results are:

Note: ImageSharp creates 24 bit images
imageSharp.jpg: Decode: 118 ms
imageSharp.jpg: Resize: 93 ms
imageSharp.jpg: Encode: 135 ms
imageSharp.jpg: Total: 228 ms
imageSharp.jpg: Size: 847 bytes

skiaSharp.jpg: Decode: 36 ms
skiaSharp.jpg: Resize: 1 ms
skiaSharp.jpg: Encode: 38 ms
skiaSharp.jpg: Total: 39 ms
skiaSharp.jpg: Size: 449 bytes

If you are interested I can also post the SkiaSharp code if you would like to benchmark yourself.

@CoenraadS Jpegs are 24 bit (8 bits per channel). You are never going to be able to save an 8bit jpeg.

The difference in size is probably due to a combination of different output quality, metadata preservation and resampling algorithm.

The performance difference in Resize is dubious, like-for-like benchmarks show that we normally come out on top and also produce higher quality output. This does depend on many factors, CPU etc. If you're saving at 10% quality you should be using Nearest Neighbor for resizing as it's way faster.

SkiaSharp decodes and encode jpegs faster because they use libjpeg-turbo under the hood. We do not have the SIMD tools available yet to allow faster decoding but we can probably speed up encoding a lot by optimizing our color transforms (It's on the TODO list).

Once you align the output quality you'll find the performance much closer.

Anyway it's milliseconds and our API is an order of magnitude nice to use.

Aw good to know. I was also comparing with XnConvert which gave me an 8bit jpeg but I assume its a mistake in the metadata then.

Its milliseconds but I am converting millions of images 馃憤

Using nearest neighbor bought the resize time down to 30ms, thank for the tip.

@CoenraadS Actually you are correct! We should support 8 bit encoding!

I'm not sure whether there are more performance-related bits which are not covered by the text in #808, #809 and #642.

If not, we can close this issue in favor of those.

Ok, actually opened #810 for the SIMD bits of #808, however we should address them together. @CoenraadS I'm closing this in favor of the specific issues, but let me know if I'm missing something!

Turns out SkiaSharp doesn't support 8 bit resizing either, it seems not many libraries actually support 8 bit operations other then decoding. My benchmark was actually benching 24 bits for both libraries 馃敘

Well... any progress, guys?
I also have similar task: grayscale image I want to save as JPEG/8-bit depth.
Maybe somebody already implement it? I feel it's not so hard task.

Maybe somebody already implement it? I feel it's not so hard task.

PRs are welcome!

Yeah, core team handles this with priority, but community PR-s are welcome.

The feature request is tracked under #808. All discussions should happen under that issue, please don't reply here.

Was this page helpful?
0 / 5 - 0 ratings