不用第三方解码库取得图片宽高 附完整C++算法实现代码

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

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

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

在stackoverflow有一篇相关讨论。

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

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

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

实现了 常用图片格式(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);

完整代码:

#include <stdio.h>
#include <sys/stat.h> 

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/
// 博客: http://tntmonks.cnblogs.com/
// 邮箱: [email protected]
bool get_image_size_without_decode_image(const char* file_path, int*width, int*height)
{
    bool has_image_size = false;
    *height = -1;
    *width = -1;
    int 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\r\n\032\n";
    unsigned char ihdr_signature[4] = { ‘I‘, ‘H‘, ‘D‘, ‘R‘ };
    char* gif87_signature = "GIF87a";
    char* gif89_signature = "GIF89a";
    char* jpeg_signature = "\377\330";
    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, sizeof(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("ico 包含多个图片");
            }
            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;
}

调用方法:

const char* file_path = "d:\\test.png";

int h, w;
get_image_size_without_decode_image(file_path , &w, &h);

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

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

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

邮箱地址是: 
[email protected]

原文地址:https://www.cnblogs.com/tntmonks/p/8320748.html

时间: 2024-10-15 21:00:27

不用第三方解码库取得图片宽高 附完整C++算法实现代码的相关文章

JS快速获取图片宽高的方法

快速获取图片的宽高其实是为了预先做好排版样式布局做准备,通过快速获取图片宽高的方法比onload方法要节省很多时间,甚至一分钟以上都有可能,并且这种方法适用主流浏览器包括IE低版本浏览器.一.简陋的获取图片方式 // 图片地址 后面加时间戳是为了避免缓存 var img_url = 'http://www.qttc.net/static/upload/2013/13643608813441.jpg?'+Date.parse(new Date()); // 创建对象 var img = new I

转载:JS快速获取图片宽高的方法

快速获取图片的宽高其实是为了预先做好排版样式布局做准备,通过快速获取图片宽高的方法比onload方法要节省很多时间,甚至一分钟以上都有可能,并且这种方法适用主流浏览器包括IE低版本浏览器. 我们一步一步进入这个过程. 一.简陋的获取图片方式 1 2 3 4 5 6 7 8 9 10 11 // 图片地址 后面加时间戳是为了避免缓存 var img_url = 'http://www.qttc.net/static/upload/2013/13643608813441.jpg?'+Date.par

写个js动态调整图片宽高 (原创)

<body style="TEXT-ALIGN: center;"> <div id="testID" style="background:red;MARGIN-RIGHT: auto; MARGIN-LEFT: auto; width:173;height:184"> <img src="http://e.hiphotos.baidu.com/image/pic/item/024f78f0f736afc3

css未知图片宽高在容器里垂直居中

未知图片宽高在容器里垂直居中 自己总结的一些方法法: 一:比较简单的方法,不存在什么兼容性的问题 1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 5 <title>无标题文档</title> 6 <style> 7 .bo

获取url 里的图片宽高

想获取一个url里的图片的尺寸时: var img_url = "http://www.qttc.net/static/upload/2013/13643608813441.jpg"; // 创建对象 var img = new Image(); // 改变图片的src img.src = img_url; alert(img.width , img.height); 获取url 里的图片宽高

读取部分图片流,获取图片宽高

import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * 图片宽高基本信息类 * @author kira peng * */ public class SimpleImageInfo { private int height; private int

css+background实现 图片宽高自适应,拉伸裁剪不变形

图片宽高不固定 ,一样实现自适应,拉伸裁剪不变形,适应各大兼容性.  下面咱们在网上找两张宽高不一样的照片:     No.1                                              No.2        从上图看一个宽的一个宅的,很难做到自适应,无奈可恶的产品经理,只能自己想办法了  请看下面图片,经在各大浏览器和手机端测试,是好用的                                 咱们先来个对比: 好用                   

js 获取图片宽高 和 图片大小

获取要查看大小的img varimg_url = 'http://img5.imgtn.bdimg.com/it/u=4267222417,1017407570&fm=200&gp=0.jpg'   // 创建img对象 var img = new Image();   // 改变图片的src img.src = img_url;   // 加载完成执行 img.onload = function(){   // 打印   alert('width:'+img.width+',height

JS 图片上传兼容性问题(获取图片宽高兼容)

原代码(360安全浏览器的极速模式不兼容) function ImgAuto(i, MaxW, MaxH) {     var o = new Image();     o.src = i.src;     var w = o.width;//w等于null,别的浏览器未出现该问题 } 图片需要重新再加载一遍 function ImgAuto(i, MaxW, MaxH) {     var o = new Image();     o.onload = function(){