Closed ben-manes closed 1 month ago
Could it be quantization and dithering? My phone couldn't open the attached zip file so haven't been able to see the actual difference but here is a link where I answered a question which may give you some hint: https://stackoverflow.com/questions/31973354/converting-pdf-to-multipage-tiff-group-4/32702373#32702373
Thanks, it may be. I tried dithering earlier today and Bayes was more acceptable, but not as good. I'm going to try see if that can be used as a stop gap. I converted the images back to jpeg so you can see them.
If comes out clear if I use a different ImageColorType
like grayscale, where the compression is RLE instead of Group4. Unfortunately, my experience has been that the systems this industry are based on faxes and have very poor support for non group4 tif images. Perhaps it is something to do with IMGUtils.rgb2bilevel
, but I'm not familiar with graphic algorithms enough to debug.
It turns out that Java 9 added support for multi-page TIFF images. I used 12Monkeys to convert to monochrome and set the dpi, though I'm sure with some digging that could be done without a library. The output metadata matches and the results are pretty good. Here's the test code if helpful and sample image (converted back to jpg for github).
The threshold for the rgb2bilevel method takes the average greyscale. This can be improved by histogram analysis which I am going to try. Hope it can improve the quality.
Thanks @dragon66. I switched off of this library so you are welcome to close as won't do if you prefer. This was a very useful library, so thank you for all your work!
@ben-manes thanks for the feedback and also for bringing this issue up front. Just got some momentum from fixing some other issues and would want to give it a try anyway. Hope it can help other users.
Confirmed! I used a Java library from github to find the median of the original.jpg image to be 148. Plug it into my rgb2bilevel function and converted the image to BW TIFF without dithering. Voila, a crisp and sharp BW image even a bit better than the one created by ImageMagick!
I'm observing lower quality images when converting from jpeg to tif, if compared to Imagemagick. I am using 26c49d5d40 and have also tried the latest (
2c0b9f557d
). Theidentify -verbose
difference between the two files shows that they are very similar in the metadata, so nothing stands out as misconfigured.As github won't attach tif files, this zip file contains the original jpg, imagemagick's, and icafe's. images.zip
A simplified reproducer is below. Do you have any recommendations to improve the quality?
Multi-page TIFF
```java import static com.icafe4j.image.ImageColorType.BILEVEL; import static com.icafe4j.image.tiff.TiffFieldEnum.Compression.CCITTFAX4; import static com.icafe4j.io.ByteOrder.BIG_ENDIAN; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import javax.imageio.ImageIO; import com.icafe4j.image.ImageParam; import com.icafe4j.image.options.TIFFOptions; import com.icafe4j.image.tiff.TIFFTweaker; import com.icafe4j.io.FileCacheRandomAccessOutputStream; import com.icafe4j.io.WriteStrategyMM; public class TiffTest { public static void main(String[] args) { create( Path.of("/Users/ben/Downloads/original.jpg"), Path.of("/Users/ben/Downloads/java.tif")); } public static void create(Path source, Path destination) { BufferedImage[] images = new BufferedImage[1]; try (var fileOutput = Files.newOutputStream(destination); var rout = new FileCacheRandomAccessOutputStream(fileOutput)) { images[0] = ImageIO.read(source.toFile()); TIFFOptions tiffOptions = new TIFFOptions(); tiffOptions.setTiffCompression(CCITTFAX4); tiffOptions.setByteOrder(BIG_ENDIAN); tiffOptions.setXResolution(200); tiffOptions.setYResolution(200); tiffOptions.setJPEGQuality(100); ImageParam imageSetting = ImageParam.getBuilder() .colorType(BILEVEL) .imageOptions(tiffOptions) .build(); rout.setWriteStrategy(WriteStrategyMM.getInstance()); TIFFTweaker.writeMultipageTIFF(rout, images, new ImageParam[] { imageSetting }); } catch (IOException e) { throw new UncheckedIOException(e); } finally { for (var image : images) { if (image != null) { image.getGraphics().dispose(); } } } } } ```