JpegSurface.java

package io.brunoborges.jairosvg.surface;

import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.MemoryCacheImageOutputStream;

/**
 * JPEG output surface.
 */
public final class JpegSurface extends Surface {

    private static final ImageWriter JPEG_WRITER;

    static {
        var writers = ImageIO.getImageWritersByFormatName("JPEG");
        if (!writers.hasNext()) {
            throw new ExceptionInInitializerError("No JPEG ImageWriter found");
        }
        JPEG_WRITER = writers.next();
    }

    private float quality = -1f; // -1 = default (~0.75)

    /**
     * Set JPEG quality (0.0-1.0). 0.0 = lowest quality (smallest), 1.0 = highest
     * quality (largest). Default uses the JDK default (~0.75).
     */
    public void setQuality(float quality) {
        if (quality < 0f || quality > 1f) {
            throw new IllegalArgumentException("JPEG quality must be 0.0-1.0, got: " + quality);
        }
        this.quality = quality;
    }

    @Override
    protected void createSurface(double w, double h) {
        int iw = Math.max(1, (int) Math.round(w));
        int ih = Math.max(1, (int) Math.round(h));
        this.image = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
        this.width = iw;
        this.height = ih;
    }

    @Override
    public void finish() throws IOException {
        super.finish();
        if (output != null && image != null) {
            synchronized (JPEG_WRITER) {
                try (var ios = new MemoryCacheImageOutputStream(output)) {
                    JPEG_WRITER.setOutput(ios);
                    ImageWriteParam param = null;
                    if (quality >= 0f) {
                        param = JPEG_WRITER.getDefaultWriteParam();
                        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                        param.setCompressionQuality(quality);
                    }
                    JPEG_WRITER.write(null, new IIOImage(image, null, null), param);
                } finally {
                    JPEG_WRITER.reset();
                }
            }
        }
    }
}