T6 сжатое изображение Tiff - PullRequest
       71

T6 сжатое изображение Tiff

0 голосов
/ 05 апреля 2020

Я пытаюсь прочитать файл изображения в формате JPG, записать текст в изображение и сохранить его в файл в виде одной полосы в сжатом формате изображения TIFF. Я использовал библиотеку Apache Commons для сжатия и записи выходного файла изображения. Я понятия не имею, почему изображение выводится так, как будто оно было разделено на две части, а вторая часть нарисована первой. Если кто-то может помочь мне решить эту проблему или указать, что я делаю здесь неправильно. Спасибо ..

Это пример входного и выходного изображения из кода ниже ...

пример изображения

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 Ответ

1 голос
/ 06 апреля 2020

Проблема с вашим кодом заключается в том, что вы сначала сохраняете BufferedImage в виде файла TIFF с помощью ImageIO, а затем сжимаете весь файл вместе с заголовками в качестве данных пикселей изображения, которое вы передаете в систему обработки изображений общего пользования. :

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 и теги, отображаемые в пикселях ...

Вместо этого вы, вероятно, хотели сделать что-то вроде:

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