coobird / thumbnailator

Thumbnailator - a thumbnail generation library for Java
MIT License
5.16k stars 786 forks source link

Image color loss during conversion #201

Open aleksanderFox opened 1 year ago

aleksanderFox commented 1 year ago

Expected behavior

Please describe what you are expecting the library to perform. The image does not lose color during conversion.

Actual behavior

Hello! I'm using the thumbnailator library to compress and convert customers images to png (to default size 200x200). One user came in with an image that was losing color (black gets lighter). Perhaps the error is due to the fact that the original image was 16 BitsPerPixel - the result is 32 BitsPerPixel. Perhaps I'm not using the library correctly. Help me to understand.

Steps to reproduce the behavior

My code:

    public static final Blob convertResizeImage(BufferedImage image, String formatName/*PNG*/, int targetWidth/*200*/, int targetHeight/*200*/) throws SQLException, IOException, InstantiationException, IllegalAccessException {
        int imgType = image.getType();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        Thumbnails.of(image)
                .size(targetWidth, targetHeight)
                .outputFormat(formatName)
                .imageType(imgType)
                .outputQuality(1)
                .toOutputStream(outputStream);
        byte[] data = outputStream.toByteArray();
        return bytes2Blob(data);
    }

Source image: source

Converted image: destination

Environment

coobird commented 1 year ago

There have been similar issues reported in the past, and usually it can be solved by forcing the image type to be BufferedImage.TYPE_INT_ARGB by .outputFormat(BufferedImage.TYPE_INT_ARGB) -- not setting this will make Thumbnailator perform image processing on the original image type which could introduce these types of issues.

aleksanderFox commented 1 year ago

Perhaps .outputFormat(BufferedImage.TYPE_INT_ARGB) is a typo? It was meant .imageType(BufferedImage.TYPE_INT_ARGB)?

        int imgType = originalImage.getType();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        Thumbnails.of(originalImage)
                .size(targetWidth, targetHeight)
                .outputFormat(formatName)
                //.imageType(imgType)
                .imageType(BufferedImage.TYPE_INT_ARGB)
                .outputQuality(1)
                .toOutputStream(outputStream);

Unfortunately, the above code did not help to fix the error.

LouisWayne commented 1 year ago

I had a similar issue (converting from PNG to JPG) but fixed it by using BufferedImage.TYPE_INT_RGB

BufferedImage thumbnailImg = Thumbnails.of(pngImage)
    .size(width, height)
    .outputFormat("jpg")
    .imageType(BufferedImage.TYPE_INT_RGB) // PNG -> JPG
    .asBufferedImage();

It's a bit cumbersome since we need to set imageType(...) manually