Как говорит @ fmw42, сделать изображение 1-битным вы должны сами. Плагин TIFFImageWriter
запишет изображение, переданное как есть. К счастью, это не сложно сделать.
Вот простой (но не очень сложный) способ преобразования изображения в двоичный файл:
private static BufferedImage toBinary(BufferedImage original) {
if (original.getType() == BufferedImage.TYPE_BYTE_BINARY) {
return original;
}
// Quick and unsophisticated way to convert to B/W binary, using default dither and threshold (fixed, 50% I think)
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
Graphics2D g = image.createGraphics();
try {
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
}
finally {
g.dispose();
}
return image;
}
Я оставлю это в качестве упражнения для написания более совершенных решений, использующих адаптивный порог, сглаживание диффузии и т.д.
Теперь вы можете использовать следующий код, и вы почти у цели:
public static void main(String[] args) throws IOException {
BufferedImage original = ImageIO.read(new File(args[0]));
ImageIO.write(toBinary(original), "TIFF", new File("out.tif"));
}
К сожалению, это не установит теги X и Y Resolution. Если вам это тоже нужно, вам нужно немного углубиться в API ImageIO и выяснить, как использовать метаданные для управления выводом. Обратите внимание, что таким образом могут быть установлены только некоторые значения в метаданных. Другие значения будут вычислены из переданных данных изображения, а некоторые могут быть заполнены значениями по умолчанию автором.
Вы можете использовать следующий код (метод toBinary
такой же, как и выше):
public static void main(String[] args) throws IOException {
BufferedImage original = ImageIO.read(new File(args[0]));
BufferedImage image = toBinary(original);
ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new File("out.tif"))) {
// You may use the param to control compression
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
Node root = metadata.getAsTree("com_sun_media_imageio_plugins_tiff_image_1.0"); // "javax_imageio_tiff_image_1.0" will work in later versions
Node ifd = root.getFirstChild();
// Add X and Y resolution tags
ifd.appendChild(createResTag("282", "XResolution", "204/1"));
ifd.appendChild(createResTag("283", "YResolution", "196/1"));
// Merge changes back to metadata
metadata.mergeTree("com_sun_media_imageio_plugins_tiff_image_1.0", root);
// Write full image, with metadata
writer.setOutput(stream);
writer.write(null, new IIOImage(image, null, metadata), param);
}
finally {
writer.dispose();
}
}
private static IIOMetadataNode createResTag(String tagNumber, String tagName, String tagValue) {
IIOMetadataNode res = new IIOMetadataNode("TIFFField");
res.setAttribute("number", tagNumber);
res.setAttribute("name", tagName); // Tag name is optional
IIOMetadataNode value = new IIOMetadataNode("TIFFRational");
value.setAttribute("value", tagValue);
IIOMetadataNode rationals = new IIOMetadataNode("TIFFRationals");
rationals.appendChild(value);
res.appendChild(rationals);
return res;
}
PS: плагин TwelveMonkeys TIFF в настоящее время не записывает PlanarConfiguration: 1
, так как это значение по умолчанию, и нет никакого способа его форсировать. Но это не должно иметь значения, так как все совместимые программы TIFF должны использовать значение по умолчанию в этом случае.