Я пытаюсь записать файл png из java.awt.image.BufferedImage. Все работает нормально, но результирующий png представляет собой 32-битный файл.
Есть ли способ сделать файл png 8-битным? Изображение в оттенках серого, но мне нужна прозрачность, так как это накладываемое изображение. Я использую java 6, и я бы предпочел вернуть OutputStream, чтобы я мог иметь дело с вызывающим классом для записи файла на disk / db.
Вот соответствующая часть кода:
public static ByteArrayOutputStream createImage(InputStream originalStream)
throws IOException {
ByteArrayOutputStream oStream = null;
java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream);
int imgWidth = newImg.getWidth(null);
int imgHeight = newImg.getHeight(null);
java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth,
imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB);
Color bckgrndColor = new Color(0x80, 0x80, 0x80);
Graphics2D gf = (Graphics2D)bim.getGraphics();
// set transparency for fill image
gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
gf.setColor(bckgrndColor);
gf.fillRect(0, 0, imgWidth, imgHeight);
oStream = new ByteArrayOutputStream();
javax.imageio.ImageIO.write(bim, "png", oStream);
oStream.close();
return oStream;
}




Интересный вопрос ... Уже поздно, завтра поэкспериментирую. Сначала я попробую использовать BufferedImage.TYPE_BYTE_INDEXED (возможно, после рисования), чтобы увидеть, достаточно ли умен Java, чтобы сгенерировать 8-битный PNG.
Или, возможно, какая-то библиотека изображений может позволить это.
[РЕДАКТИРОВАТЬ] Несколько лет спустя ... На самом деле, я сделал код в то время, но забыл обновить эту ветку ... Я использовал код, на который указывает Кэт, с небольшими уточнениями в обработке прозрачности и сохранением в формате PNG вместо Gif формат. Он работает при создании 8-битного файла PNG с прозрачностью «все или ничего».
Вы можете найти рабочий тестовый файл на http://bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.java используя мой класс ImageUtil.
Поскольку код не такой уж и большой, для потомков я публикую его здесь без JavaDoc, чтобы сохранить несколько строк.
public class ImageUtil
{
public static int ALPHA_BIT_MASK = 0xFF000000;
public static BufferedImage imageToBufferedImage(Image image, int width, int height)
{
return imageToBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB);
}
public static BufferedImage imageToBufferedImage(Image image, int width, int height, int type)
{
BufferedImage dest = new BufferedImage(width, height, type);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
return dest;
}
public static BufferedImage convertRGBAToIndexed(BufferedImage srcImage)
{
// Create a non-transparent palletized image
Image flattenedImage = transformTransparencyToMagenta(srcImage);
BufferedImage flatImage = imageToBufferedImage(flattenedImage,
srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
BufferedImage destImage = makeColorTransparent(flatImage, 0, 0);
return destImage;
}
private static Image transformTransparencyToMagenta(BufferedImage image)
{
ImageFilter filter = new RGBImageFilter()
{
@Override
public final int filterRGB(int x, int y, int rgb)
{
int pixelValue = 0;
int opacity = (rgb & ALPHA_BIT_MASK) >>> 24;
if (opacity < 128)
{
// Quite transparent: replace color with transparent magenta
// (traditional color for binary transparency)
pixelValue = 0x00FF00FF;
}
else
{
// Quite opaque: get pure color
pixelValue = (rgb & 0xFFFFFF) | ALPHA_BIT_MASK;
}
return pixelValue;
}
};
ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
public static BufferedImage makeColorTransparent(BufferedImage image, int x, int y)
{
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel))
return image; // No transparency added as we don't have an indexed image
IndexColorModel originalICM = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int colorIndex = raster.getSample(x, y, 0); // colorIndex is an offset in the palette of the ICM'
// Number of indexed colors
int size = originalICM.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
originalICM.getReds(reds);
originalICM.getGreens(greens);
originalICM.getBlues(blues);
IndexColorModel newICM = new IndexColorModel(8, size, reds, greens, blues, colorIndex);
return new BufferedImage(newICM, raster, image.isAlphaPremultiplied(), null);
}
}
Спустя 4 года все еще жду ответа, а не другого вопроса.
Я не вижу вопроса в своем ответе, хотя, честно говоря, я тоже не вижу ответа (эй, в то время я был новичком в SO ...). В любом случае, несмотря на тон, спасибо за внимание.
Извините за тон, он не должен был звучать агрессивно. SO просит вас указать, почему вы голосуете против, поэтому я как раз отвечал на этот вопрос.
Сборка в imageio png writer будет записывать 32-битные файлы png на всех платформах, на которых я ее использовал, независимо от исходного изображения. Вы также должны знать, что многие люди жаловались, что результирующее сжатие намного ниже, чем это возможно с форматом png. Доступно несколько независимых библиотеки png, которые позволяют указать точный формат, но на самом деле у меня нет опыта работы ни с одним из них.
Спасибо за ответ, я собирался попробовать TYPE_BYTE_INDEXED с IndexColorModel и все еще могу, но если ImageIO будет записывать 32-битные, несмотря на это, похоже, что я зря трачу там свое время.
Изображение, которое я пытаюсь написать, может быть очень большим (до 8000x4000), но это всего лишь простая маска для изображения внизу, поэтому будет только ~ 30% прозрачного серого и 100% прозрачного вырезанного изображения. Я бы использовал GIF, но IE6, похоже, не умеет отображать такой большой.
Он генерируется только один раз и на внутреннем экране типа настройки, поэтому производительность тоже не является проблемой, но это должно выполняться в коде Java, а не с помощью автономной утилиты.
Библиотеки, которые вы указали, могут быть использованы для его преобразования во время написания ... Я собираюсь проверить это.
Если у кого-то есть способ получше, дайте мне знать!
Спасибо!
Я нашел ответ о том, как преобразовать RGBA в индексированный здесь: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html
Однако полученный 8-битный png-файл имеет прозрачность только 100% или 0%. Вы, вероятно, могли бы настроить массивы IndexColorModel, но мы решили превратить сгенерированный файл (что было маской наложения) в подложку jpg и использовать то, что было статической базой, в качестве прозрачного наложения.
Вместо того, чтобы прикреплять ответы к своему сообщению, вы можете добавить информацию к исходному вопросу, нажав кнопку «Изменить». Пользователи могут видеть, что было изменено, и это не просто добавляется в столбец ответов.
Возможно, больше информации можно найти сейчас на stackoverflow.com/questions/665406/…