編譯前的工作
在編譯libpng前,需要把zlib編譯好,並加載到編譯環境里。
下載與解壓
libpng的官網是 http://www.libpng.org/pub/png/libpng.html ,但它的源碼是存在 https://sourceforge.net 上的;具體最新的版本可以先進官網看看,再點連接過去下載
我當前的版本是libpng 1.6.36:
把里面的文件解壓出來
CMake創建工程
看了一下,CMakeLists.txt就在這個目錄下,用CMake加載一下;在Cmake-gui里,設置好source code 和build the binaries,就點擊一下【Configure】:
加載后,別急着【Generate】需要設置一下編譯后的lib、dll和頭文件的安裝路徑了,第一次我建議設定源碼目錄下的路徑,方便看一下編譯后生成了哪些文件,不然的話可以直接設置為您本機的VC的路徑【注意:不是VS的路徑,而是VS下VC的路徑,這是個人建議,不喜歡的后面給另外一個方法】:
設置好這再【Generate】,基本不會再出什么問題了,就可以點擊【Open Project】打開工程:
不安裝到VC路徑下
如果不喜歡把libpng安裝到VC路徑下時,還是需要設定安裝的路徑,但在安裝后,需要把您設定的安裝路徑添加到環境變量中的Path里。
如果是用VS創建工程的, 就需要把頭文件、lib和dll這些的路徑添加到工程屬性里。
但用CMake可以去掉手動配置的這一步, 但必須把庫的安裝路徑添加到環境變量里,不然CMake是沒查找到這個庫的。本人做個測試, 如果不對可以評論指正!
編譯與安裝
編譯
使用CMake+VS2015編譯的過程很簡單,經過前面的配置工作后,打開工程后,就直接右鍵解決方案,再點擊【生成解決方案】:
之后就是等待了,還好libpng比較小,編譯很快的:
安裝
在編譯成功后,這時就需要把編譯生成的文件安裝到前面設定好的目錄下;看【解決方案】下方,有一個項目的名字為【INSTALL】,只要右鍵【INSTALL】→
【僅用於項目】→【僅生成INSTALL】
ok, 已經安裝完畢:
小貼示
看到編譯生成的文件名竟然帶有版本號信息,我有點小小強迫症,所以我想去,這就需要修改一下CMake配置文件CMakeLists.txt:
這個時候回去cmake-gui需要刪除之前緩存,再Configure和Generate,並重新編譯就好了。
使用libpng生成圖片
因為用了CMake后,基本很少用VS里的功能來創建工程了:
生成一個png圖片
CMakeLists.txt

1 cmake_minimum_required(VERSION 3.0) 2 3 project(PngDemoEx1) 4 5 aux_source_directory(. SRC) 6 7 link_libraries(debug libpngd) #設置Debug時使用libpngd.lib 8 link_libraries(optimized libpng) #設置非Debug時使用libpng.lib 9 10 add_executable(${PROJECT_NAME} ${SRC})
main.cpp

