dragon66 / icafe

Java library for reading, writing, converting and manipulating images and metadata
Eclipse Public License 1.0
204 stars 58 forks source link

tiff pages are being written as a blank, white page, or solid black #75

Closed suncds-git closed 6 years ago

suncds-git commented 6 years ago

I have a scenario where I have a 678 page tiff file. Unfortunately, the tiff file contains sensitive information, which prevents me from uploading the file. When the pages are written to a new tif file, the pages are blank. I've played around some with the TiffOptions. Changing the tiff options either produces a white page, or a solid black page. Code snippet follows:

// Adjusting the tiff options:
    private static ImageParam.ImageParamBuilder getTiffOptions()
    {
        ImageParam.ImageParamBuilder builder = ImageParam.getBuilder();

        TIFFOptions tiffOptions = new TIFFOptions();
        tiffOptions.setTiffCompression(Compression.LZW);
        builder.imageOptions(tiffOptions);

        builder.colorType(ImageColorType.BILEVEL).ditherMatrix(DitherMatrix.getBayer8x8Diag()).applyDither(true).ditherMethod(DitherMethod.BAYER);
        return builder;
         }

// read and write the tif file:
    String output = ApplicationProperties.getTempFolder() + File.separator + new File(j_target).getName() + "_" + Calendar.getInstance().getTimeInMillis() + ".tif";                    
    targetFile = new File(j_target);

    File file = new File(output);

    targetFile.renameTo(file);
    FileInputStream in = new FileInputStream(file);

    RandomAccessInputStream source = new FileCacheRandomAccessInputStream(
            in);
    FileOutputStream out = new FileOutputStream(j_target);
    RandomAccessOutputStream target = new FileCacheRandomAccessOutputStream(
            out);
    message = "";
    Integer pages = pageCount(file.toString(),message).intValue();
    TIFFWriter writer = new TIFFWriter();
    target.setWriteStrategy(WriteStrategyII.getInstance());
    List<IFD> ifds = new ArrayList<IFD>(pages);                 
    int offset = TIFFTweaker.prepareForInsert(source, target, ifds);    
    in.close();
    source.close();

// prepareForInsert positions the file at eof.  Open another input stream for the input file
if (!replace) {
    String output = ApplicationProperties.getTempFolder() + File.separator + new File(j_target).getName() + "_" + Calendar.getInstance().getTimeInMillis() + ".tif";                    
    targetFile = new File(j_target);

    File file = new File(output);

    targetFile.renameTo(file);
    FileInputStream in = new FileInputStream(file);

    RandomAccessInputStream source = new FileCacheRandomAccessInputStream(
            in);
    FileOutputStream out = new FileOutputStream(j_target);
    RandomAccessOutputStream target = new FileCacheRandomAccessOutputStream(
            out);
    message = "";
    Integer pages = pageCount(file.toString(),message).intValue();
    TIFFWriter writer = new TIFFWriter();
    target.setWriteStrategy(WriteStrategyII.getInstance());
    List<IFD> ifds = new ArrayList<IFD>(pages);                 
    int offset = TIFFTweaker.prepareForInsert(source, target, ifds);    
    in.close();
    source.close();
    in = new FileInputStream(j_source);
    source = new FileCacheRandomAccessInputStream(
            in);
    PageReader reader = new PageReader();

        BufferedImage image = null;
        while (true) {
            image = reader.getNextPage(source);
            if (image == null)
                break;
        try {
            ImageFrame frame = new ImageFrame(image);
            ImageParam param = builder.build();
            frame.setFrameParam(param);
            offset = TIFFTweaker.insertPage(frame, pages++,
                    target, ifds, offset, writer);
        } catch (NullPointerException npe) {}                       

    }
    TIFFTweaker.finishInsert(target, ifds);
    source.close();
    in.close();
    target.close();
    out.close();
    file.setWritable(true);
    file.delete();

}

``

dragon66 commented 6 years ago

I believe the issue is icafe does not support reading the input image as I mentioned in #73.

Unfortunately I couldn’t find a good time to complete the tiff reader for icafe.

dragon66 commented 6 years ago

By the way, why do you want to read and write to some other tiff? Maybe there is but I don’t know of any other tiff readers which could read pages one at a time.

A workaround could be to first split the multi page tiff to single pages using icafe, then using Java imageio (with the plugin included in lib folder for tiff read support) to read the single page tiffs and do the write with icafe.

suncds-git commented 6 years ago

The PageReader class (com.icafe4j.image.tiff.PageReader) reads one tiff image at a time. I am doing the single read and write to another tiff, because I need to append tiff images to an exiting file. Because of java out of memory issues, I cannot read the entire tiff file into memory. The code I have posted works with other tiff files, just not the one I am trying to write.

dragon66 commented 6 years ago

Do you know what kinds of compression method the other images which work use? I don't think the code you posted will work for CCITT G3 and G4 as I am still working on them. It would work if the input tiff is compressed with methods other than G3, G4 and JPEG.

You can find the compression method from the console output when you read the image.

suncds-git commented 6 years ago

For now I am using JAI to read the tiff images, and using icafe to write the images, which is working, code snippet follows:

                    ImageInputStream is = ImageIO.createImageInputStream(new File(j_source));
                    if (is == null || is.length() == 0){
                      // handle error
                    }
                    Iterator<ImageReader> iterator = ImageIO.getImageReaders(is);
                    if (iterator == null || !iterator.hasNext()) {
                      throw new IOException("Image file format not supported by ImageIO: " + j_source);
                    }
                    // We are just looking for the first reader compatible:
                    ImageReader reader = (ImageReader) iterator.next();
                    iterator = null;
                    reader.setInput(is);
                    Integer numberOfPages = reader.getNumImages(true);                  
                    BufferedImage image = null;
                    for (Integer page = 0; page < numberOfPages; page++) {
                        image = reader.read(page);

                    try {   
                        ImageFrame frame = new ImageFrame(image);
                        ImageParam param = builder.build();
                        frame.setFrameParam(param);
                        writeOffset = TIFFTweaker.writePage(frame, rout,
                                ifds, writeOffset, writer);
                    } catch (NullPointerException npe) {}                       
                    }
dragon66 commented 6 years ago

Good you found a workaround!