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

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

  • 相关阅读:
    part11-1 Python图形界面编程(Python GUI库介绍、Tkinter 组件介绍、布局管理器、事件处理)
    part10-3 Python常见模块(正则表达式)
    Cyclic Nacklace HDU
    模拟题 Right turn SCU
    状态DP Doing Homework HDU
    Dp Milking Time POJ
    区间DP Treats for the Cows POJ
    DP Help Jimmy POJ
    Dales and Hills Gym
    Kids and Prizes Gym
  • 原文地址:https://www.cnblogs.com/memset/p/dui_with_ico.html
Copyright © 2011-2022 走看看