1 #include <png.h> 2 #include <stdio.h> 3 #include <iostream> 4 using namespace std; 5 6 7 int main(int argc, char* argv[]) 8 { 9 10 png_structp ppng = NULL;//libpng的結構體 11 png_infop pinfo = NULL;//libpng的信息 12 13 //打開一個保存png的文件流 14 FILE* fpng = fopen("tt.png", "wb"); 15 16 //創建一個png_structp結構體實例ppng 17 ppng = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 18 if (!ppng) { 19 printf("png_create_write_struct failed ...\n"); 20 return -1; 21 } 22 png_init_io(ppng, fpng); //把ppng與文件流綁定起來 23 if (setjmp(png_jmpbuf(ppng))) { 24 printf("error during init_io ...\n"); 25 return -1; 26 } 27 //用png_structp結構體創建一個png_infop結構體實例pinfo,個人理解這是png相關頭信息的結構體 28 pinfo = png_create_info_struct(ppng); 29 if (!pinfo) { 30 printf("png_create_info_struct failed ...\n"); 31 return -1; 32 } 33 png_set_IHDR(ppng, pinfo, 34 10, 10,//尺寸 35 8,//顏色深度,也就是每個顏色成分占用位數(8表示8位紅8位綠8位藍,如果有透明通道則還會有8位不透明度) 36 PNG_COLOR_TYPE_RGB,//顏色類型,PNG_COLOR_TYPE_RGB表示24位真彩深色,PNG_COLOR_TYPE_RGBA表示32位帶透明通道真彩色 37 PNG_INTERLACE_NONE,//不交錯。PNG_INTERLACE_ADAM7表示這個PNG文件是交錯格式。交錯格式的PNG文件在網絡傳輸的時候能以最快速度顯示出圖像的大致樣子。 38 PNG_COMPRESSION_TYPE_BASE,//壓縮方式 39 PNG_FILTER_TYPE_BASE);//這個不知道,總之填寫PNG_FILTER_TYPE_BASE即可。 40 png_write_info(ppng, pinfo); 41 png_set_packing(ppng);//設置打包信息 42 png_write_info(ppng, pinfo);//寫入文件頭 43 44 //定義行數組,是一個指向指針的數組,數組中每一個指向一行的像素數組 45 png_bytepp data = new png_bytep[10]; 46 for (size_t i = 0; i < 10; i++) 47 { 48 data[i] = new png_byte[30]{0x23,0x32, 0x25, 0x21, 0x89};//定義一行像素數組 49 } 50 //把像素數據寫入png_structp結構體實例ppng中 51 png_write_image(ppng, (png_bytepp)data); 52 //寫入png結束信息 53 png_write_end(ppng, pinfo); 54 55 //后面都是清理,回收內存 56 for (size_t i = 0; i < 10; i++) 57 { 58 delete[]data[i]; 59 } 60 delete[]data; 61 png_destroy_write_struct(&ppng, &pinfo); 62 fclose(fpng); 63 return 0; 64 }
總結一下
之前第一次使用時,遇到一個問題,一開始只編譯安裝了libpng的Release版,但在使用的時候工程是Debug版的,編譯過了,但運行時就一直提示一個異常:
其解決方法是編譯版對應的,在開發中Debug就用debug版的libpng,Release就對應Release版的libpng。
讀取png,生成RGB數據文件
- 打開png文件的文件流
- 從文件流中讀四個字節,做PNG簽字驗證
- 重置流的位置
- 定義png_structp指針並創建結構體png_struct實例
- 定義png_infop指針並創建結構體png_info實例
- png_init_io初始化png_struct實例的文件流
- png_read_png讀取png圖片信息與數據
- png_get_color_type
- png_get_image_width 與 png_get_image_height
- png_get_rows
- png_destroy_read_struct 釋放png_struct實例和png_info實例
- 關閉文件流

1 #include <stdio.h> 2 #include <png.h> 3 #include <iostream> 4 #include <sstream> 5 #include <string> 6 using namespace std; 7 #define PNG_SIGN_SIZE 4 8 int main(int argc, char* argv[]) 9 { 10 int ret = 0; 11 FILE* fpng = fopen("tt.png", "rb"); 12 if (fpng == NULL) 13 { 14 cerr << "open png file error" << endl; 15 return __LINE__; 16 } 17 18 char png_sign_buf[PNG_SIGN_SIZE] = {0}; 19 ret = fread(png_sign_buf, sizeof(char), PNG_SIGN_SIZE, fpng); 20 if (ret < PNG_SIGN_SIZE) 21 { 22 cerr << "數據長度不足" << PNG_SIGN_SIZE << "個字節" << endl; 23 fclose(fpng); 24 return __LINE__; 25 } 26 27 ret = png_sig_cmp((png_bytep)png_sign_buf, 0, PNG_SIGN_SIZE); 28 if (ret != 0) 29 { 30 cerr << "lPNG的簽名不正確" << endl; 31 fclose(fpng); 32 return __LINE__; 33 } 34 35 rewind(fpng);/* 復位文件指針 */ 36 37 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); 38 png_infop info_ptr = png_create_info_struct(png_ptr); 39 40 png_init_io(png_ptr, fpng); 41 /* 讀取PNG圖片信息和像素數據 */ 42 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, NULL); 43 /* 獲取圖像的色彩類型 */ 44 int color_type = png_get_color_type(png_ptr, info_ptr); 45 46 int width = png_get_image_width(png_ptr, info_ptr); 47 int height = png_get_image_height(png_ptr, info_ptr); 48 49 png_bytepp rows_ptr; 50 rows_ptr = png_get_rows(png_ptr, info_ptr); 51 52 int channel = color_type == PNG_COLOR_TYPE_RGB ? 3 : 4; 53 54 stringstream ss; 55 ss << "tt_" << width << "x" << height << ".rgb"; 56 57 FILE* frgb = fopen(ss.str().c_str(), "wb"); 58 59 if (frgb != NULL) 60 { 61 for (int h = 0; h < height; h++) 62 { 63 for (int w = 0; w < width; w++) 64 { 65 fwrite((void*)&rows_ptr[h][w*channel], sizeof(char), 3, frgb); 66 } 67 } 68 fclose(frgb); 69 } 70 71 png_destroy_read_struct(&png_ptr, &info_ptr, 0); 72 fclose(fpng); 73 74 return 0; 75 }
這個實例,把png圖片文件中的RGB讀取出來保存了,如果需要查看RGB數據文件,可以用相關工具看的