T6 压缩的 Tiff 图像

huangapple go评论107阅读模式
英文:

T6 Compressed Tiff 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) {
        }
    }
}
英文:

I am trying to read an image file in JPG format, write a text into the image,
and save it into a file in a single strip, compressed TIFF image format.
I used Apache Commons library to do the compression and the writing of the
output image file. I have no idea why the output image is drawn like it was split in two parts and the second part drawn first. If anyone can help me resolve this or point out what am I doing wrong here. Thanks..

This is the sample input and output image from the code below...

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 ) { }
}
}

答案1

得分: 2

你的代码问题在于你首先使用ImageIO将BufferedImage存储为TIFF文件,然后将整个文件连同头部一起作为你传递给Commons Imaging的图像像素数据进行压缩:

baos = new ByteArrayOutputStream(); 
ImageIO.write(outputImage, "tif", baos); 
byte[] bytes = baos.toByteArray(); // <-- 这不是像素数据,而是完整的TIFF文件

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

这实际上与你预期的图像相似,是因为ImageIO以未压缩的方式写入图像数据。垃圾行和图像前面的偏移是TIFF头部和标签,被显示为像素...

相反,你可能想要做类似这样的操作:

// 在这里进行强制转换是安全的,因为你知道outputImage的类型是TYPE_BYTE_BINARY
byte[] bytes = ((DataBufferByte) outputImage.getRaster().getDataBuffer()).getData();
byte[] compressedBytes = T4AndT6Compression.compressT6(bytes, width, height);

这将只压缩像素数据,你的图像应该会正常。


你也可以只使用ImageIO来完成所有操作,避免对Commons Imaging的额外依赖,做类似以下的操作:

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: 设置200 DPI,默认可能是72,如果需要的话还可以设置子文件类型,其他标签将会正确设置

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

The problem with your code is that you first store the BufferedImage as a TIFF file using ImageIO, then compress the entire file along with headers as the pixel data of the image you pass to commons imaging:

baos = new ByteArrayOutputStream(); 
ImageIO.write(outputImage, &quot;tif&quot;, baos); 
byte[] bytes = baos.toByteArray(); // &lt;-- This is not pixel data, but a complete TIFF file
byte[] compressedBytes = T4AndT6Compression.compressT6(bytes, width, height);

The reason this actually resembles the image you expect, is that ImageIO writes the image data uncompressed. The garbage lines and offset before your image, is the TIFF header and tags displayed as pixels...

Instead, you probably meant to do something like:

// 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);

This will compress just the pixels, and your image should be fine.


You could also do everything using just ImageIO, and avoid the extra dependency on commons imaging, by doing something like this:

try (ImageOutputStream stream = ImageIO.createImageOutputStream(outputFile)) {
ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromRenderedImage(outputImage);
ImageWriter writer = ImageIO.getImageWriters(imageTypeSpecifier, &quot;TIFF&quot;).next();
writer.setOutput(stream);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType(&quot;CCITT T.6&quot;);
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);
}

huangapple
  • 本文由 发表于 2020年4月5日 18:30:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/61041199.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定