1. 程式人生 > >不用第三方解碼庫取得圖片寬高 附完整C++算法實現代碼

不用第三方解碼庫取得圖片寬高 附完整C++算法實現代碼

== 實現 for break 特定 out printf chunk char*

在特定的應用場景下,有時候我們只是想獲取圖片的寬高,

但不想通過解碼圖片才取得這個信息。

預先知道圖片的寬高信息,進而提速圖片加載,預處理等相關操作以提升體驗。

在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]

不用第三方解碼庫取得圖片寬高 附完整C++算法實現代碼