BufferedImage img = new BufferedImage(16,16,BufferedImage.TYPE_INT_RGB); Graphics g = img.getGraphics(); g.setColor(Color.GREEN); g.fillRect(0,16); byte[] imgBytes = getImgBytes(img); int fileSize = imgBytes.length + 22; ByteBuffer bytes = ByteBuffer.allocate(fileSize); bytes.order(ByteOrder.LITTLE_ENDIAN); bytes.putShort((short) 0);//Reserved must be 0 bytes.putShort((short) 1);//Image type bytes.putShort((short) 1);//Number of image in file bytes.put((byte) img.getWidth());//image width bytes.put((byte) img.getHeight());//image height bytes.put((byte) 0);//number of colors in color palette bytes.put((byte) 0);//reserved must be 0 bytes.putShort((short) 0);//color planes bytes.putShort((short) 0);//bits per pixel bytes.putInt(imgBytes.length);//image size bytes.putInt(22);//image offset bytes.put(imgBytes); byte[] result = bytes.array(); FileOutputStream fos = new FileOutputStream("C://Users//Owner//Desktop//picture.ico"); fos.write(result); fos.close(); fos.flush(); private static byte[] getImgBytes(BufferedImage img) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(img,"png",bos); return bos.toByteArray(); }
问题是窗口似乎无法打开图像,当我尝试使用Windows照片库打开图像时出现错误.但是,当我尝试使用gimp打开图像时,图像打开正常.我究竟做错了什么.我觉得我正在搞乱文件头中的东西.编辑:即使陌生人在桌面上的图片看起来正确,只是不是当我尝试打开它.
在我的桌面上,图像看起来像这样
在png尝试失败后,我尝试使用位图图像,而这是我的新代码
import java.awt.AWTException; import java.awt.Color; import java.awt.Graphics; import java.awt.HeadlessException; import java.awt.Rectangle; import java.awt.Robot; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import javax.imageio.ImageIO; public class IconWriter { public static void main(String[] args) throws HeadlessException,AWTException,IOException { BufferedImage img = new BufferedImage(16,BufferedImage.TYPE_INT_RGB); Graphics g = img.getGraphics(); g.setColor(Color.GREEN); g.fillRect(0,16); byte[] imgBytes = getImgBytes(img); int fileSize = imgBytes.length + 22; ByteBuffer bytes = ByteBuffer.allocate(fileSize); bytes.order(ByteOrder.LITTLE_ENDIAN); bytes.putShort((short) 0);//Reserved must be 0 bytes.putShort((short) 1);//Image type bytes.putShort((short) 1);//Number of images in file bytes.put((byte) img.getWidth());//image width bytes.put((byte) img.getHeight());//image height bytes.put((byte) 0);//number of colors in color palette bytes.put((byte) 0);//reserved must be 0 bytes.putShort((short) 0);//color planes bytes.putShort((short) 0);//bits per pixel bytes.putInt(imgBytes.length);//image size bytes.putInt(22);//image offset bytes.put(imgBytes); byte[] result = bytes.array(); FileOutputStream fos = new FileOutputStream("C://Users//Owner//Desktop//hi.ico"); fos.write(result); fos.close(); fos.flush(); } private static byte[] getImgBytes(BufferedImage img) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(img,"bmp",bos); byte[] bytes = bos.toByteArray(); return Arrays.copyOfRange(bytes,14,bytes.length); } }
现在,当我尝试在照片库中打开我的图像时,图像看起来像这样我不知道为什么它现在不工作,特别是为什么奇怪的线条出现,虽然我怀疑它必须与彩色飞机属性在ico图像标题.
解决方法
引用:
Images with less than 32 bits of color depth[6] follow a particular
format: the image is encoded as a single image consisting of a color
mask (the “XOR mask”) together with an opacity mask (the “AND mask”).
这很复杂
创建32位图像 – >失败
所以,上面的引用可能会让你想到:“哦,我只需要使32位而不是24位”,作为一种解决方法.不幸的是,这不行.那么实际上存在一个32位的BMP格式.但是最后8位没有真正使用,因为BMP文件并不真正支持透明度.
所以,您可以尝试使用不同的图像类型:INT_ARGB_PRE,它使用32位颜色深度.但是,一旦您尝试使用ImageIO类保存它,您会注意到没有任何反应.流的内容将为空.
BufferedImage img = new BufferedImage(16,BufferedImage.TYPE_INT_ARGB_PRE); ImageIO.write(img,bos);
替代解决方案:image4j
ImageIO无法处理32位图像,但还有其他的图库可以做到这一点. image4J库可以保存32位bmp文件.但是我猜测是因为某些原因你不想使用这个库. (使用image4J会使您的大部分代码无意义,因为image4jhas内置ICO创建支持).
第二个选项:创建一个移动的24位图像 – >作品
所以,让我们再来看一下维基百科说什么,32位BMP数据.
The height for the image in the ICONDIRENTRY structure of the ICO/CUR
file takes on that of the intended image dimensions (after the masks
are composited),whereas the height in the BMP header takes on that
of the two mask images combined (before they are composited).
Therefore,the masks must each be of the same dimensions,
and the height specified in the BMP header must be exactly twice the
height specified in the ICONDIRENTRY structure.
所以,第二个解决方案是创建一个原始大小的两倍的图像.而实际上你只需要替换你的getImageBytes函数,下面的代码就可以了.如上所述,代码的另一部分中指定的ICONDIRENTRY标题保持原始图像高度.
private static byte[] getImgBytes(BufferedImage img) throws IOException { // create a new image,with 2x the original height. BufferedImage img2 = new BufferedImage(img.getWidth(),img.getHeight()*2,BufferedImage.TYPE_INT_RGB); // copy paste the pixels,but move them half the height. Raster sourceRaster = img.getRaster(); WritableRaster destinationRaster = img2.getRaster(); destinationRaster.setRect(0,img.getHeight(),sourceRaster); // save the new image to BMP format. ByteArrayOutputStream bos = new ByteArrayOutputStream(); ImageIO.write(img2,bos); // strip the first 14 bytes (contains the bitmap-file-header) // the next 40 bytes contains the DIB header which we still need. // the pixel data follows until the end of the file. byte[] bytes = bos.toByteArray(); return Arrays.copyOfRange(bytes,bytes.length); }
我建议使用标题如下:
ByteBuffer bytes = ByteBuffer.allocate(fileSize); bytes.order(ByteOrder.LITTLE_ENDIAN); bytes.putShort((short) 0); bytes.putShort((short) 1); bytes.putShort((short) 1); bytes.put((byte) img.getWidth()); bytes.put((byte) img.getHeight()); //no need to multiply bytes.put((byte) img.getColorModel().getNumColorComponents()); //the pallet size bytes.put((byte) 0); bytes.putShort((short) 1); //should be 1 bytes.putShort((short) img.getColorModel().getPixelSize()); //bits per pixel bytes.putInt(imgBytes.length); bytes.putInt(22); bytes.put(imgBytes);