加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

写ico文件java

发布时间:2020-12-14 05:24:05 所属栏目:Java 来源:网络整理
导读:最近我已经变得有兴趣在 java中创建.ico文件或 Windows图标文件.这是我使用的当前代码.我从这里获得了文件格式规格 http://en.wikipedia.org/wiki/ICO_%28file_format%29 BufferedImage img = new BufferedImage(16,16,BufferedImage.TYPE_INT_RGB); Graphic
最近我已经变得有兴趣在 java中创建.ico文件或 Windows图标文件.这是我使用的当前代码.我从这里获得了文件格式规格 http://en.wikipedia.org/wiki/ICO_%28file_format%29
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打开图像时,图像打开正常.我究竟做错了什么.我觉得我正在搞乱文件头中的东西.编辑:即使陌生人在桌面上的图片看起来正确,只是不是当我尝试打开它.

在我的桌面上,图像看起来像这样

当我尝试在Windows照片库中打开它时会显示此错误

在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);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读