zoukankan      html  css  js  c++  java
  • 不用第三方解码库取得图片宽高 附完整C++算法实现代码

    在特定的应用场景下,有时候我们只是想获取图片的宽高,

    但不想通过解码图片才取得这个信息。

    预先知道图片的宽高信息,进而提速图片加载,预处理等相关操作以提升体验。

    在stackoverflow有一篇相关讨论。

    Get Image size WITHOUT loading image into memory
    http://stackoverflow.com/questions/15800704/python-get-image-size-without-loading-image-into-memory/

    不加图片到内存,而取得图像的大小。

    这个技巧具有一定的实用价值,博主据此进行了相应的编码。

    项目地址:https://github.com/cpuimage/image_size

    实现了 常用图片格式(png,jpeg,ico,bmp,gif) 不采用第三方解码库,解析得到图像宽高的函数get_image_size_without_decode_image。

    bool get_image_size_without_decode_image(const char* file_path, int*width, int*height,int *filesize);

    完整代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>  
    #include <stdbool.h>
    #include <stdint.h>
    
    #if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/
    #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
    #endif /*_MSC_VER */
    
    unsigned long byteswap_ulong(unsigned long i)
    {
        unsigned int j;
        j = (i << 24);
        j += (i << 8) & 0x00FF0000;
        j += (i >> 8) & 0x0000FF00;
        j += (i >> 24);
        return j;
    }
    
    inline int Abs(int x) {
        return  (x ^ (x >> 31)) - (x >> 31);
    }
    
    unsigned short byteswap_ushort(unsigned short i)
    {
        unsigned short j;
        j = (i << 8);
        j += (i >> 8);
        return j;
    }
    
    //Get Image size WITHOUT loading image into memory
    //ref: http://stackoverflow.com/questions/15800704/python-get-image-size-without-loading-image-into-memory/
    
    bool get_image_size_without_decode_image(const char* file_path, int*width, int*height, int * file_size)
    {
        bool has_image_size = false;
        *height = -1;
        *width = -1;
        *file_size = -1;
        FILE * fp = fopen(file_path, "rb");
        if (fp == NULL)
            return has_image_size;
        struct stat st;
        char sigBuf[26];
        if (fstat(fileno(fp), &st) < 0)
        {
            fclose(fp);
            return has_image_size;
        }
        else
        {
            *file_size = st.st_size;
        }
        if (fread(&sigBuf, 26, 1, fp) < 1)
        {
            fclose(fp);
            return has_image_size;
        }
        char* png_signature = "211PNG
    32
    ";
        char* ihdr_signature = "IHDR";
        char* gif87_signature = "GIF87a";
        char* gif89_signature = "GIF89a";
        char* jpeg_signature = "377330";
        char* bmp_signature = "BM";
        if ((*file_size >= 10) && (memcmp(sigBuf, gif87_signature, strlen(gif87_signature)) == 0 || memcmp(sigBuf, gif89_signature, strlen(gif89_signature)) == 0))
        {
            // image type: gif
            unsigned short* size_info = (unsigned short*)(sigBuf + 6);
            *width = size_info[0];
            *height = size_info[1];
            has_image_size = true;
        }
        else if ((*file_size >= 24) && (memcmp(sigBuf, png_signature, strlen(png_signature)) == 0 && memcmp(sigBuf + 12, ihdr_signature, strlen(ihdr_signature)) == 0))
        {
            // image type:   png
            unsigned long* size_info = (unsigned long*)(sigBuf + 16);
            *width = byteswap_ulong(size_info[0]);
            *height = byteswap_ulong(size_info[1]);
            has_image_size = true;
        }
        else if ((*file_size >= 16) && (memcmp(sigBuf, png_signature, strlen(png_signature)) == 0))
        {
            // image type: old png
            unsigned long* size_info = (unsigned long*)(sigBuf + 8);
            *width = byteswap_ulong(size_info[0]);
            *height = byteswap_ulong(size_info[1]);
            has_image_size = true;
        }
        else if ((*file_size >= 2) && (memcmp(sigBuf, jpeg_signature, strlen(jpeg_signature)) == 0))
        {
            // image type: jpeg
            fseek(fp, 0, SEEK_SET);
            char b = 0;
            fread(&sigBuf, 2, 1, fp);
            fread(&b, 1, 1, fp);
            int w = -1;
            int h = -1;
            while (b && ((unsigned char)b & 0xff) != 0xDA) {
                while (((unsigned char)b & 0xff) != 0xFF)
                {
                    fread(&b, 1, 1, fp);
                }
                while (((unsigned char)b & 0xff) == 0xFF) {
                    fread(&b, 1, 1, fp);
                }
                if (((unsigned char)b & 0xff) >= 0xC0 && ((unsigned char)b & 0xff) <= 0xC3)
                {
                    fread(&sigBuf, 3, 1, fp);
                    fread(&sigBuf, 4, 1, fp);
                    unsigned short* size_info = (unsigned short*)(sigBuf);
                    h = byteswap_ushort(size_info[0]);
                    w = byteswap_ushort(size_info[1]);
                }
                else
                {
                    unsigned short chunk_size = 0;
                    fread(&chunk_size, 2, 1, fp);
                    if (fseek(fp, byteswap_ushort(chunk_size) - 2, SEEK_CUR) != 0)
                        break;
                }
                fread(&b, 1, 1, fp);
            }
            if (w != -1 && h != -1)
            {
                *width = w;
                *height = h;
            }
            has_image_size = true;
        }
        else if ((*file_size >= 26) && (memcmp(sigBuf, bmp_signature, strlen(bmp_signature)) == 0))
        {
            // image type: bmp
            unsigned int header_size = (*(sigBuf + 14));
            if (header_size == 12)
            {
                unsigned short* size_info = (unsigned short*)(sigBuf + 18);
                *width = size_info[0];
                *height = size_info[1];
            }
            else if (header_size >= 40)
            {
                unsigned int* size_info = (unsigned int*)(sigBuf + 18);
                *width = size_info[0];
                *height = Abs((size_info[1]));
            }
            has_image_size = true;
        }
        else if (*file_size >= 2)
        {
            // image type: ico
            fseek(fp, 0, SEEK_SET);
            unsigned short format = -1;
            unsigned short reserved = -1;
            fread(&reserved, 2, 1, fp);
            fread(&format, 2, 1, fp);
            if (reserved == 0 && format == 1)
            {
                unsigned short num = -1;
                fread(&num, 2, 1, fp);
                if (num > 1)
                {
                    printf("this is a muti-ico file.");
                }
                else
                {
                    char w = 0, h = 0;
                    fread(&w, 1, 1, fp);
                    fread(&h, 1, 1, fp);
                    *width = (int)((unsigned char)w & 0xff);
                    *height = (int)((unsigned char)h & 0xff);
                }
            }
            has_image_size = true;
        }
        if (fp != NULL)
            fclose(fp);
        return has_image_size;
    }
    
    int main(int argc, char ** argv) {
    
        const char * pic_file = "lookmanodeps.png";
        int w = 0;
        int h = 0;
        int filesize = 0;
        get_image_size_without_decode_image(pic_file, &w, &h, &filesize);
        printf("file:%s
    filesize:%d
    %d
    height%d
    ", pic_file, filesize, w, h);
        getchar();
    }

    传入图片的位置,输出对应的宽高,高和宽 为-1时,就是解析失败了。

    代码比较简单,不多注释了。

    若有其他相关问题或者需求可以邮件联系俺探讨。

    邮箱地址是: 
    gaozhihan@vip.qq.com

  • 相关阅读:
    Servlet学习笔记(1)--第一个servlet&&三种状态对象(cookie,session,application)&&Servlet的生命周期
    XML学习笔记(2)--dom4j操作XML
    坦克大战(版本2.5-版本2.9)
    坦克大战(版本1.7-版本2.4)
    坦克大战(版本1.0-版本1.6)
    坦克大战(版本0.1-版本0.9)
    JavaSE聊天室
    HTML+CSS+JS学习总结
    JDBC学习笔记(10)——调用函数&存储过程
    VS工程的相对路径写法
  • 原文地址:https://www.cnblogs.com/cpuimage/p/8320748.html
Copyright © 2011-2022 走看看