T6 压缩 Tiff 图像

T6 Compressed Tiff image

我正在尝试读取 JPG 格式的图像文件,在图像中写入文本, 并将其保存为单条压缩 TIFF 图像格式的文件。 我使用 Apache Commons 库来压缩和编写 输出图像文件。我不知道为什么输出图像被绘制成分成两部分,第二部分先绘制。如果有人可以帮助我解决这个问题或指出我在这里做错了什么。谢谢..

这是来自以下代码的示例输入和输出图像...

sample image

FileOutputStream      fos  = null;
BufferedOutputStream  os   = null;
ByteArrayOutputStream baos = null;

try {

    String          inputPath    = "D:\Test\input.jpg";
    File            inputFile    = new File(inputPath);

    BufferedImage   inputImage   = ImageIO.read(inputFile);

    int             width        = inputImage.getWidth();
    int             height       = inputImage.getHeight();

    BufferedImage   outputImage  = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);

    Font font = new Font("Arial", Font.BOLD, 40 );
    java.awt.Graphics2D g2 = outputImage.createGraphics();
    g2.setFont( font );
    g2.setColor ( Color.BLACK );
    g2.drawImage ( inputImage, 0, 0, width, height, Color.WHITE, null);
    g2.drawString("TEST TEXT", 20, 40);
    g2.dispose();

    PixelDensity        resolution   = PixelDensity.createFromPixelsPerInch ( 200, 200);
    double              resolutionX  = resolution.horizontalDensityInches();
    double              resolutionY  = resolution.verticalDensityInches();
    RationalNumber      rationalNumX = RationalNumber.valueOf ( resolutionX );
    RationalNumber      rationalNumY = RationalNumber.valueOf ( resolutionY );

    TiffOutputSet       outputSet    = new TiffOutputSet(ByteOrder.LITTLE_ENDIAN);
    TiffOutputDirectory directory    = outputSet.addRootDirectory();

    baos = new ByteArrayOutputStream(); 
    ImageIO.write(outputImage, "tif", baos); 
    byte[] bytes = baos.toByteArray();

    byte[] compressedBytes = T4AndT6Compression.compressT6(bytes, width, height);

    TiffImageData.Data data = new TiffImageData.Data(0, compressedBytes.length, compressedBytes);

    TiffElement.DataElement[] dataElements = new TiffElement.DataElement[]{ data };

    TiffImageData tiffImageData = new TiffImageData.Strips(dataElements, height);

    directory.add ( TiffTagConstants.TIFF_TAG_NEW_SUBFILE_TYPE,                   1    );
    directory.add ( TiffTagConstants.TIFF_TAG_PHOTOMETRIC_INTERPRETATION, (short) 1    );
    directory.add ( TiffTagConstants.TIFF_TAG_COMPRESSION,                (short) 4    );
    directory.add ( TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE,            (short) 1    );
    directory.add ( TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT,            (short) 2    );
    directory.add ( TiffTagConstants.TIFF_TAG_ROWS_PER_STRIP,             height       );
    directory.add ( TiffTagConstants.TIFF_TAG_IMAGE_WIDTH,                width        );
    directory.add ( TiffTagConstants.TIFF_TAG_IMAGE_LENGTH,               height       );
    directory.add ( TiffTagConstants.TIFF_TAG_XRESOLUTION,                rationalNumX );
    directory.add ( TiffTagConstants.TIFF_TAG_YRESOLUTION,                rationalNumY );

    directory.setTiffImageData( tiffImageData );

    String outputPath = "D:\Test\output.tif";
    File outputFile = new File(outputPath);

    fos = new FileOutputStream(outputFile);
    os   = new BufferedOutputStream(fos);

    new TiffImageWriterLossy().write( os, outputSet );


} catch (IOException ex) {

    Logger.getLogger(JavaApplication7.class.getName()).log(Level.SEVERE, null, ex);

}   catch (ImageWriteException ex) {

    Logger.getLogger(JavaApplication7.class.getName()).log(Level.SEVERE, null, ex);

} finally {

    if ( baos != null ) {
        try { 
            baos.flush();   
            baos.close();   
        } catch ( IOException ex ) { }
    }
    if ( os != null ) {
        try { 
            os.flush();   
            os.close();   
        } catch ( IOException ex ) { }
    }
    if ( fos != null ) {
        try { 
            fos.flush();   
            fos.close();   
        } catch ( IOException ex ) { }
    }

}

您的代码存在问题,您首先使用 ImageIO 将 BufferedImage 存储为 TIFF 文件,然后压缩 整个文件 以及 header s作为你传递给commons imaging的图像的像素数据:

baos = new ByteArrayOutputStream(); 
ImageIO.write(outputImage, "tif", baos); 
byte[] bytes = baos.toByteArray(); // <-- This is not pixel data, but a complete TIFF file

byte[] compressedBytes = T4AndT6Compression.compressT6(bytes, width, height);

这实际上类似于您期望的图像的原因是 ImageIO 写入未压缩的图像数据。图像之前的垃圾线和偏移量是 TIFF header 和显示为像素的标签...

相反,您可能打算做类似的事情:

// Cast is safe here, as you know outputImage is TYPE_BYTE_BINARY
byte[] bytes = ((DataBufferByte) outputImage.getRaster().getDataBuffer()).getData();
byte[] compressedBytes = T4AndT6Compression.compressT6(bytes, width, height);

这只会压缩像素,您的图像应该没问题。


您也可以仅使用 ImageIO 来完成所有操作,并避免对公共图像的额外依赖,方法如下:

try (ImageOutputStream stream = ImageIO.createImageOutputStream(outputFile)) {
    ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromRenderedImage(outputImage);
    ImageWriter writer = ImageIO.getImageWriters(imageTypeSpecifier, "TIFF").next();
    writer.setOutput(stream);

    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionType("CCITT T.6");

    IIOMetadata metadata = writer.getDefaultImageMetadata(imageTypeSpecifier, param);
    // TODO: Set 200 DPI, default is likely 72, and perhaps subfile type if needed, 
    // other tags will be set correctly for you

    writer.write(null, new IIOImage(outputImage, null, metadata), param);
}