coobird / thumbnailator

Thumbnailator - a thumbnail generation library for Java
MIT License
5.14k stars 784 forks source link

Can I set max-size instead of just size? (Only scale down) #152

Open ILyaCyclone opened 4 years ago

ILyaCyclone commented 4 years ago

First of all, really glad to see new Thumbnailator releases in 2020 after ~6 years of silence. Cheers!

I'd like to know if there is an option to restrict upscaling of images and only resize them down. We plan to use Thumbnailator as dynamic on-fly resizer rather than for making static thumbnails, so in rare circumstances original image may be smaller than requested size. What happens now is that image is scaled UP to requested size and becomes very messy. I haven't found any method to tell Thumbnailator not to make images larger than they already are (even if requested size says so), only make them smaller. Is there such method?

Example: Image original size is 150*150. For some internal reasons we call resize(200, 200). I want result image to stay 150*150.

void resize(InputStream is, OutputStream os, int width, int height) {
    Thumbnails.of(is).size(width, height).toOutputStream(os);
}

Consider this as CSS max-width attribute instead of width.

leoviveiros commented 4 years ago

I've tried a ResizerFactory returning a NullResizer without success, it still upscales the image.

coobird commented 4 years ago

@ILyaCyclone, unfortunately, the quick answer to your question is "no", not yet.

It's been brought up in the past as well, as issue #11.

I'll actually keep this ticket open, and supersede #11 with this ticket.

ILyaCyclone commented 4 years ago

Gotcha, thanks for your attention.

simon1867 commented 1 year ago

This has been open for a while. Any plans to add support for this? Or at least to disable upscaling?

qiezhengyuan commented 1 year ago

One solution:

public class NoScaleUpResizer implements ImageFilter {
    private final int maxWidth;
    private final int maxHeight;

    public NoScaleUpResizer(int maxWidth, int maxHeight) {
        this.maxWidth = maxWidth;
        this.maxHeight = maxHeight;
    }

    @Override
    public BufferedImage apply(BufferedImage img) {
        if (img.getWidth() <= maxWidth && img.getHeight() <= maxHeight) {
            return img;
        }
        try {
            return Thumbnails.of(img).size(maxWidth, maxHeight).asBufferedImage(); 
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

And then:

Thumbnails.of(inputFile)
    .scale(1) // do not resize
    .addFilter(new NoScaleUpResizer(maxWidth, maxHeight)) // then resize only if larger
    .toFile(outputFile);