zoukankan      html  css  js  c++  java
  • 修改stb_image.c以让Duilib直接支持Ico格式的图标显示

         duilib不支持ico格式的图标资源, 但是我要想显示ico格式的图标...

         发现网上那些转换ico为bmp或其它格式的都不是一个好办法, 也还是不能让duilib直接显示ico...

         昨晚稍微研究了一下ico文件的格式, 发现其非常简单, 其就是一个容器而已, ico文件是bmp/png文件的组合.

         于是我写了几句代码修改了下duilib的图片解码核心stb_image.c, 让她支持解码ico.

          随笔后面有文件下载, 可跳过接下来的内容, 直接下载stb_image.c并重新编译duilib即可.

      代码有BUG, 请不要再使用这种方法. 可以考虑使用评论中的那种方式.

          下面是对utils/stb_image.c添加的内容:

    //女孩不哭 添加于 2014年4月22日 01:09:35
    // QQ: 191035066
    // 增加ico支持
    // 
    
    // ICO (file format)
    // http://en.wikipedia.org/wiki/ICO_%28file_format%29
    #pragma pack(push,1)
    typedef struct{
        unsigned short reserved;    
        unsigned short type;        
        unsigned short nfiles;        
    }ICONDIR;
    
    typedef struct{
        unsigned char  width;        
        unsigned char  height;        
        unsigned char  ncolors;        
        unsigned char  reserved;    
        unsigned short color_planes;
        unsigned short bpp;
        unsigned long  cb;
        unsigned long  offset;
    }ICONDIRENTRY;
    
    //位图文件头数据
    typedef struct _BITMAP_FILE_HEADER{
        unsigned char signature[2];            //00~01:文件头签名字节,仅检测'BM'序
        unsigned long file_size;            //02~05:整个文件的大小
        unsigned long _reserved1;            //06~09:保留4字节,必须为0
        unsigned long data_offset;            //0A~0D:位图数据距文件开始的偏移
    }BITMAP_FILE_HEADER;
    
    #pragma pack(pop)
    
    static unsigned char png_sig[8] = {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
    
    unsigned char* do_load_ico(unsigned char* buffer,unsigned int size,int* psize)
    {
        //  我实在是讨厌ms不支持完整的C语言
        ICONDIR* pIconDir;
        ICONDIRENTRY* pIconDirEntry;
        int nfiles,themax;
        int width,height;
        int i;
    
        unsigned char* data;
    
        if(size < sizeof(ICONDIR)) return NULL;
        pIconDir = (ICONDIR*)buffer;
    
        if(pIconDir->reserved != 0) return NULL;
        if(pIconDir->type != 1) return NULL;
        if(pIconDir->nfiles == 0) return NULL;
    
        nfiles = pIconDir->nfiles;
    
        if(sizeof(ICONDIR) + nfiles*sizeof(ICONDIRENTRY) > size) return NULL;
    
        //找最大的那张图出来
        width=height = -1;
        themax = -1;
        for(i=0; i<nfiles; i++){
            pIconDirEntry = &((ICONDIRENTRY*)(buffer+sizeof(ICONDIR)))[i];
            if(pIconDirEntry->width==0 && pIconDirEntry->height==0){
                width=256;
                height=256;
                themax = i;
                break;
            }
            if(pIconDirEntry->width > width
                && pIconDirEntry->height > height)
            {
                width = pIconDirEntry->width;
                height = pIconDirEntry->height;
                themax = i;
            }
        }
    
        //定位到最大那张
        pIconDirEntry = (ICONDIRENTRY*)(buffer+sizeof(ICONDIR)) + themax;
    
        if(pIconDirEntry->offset + pIconDirEntry->cb > size) return NULL;
    
        if(memcmp(buffer+pIconDirEntry->offset, png_sig, 8) == 0){ // PNG
            data = (unsigned char*)malloc(pIconDirEntry->cb);
            if(!data) return NULL;
            memcpy(data, buffer+pIconDirEntry->offset,pIconDirEntry->cb);
            *psize = pIconDirEntry->cb;
            return data;
        }else{  //may BMP
            BITMAP_FILE_HEADER* pbfh;
            data = (unsigned char*)malloc(sizeof(BITMAP_FILE_HEADER) + pIconDirEntry->cb);
            if(!data) return NULL;
            pbfh = (BITMAP_FILE_HEADER*)data;
            pbfh->_reserved1 = 0;
            pbfh->signature[0]='B';
            pbfh->signature[1]='M';
            pbfh->file_size = sizeof(BITMAP_FILE_HEADER) + pIconDirEntry->cb;
            pbfh->data_offset = sizeof(BITMAP_FILE_HEADER) + 40; // 40: sizeof(BITMAP_INFO_HEADER), defined by MS.
            memcpy(data+sizeof(BITMAP_FILE_HEADER), buffer+pIconDirEntry->offset, pIconDirEntry->cb);
            *psize = pIconDirEntry->cb + sizeof(BITMAP_FILE_HEADER);
            return data;
        }
    }

    找到 stbi_load_main 函数, 并把上面的函数放到它前面即可.(其实放哪儿无所谓, 只要stbi_load_main能调用即可).

    然后修改 stbi_load_main 为如下:

    static unsigned char *stbi_load_main(stbi *s, int *x, int *y, int *comp, int req_comp)
    {
        unsigned char* p; // 这个是我定义的
        int size;
    
       if (stbi_jpeg_test(s)) return stbi_jpeg_load(s,x,y,comp,req_comp);
       if (stbi_png_test(s))  return stbi_png_load(s,x,y,comp,req_comp);
       if (stbi_bmp_test(s))  return stbi_bmp_load(s,x,y,comp,req_comp);
       if (stbi_gif_test(s))  return stbi_gif_load(s,x,y,comp,req_comp);
       if (stbi_psd_test(s))  return stbi_psd_load(s,x,y,comp,req_comp);
       if (stbi_pic_test(s))  return stbi_pic_load(s,x,y,comp,req_comp);
    
       //////////////////////////////////////////////////////////////////////////
       //因为ico用得少, 所以放到最后
       p = do_load_ico(s->img_buffer,s->img_buffer_end-s->img_buffer_original,&size);
       if(p){
           unsigned char* q;
           stbi s;
           start_mem(&s,p,size);
           if (stbi_png_test(&s))  q = stbi_png_load(&s,x,y,comp,req_comp);
           else if (stbi_bmp_test(&s))  q = stbi_bmp_load(&s,x,y,comp,req_comp);
           else q = NULL;
           free(p);
           if(q) return q;
       }
       //////////////////////////////////////////////////////////////////////////
    
       #ifndef STBI_NO_HDR
       if (stbi_hdr_test(s)) {
          float *hdr = stbi_hdr_load(s, x,y,comp,req_comp);
          return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
       }
       #endif
    
       // test tga last because it's a crappy test!
       if (stbi_tga_test(s))
          return stbi_tga_load(s,x,y,comp,req_comp);
       return epuc("unknown image type", "Image not of any known type, or corrupt");
    }

    作了上面的修改后, duilib应该就能够直接加载ico并显示了.

    另外, ico文件中的图片大小信息无法直接知道, 还有另外一个几行代码拼成的小程序用来显示将要加载的ico的大小信息, 在后面一并提供下载.

    显示效果:

    dui_ico

    stb_image.c和ico大小查看工具下载: http://share.weiyun.com/e4ac833f8c6d9315b7694e4007b8cf28

    另外提供一个ico转换png的工具:  http://www.cnblogs.com/memset/p/ico2png.html

    女孩不哭 @ cnblogs.com/memset @ 2014-04-22

    结束~~~~~~~~~~~~~

  • 相关阅读:
    Java中的匿名对象、内部类、包、代码块
    Java中的final和static关键字
    Java中的this与super关键字
    Java中的构造方法
    Java中的多态
    Vue+Element中Table懒加载,新增、删除操作后手动更新
    JQ取消hover事件
    github.com访问慢解决
    vue cli3 子目录问题
    右键事件 contextmenu
  • 原文地址:https://www.cnblogs.com/memset/p/dui_with_ico.html
Copyright © 2011-2022 走看看