使用Java创建多页Tiff

4
我对使用Java添加带有文本的图层到TIF图像很感兴趣,最好使用Twelve Monkeys图像库。我可以从这里的代码进行调整,将文本添加到TIF中或创建一个大小相同但只包含文本的新TIF,但无法将它们保存为多页TIF。例如:
import javax.imageio.*;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.*;
import java.io.*;

public class ImageUtil {

public static void main(String[] args) throws Exception {

    BufferedImage src = ImageIO.read(new File("/path/to/main.tif"));
    BufferedImage text = createTextLayer(src);
    BufferedImage[] images = new BufferedImage[]{src, text};
    createMultiPage(images);

}

private static BufferedImage createTextLayer(BufferedImage src) {
    int w = src.getWidth();
    int h = src.getHeight();
    BufferedImage img = new BufferedImage(
            w, h, BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2d = img.createGraphics();
    g2d.drawImage(img, 0, 0, null);

    g2d.setPaint(Color.red);
    g2d.setFont(new Font("Serif", Font.BOLD, 200));
    String s = "Hello, world!";
    FontMetrics fm = g2d.getFontMetrics();
    int x = img.getWidth() - fm.stringWidth(s) - 5;
    int y = fm.getHeight() * 5;
    g2d.drawString(s, x, y);
    g2d.dispose();
    return img;
}

private static void createMultiPage(BufferedImage[] images) throws IOException {

    File tempFile = new File("/new/file/path.tif");
    //I also tried passing in stream var below to the try, but also receive java.lang.UnsupportedOperationException: Unsupported write variant!
    //OutputStream stream = new FileOutputStream(tempFile);

    // Obtain a TIFF writer
    ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();

    try (ImageOutputStream output = ImageIO.createImageOutputStream(tempFile)) {
        writer.setOutput(output);

        ImageWriteParam params = writer.getDefaultWriteParam();
        params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        params.setCompressionType("None");

        //error here: java.lang.UnsupportedOperationException: Unsupported write variant!
        writer.prepareWriteSequence(null);

        for (int i = 0; i < images.length; i++){
            writer.writeToSequence(new IIOImage(images[i], null, null), params);
        }

        // We're done
        writer.endWriteSequence();
    }

}
}

Maven:

<dependency>
    <groupId>com.twelvemonkeys.imageio</groupId>
    <artifactId>imageio-tiff</artifactId>
    <version>3.2.1</version>
</dependency>

如何从图像和生成的文本图像创建多页tif?
我已经成功运行了以下jpg代码,但是jpg没有层。
public static void testWriteSequence() throws IOException {
    BufferedImage[] images = new BufferedImage[] {
            new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB),
            new BufferedImage(110, 100, BufferedImage.TYPE_INT_RGB),
            new BufferedImage(120, 100, BufferedImage.TYPE_INT_RGB),
            new BufferedImage(130, 100, BufferedImage.TYPE_INT_RGB)
    };

    Color[] colors = {Color.BLUE, Color.GREEN, Color.RED, Color.ORANGE};

    for (int i = 0; i < images.length; i++) {
        BufferedImage image = images[i];
        Graphics2D g2d = image.createGraphics();
        try {
            g2d.setColor(colors[i]);
            g2d.fillRect(0, 0, 100, 100);
        }
        finally {
            g2d.dispose();
        }
    }

    //ImageWriter writer = createImageWriter();
    ImageWriter writer = ImageIO.getImageWritersByFormatName("JPEG").next();

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    try (ImageOutputStream output = ImageIO.createImageOutputStream(buffer)) {
        writer.setOutput(output);

        ImageWriteParam params = writer.getDefaultWriteParam();
        params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

        writer.prepareWriteSequence(null);

        params.setCompressionType("JPEG");
        writer.writeToSequence(new IIOImage(images[0], null, null), params);

        params.setCompressionType("JPEG");
        writer.writeToSequence(new IIOImage(images[1], null, null), params);

        params.setCompressionType("JPEG");
        writer.writeToSequence(new IIOImage(images[2], null, null), params);

        params.setCompressionType("JPEG");
        writer.writeToSequence(new IIOImage(images[3], null, null), params);

        writer.endWriteSequence();

        File tempFile = new File("/path/to/new/file.jpg");
        OutputStream out = new FileOutputStream(tempFile);

        buffer.writeTo(out);
    }
}

谢谢。

如果我在这里搜索“使用Java创建多页Tiff”,那么会给我答案;这难道是艰苦的劳动吗? - gpasch
@haraldK 感谢您的更新。我尝试使用OutputStream并将tempFile传递到try中,但仍然没有成功,收到UnsupportedOperationException:Unsupported write variant!我已经更新我的帖子,添加了当前代码。我还在帖子末尾添加了一个jpg示例,该示例是我从TwelveMonkeys testWriteSequence方法修改而来的,并且我可以成功运行,但我无法使其适用于tifs。 - jonD02
1
@haraldK 更新到3.3.1解决了问题,谢谢! - jonD02
@haraldK 相关问题,有没有一种方法可以生成 TIF 页面,使得 Photoshop 可以将它们视为图层? - jonD02
@haraldK 在文本编辑器中查看分层TIF文件,我没有看到标签,所以标签可能在加密数据中。我发布了一个新的帖子,谢谢。 - jonD02
显示剩余3条评论
1个回答

11

您可以使用标准ImageIO API编写多页图像(在支持此功能的格式中,如TIFF)。自Java 9开始,由于Java ImageIO自带了一个TIFF插件,因此以下内容应该可以正常使用,无需任何额外的依赖项。对于Java 8及更早版本,仍需要像JAI或TwelveMonkeys这样的TIFF插件。

例如,请参见TwelveMonkeys ImageIO项目测试用例中的TIFFImageWriterTest.testWriteSequence方法,了解如何执行此操作的示例。

重要部分:

BufferedImage[] images = ...
OutputStream stream = ... // May also use File here, as output

// Obtain a TIFF writer
ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();

try (ImageOutputStream output = ImageIO.createImageOutputStream(stream)) {
    writer.setOutput(output);

    ImageWriteParam params = writer.getDefaultWriteParam();
    params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

    // Compression: None, PackBits, ZLib, Deflate, LZW, JPEG and CCITT variants allowed
    // (different plugins may use a different set of compression type names)
    params.setCompressionType("Deflate");

    writer.prepareWriteSequence(null);

    for (BufferedImage image : images) {
        writer.writeToSequence(new IIOImage(image, null, null), params);
    }

    // We're done
    writer.endWriteSequence();
}

writer.dispose();

感谢您的回复,非常感激!我已经尝试使用不同的方式编写代码,但是在writer.prepareWriteSequence处,我仍然收到了一个IllegalStateException:getOutput()== null异常。在查看您提供的链接并寻找解决方案后,我已经更新了我的代码。您知道我上面的例子还缺少什么吗?谢谢。 - jonD02
3
@jonD02,你犯了一个小错误,我在评论中解释了。请注意,我代码中的“stream”是一个“java.io.OutputStream”,而在你的代码中它是一个“javax.imageio.stream.ImageOutputStream”,这是不同的东西,也是你得到异常的原因。 - Harald K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接