【開源庫 | libpng】使用 libpng 讀寫 png 文件詳細教程(附帶源碼)

😁博客主頁😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客內容🤑:🍭嵌入式開發、Linux、C語言、C++、數據結構、音視頻🍭
🤣本文內容🤣:🍭介紹 🍭
😎金句分享😎:🍭你不能選擇最好的,但最好的會來選擇你——泰戈爾🍭
?發布時間?:

本文未經允許,不得轉發!!!

目錄

  • 🎄一、概述
  • 🎄二、libpng 讀取 png 圖片文件步驟
    • ?2.1、打開文件并檢查是否png文件
    • ?2.2、初始化libpng的數據結構 :png_ptr, info_ptr
    • ?2.3、設置錯誤返回點
    • ?2.4、初始化 io
    • ?2.5、讀取png文件信息
    • ?2.6、讀取實際的rgb數據
    • ?2.7、釋放一些相關的資源和內存
  • 🎄三、libpng 寫入 png 圖片文件步驟
    • ?3.1、1、打開要寫入的png文件
    • ?2.2、初始化libpng的數據結構 :png_ptr, info_ptr
    • ?2.3、設置錯誤返回點
    • ?2.4、初始化 io
    • ?2.5、設置圖片屬性
    • ?2.6、寫文件頭
    • ?2.7、寫入實際的rgb數據
    • ?2.8、寫入文件尾
    • ?2.9、釋放一些相關的資源和內存
  • 🎄四、總結


在這里插入圖片描述

在這里插入圖片描述

🎄一、概述

前面的文章介紹過怎么將 libpng 庫進行編譯、交叉編譯。需要了解的可以參考:zlib-1.2.11庫、libpng-1.6.36庫編譯及交叉編譯。

這篇文章主要介紹怎么使用 libpng 庫讀寫png圖片文件。如果需要了解更多的關于 libpng 庫的操作,可以看看 libpng 庫源碼中的 example.c 文件。


在這里插入圖片描述

🎄二、libpng 讀取 png 圖片文件步驟

?2.1、打開文件并檢查是否png文件

libpng 讀取 png 圖片文件的第一個步驟就是打開 png 圖片,因為png圖片文件最前面有8個字節的png標識,所以先使用png_sig_cmp函數檢測一下當前文件是否是 png 文件。

// 1、打開文件并檢查是否png文件
/* Open the prospective PNG file. */
if ((fp = fopen(file_name, "rb")) == NULL)goto read_end;/* Read in some of the signature bytes. */
if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)goto read_end;/* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.* Return nonzero (true) if they match.*/
if (0 != png_sig_cmp((png_const_bytep)buf, 0, PNG_BYTES_TO_CHECK))goto read_end;

?2.2、初始化libpng的數據結構 :png_ptr, info_ptr

libpng庫讀取文件時需要用到兩個指針png_structp, png_infop,分別標識 內部表述結構體png圖片信息結構體,第二步需要初始化這兩結構體。

// 2、初始化libpng的數據結構 :png_ptr, info_ptr
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{goto read_end;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{goto read_end;
}

?2.3、設置錯誤返回點

// 3、設置錯誤返回點
if (setjmp(png_jmpbuf(png_ptr)))
{/* Free all of the memory associated with the png_ptr and info_ptr. */png_destroy_read_struct(&png_ptr, &info_ptr, NULL);if (NULL != fp){fclose(fp);fp = NULL;}/* If we get here, we had a problem reading the file. */return -1;}

?2.4、初始化 io

初始化 io, 把png結構體和文件流io進行綁定 。

// 4、初始化 io, 把png結構體和文件流io進行綁定
png_init_io(png_ptr, fp);

?2.5、讀取png文件信息

讀取文件信息,包括顏色類型、位深度、寬、高、通道數量等。

位深度,指 ARGB 單個通道的顏色占用了多少個bit,如 RGB888 的位深度是8,RGB555的位深度是5。

通道數量,指多少個顏色通道,ARGB是4,RGB是3。

// 5.讀取文件信息
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);
int color_type = png_get_color_type(png_ptr, info_ptr);       // 顏色類型
p_pic_data->bit_depth = png_get_bit_depth(png_ptr, info_ptr); // 位深度
p_pic_data->width = png_get_image_width(png_ptr, info_ptr);   // 寬
p_pic_data->height = png_get_image_height(png_ptr, info_ptr); // 高
p_pic_data->channels = png_get_channels(png_ptr, info_ptr);   // 通道數量

?2.6、讀取實際的rgb數據

libpng 庫讀取rgb數據的函數有如下幾個:
png_get_rowbytes:獲取每一行的 rgb 數據;
png_get_rows:獲取整個圖片的 rgb 數據;
png_read_row:讀取一行的 rgb 數據;
png_read_rows:讀取多行的 rgb 數據;
png_read_image:讀取整個圖片的 rgb 數據

// 6.讀取實際的rgb數據
int i, j, k;
int size, pos = 0;
png_bytepp row_pointers;                                                 // 實際存儲rgb數據的buf
row_pointers = png_get_rows(png_ptr, info_ptr);                          // 也可以分別每一行獲取png_get_rowbytes();
size = p_pic_data->width * p_pic_data->height * p_pic_data->channels;    // 申請內存先計算空間
if (p_pic_data->channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) // 顏色深度32位,帶有 Alpha 通道
{const int stride = 4; // 跨度,一個像素表示的字節數p_pic_data->rgba = (png_bytep)malloc(size);if (NULL == p_pic_data->rgba){printf("malloc rgba failed ...\n");goto read_end;}// 從row_pointers里讀出實際的rgba數據出來for (i = 0; i < p_pic_data->height; i++){for (j = 0; j < p_pic_data->width * stride; j += stride){for (k = 0; k < stride; k++){p_pic_data->rgba[pos++] = row_pointers[i][j + k];}}}
}

?2.7、釋放一些相關的資源和內存

讀取完成后,需要釋放相關的內存和資源。

read_end: // 釋放一些相關的資源和內存if (NULL != fp){fclose(fp);fp = NULL;}if (png_ptr != NULL){if (info_ptr == NULL)png_destroy_read_struct(&png_ptr, NULL, NULL);elsepng_destroy_read_struct(&png_ptr, &info_ptr, NULL);}return ret;

在這里插入圖片描述

🎄三、libpng 寫入 png 圖片文件步驟

?3.1、1、打開要寫入的png文件

首先,打開要寫入的 png 文件,后面libpng庫也會用到這個文件指針。

// 1、打開要寫入的png文件
if ((fp = fopen(file_name, "wb+")) == NULL)goto write_end;

?2.2、初始化libpng的數據結構 :png_ptr, info_ptr

libpng庫寫文件時需要用到兩個指針png_structp, png_infop,分別標識 內部表述結構體png圖片信息結構體,第二步需要初始化這兩結構體。

注意,這里使用的是 png_create_write_struct ,與讀取時有區別。

// 2、初始化libpng的數據結構 :png_ptr, info_ptr
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{goto write_end;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{goto write_end;
}

?2.3、設置錯誤返回點

// 3、設置錯誤返回點
if (setjmp(png_jmpbuf(png_ptr)))
{goto write_end;
}

?2.4、初始化 io

初始化 io, 把png結構體和文件流io進行綁定 。

// 4、初始化 io, 把png結構體和文件流io進行綁定
png_init_io(png_ptr, fp);

?2.5、設置圖片屬性

設置圖片屬性:顏色類型、寬、高、位深等。

// 5、設置圖片屬性
int color_type = PNG_COLOR_TYPE_RGB_ALPHA;
int interlace = 0;
png_set_IHDR(png_ptr, info_ptr, p_pic_data->width, p_pic_data->height, p_pic_data->bit_depth, color_type,(!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7,PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

?2.6、寫文件頭

// 6、寫文件頭
png_write_info(png_ptr, info_ptr);

?2.7、寫入實際的rgb數據

libpng 庫寫入rgb數據的函數有如下幾個:
png_write_row:寫入一行的 rgb 數據;
png_write_rows:寫入多行的 rgb 數據;
png_write_image:寫入整個圖片的 rgb 數據;

// 7、寫入圖片信息
png_bytep p_row_pointers;
int i = 0;
for (i = 0; i < p_pic_data->height; i++)
{p_row_pointers = (png_bytep)(p_pic_data->rgba + (i * p_pic_data->width * p_pic_data->channels));png_write_rows(png_ptr, &p_row_pointers, 1);
}

?2.8、寫入文件尾

// 8、寫入文件尾png_write_end(png_ptr, info_ptr);

?2.9、釋放一些相關的資源和內存

寫入完成后,需要釋放相關的內存和資源。

write_end: // 釋放一些相關的資源和內存if (NULL != fp){fclose(fp);fp = NULL;}if (png_ptr != NULL){if (info_ptr == NULL)png_destroy_read_struct(&png_ptr, NULL, NULL);elsepng_destroy_read_struct(&png_ptr, &info_ptr, NULL);}return ret;

在這里插入圖片描述

🎄四、總結

本文先介紹了使用 libpng 庫讀取png文件的步驟,然后又介紹了使用 libpng 庫寫入png文件的步驟,最后給出了源碼地址。

根據上面的步驟,你應該可以自己寫一個讀寫png圖片的 .c 源文件了,如果還有問題可以下載下面源碼,本文源碼地址:https://download.csdn.net/download/wkd_007/91134800。

在這里插入圖片描述
如果文章有幫助的話,點贊👍、收藏?,支持一波,謝謝 😁😁😁

參考:
libpng庫編碼圖片為png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88494.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88494.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88494.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Nuttx之nxsched_add_readytorun(non-SMP)

聲明&#xff1a;此處代碼分析&#xff0c;來源與 nuttx 12.8.0版本。 在分析之前&#xff0c;需要一圖鎮樓。 /***************************************************************************** Name: nxsched_add_readytorun** Description:* This function adds a TCB …

Nuttx之nxsched_add_blocked

聲明&#xff1a;此處代碼分析&#xff0c;來源與 nuttx 12.8.0版本。 在分析之前&#xff0c;需要一圖鎮樓。 /***************************************************************************** Name: nxsched_add_blocked** Description:* This function adds a TCB to o…

python 包含虛擬環境venv項目的移動

python 包含虛擬環境venv項目的移動 在ubuntu環境下&#xff0c;移動一個包含venv虛擬環境的項目后&#xff0c;在執行時會報錯: 錯誤1&#xff1a; Traceback (most recent call last):File "app.py", line 2, in <module>from flask import Flask, request…

WPF中實現TreeView的SelectedItem雙向綁定到ViewModel

WPF中實現TreeView的SelectedItem雙向綁定到ViewModel WPF中實現TreeView的SelectedItem雙向綁定到ViewModel問題背景解決方案一&#xff1a;附加行為&#xff08;推薦&#xff09;實現步驟優點 解決方案二&#xff1a;通過IsSelected屬性綁定實現步驟注意事項 兩種方案對比補充…

類型轉換運算符重載

C 類型轉換函數詳解 類型轉換函數是C中用于實現類類型與其他類型之間相互轉換的特殊成員函數&#xff0c;分為兩種主要形式&#xff1a;轉換構造函數和類型轉換運算符。 1. 轉換構造函數 (Conversion Constructor) 基本概念 轉換構造函數是一種特殊的構造函數&#xff0c;它…

ES10(ES2019)新特性整理

一、Array.prototype.flat() 和 flatMap()&#xff08;數組扁平化&#xff09; &#xff08;1&#xff09;flat(depth) 將嵌套數組“拉平”到指定深度&#xff08;默認 depth1&#xff09;。 const arr [1, [2, [3]]]; arr.flat(); // [1, 2, [3]]&#xff08;默認深度 …

基于 LCD1602 的超聲波測距儀設計與實現:從原理到應用

具體材料可在主頁資源里下載 超聲波測距技術作為非接觸式測量的重要手段&#xff0c;在工業檢測、智能家居、機器人避障等領域有著廣泛應用。本文將詳細介紹一款基于 STC89C51 單片機與 LCD1602 顯示屏的超聲波測距系統&#xff0c;從硬件架構到軟件實現&#xff0c;完整呈現一…

2.5G/5G/10G自協商An

IEEE 802.3 協議中&#xff0c;**2.5GBASE-T、5GBASE-T 和 10GBASE-T** 的鏈路自協商&#xff08;auto-negotiation&#xff0c;簡稱 AN&#xff09;是在物理層&#xff08;PHY&#xff09;完成的。它的作用是&#xff1a; * **讓連接雙方&#xff08;主機和對端&#xff09;自…

閑庭信步使用SV搭建圖像測試平臺:第五課——使用task

&#xff08;本系列只需要modelsim即可完成數字圖像的處理&#xff0c;每個工程都搭建了全自動化的仿真環境&#xff0c;只需要雙擊top_tb.bat文件就可以完成整個的仿真&#xff0c;大大降低了初學者的門檻&#xff01;&#xff01;&#xff01;&#xff01;如需要該系列的工程…

Android數據庫GreenDao的使用

簡介 GreenDao 是一個輕量級的對象關系映射&#xff08;ORM&#xff09;庫&#xff0c;用于簡化 Android 應用中的數據庫操作。它提供了以下主要功能&#xff1a; 簡化數據庫操作&#xff1a;通過注解定義實體類&#xff0c;GreenDao 自動生成 DAO&#xff08;數據訪問對象&a…

24小時留言板

title: 24小時留言板 date: 2025-06-25 23:32:53 tags: 代碼工具 24小時留言板 核心效果如圖所示 代碼解析 # TodoController 代碼解析## 整體架構 這是一個基于Spring WebFlux的響應式控制器&#xff0c;結合Redis發布\訂閱機制實現實時更新的待辦事項系統。關鍵組件包括&a…

深入理解Redis整數集合(intset)的升級策略:內存優化的核心魔法

引言 作為Redis中最節省內存的數據結構之一&#xff0c;整數集合&#xff08;intset&#xff09; 專門用于高效存儲整型數據。但你可能不知道&#xff0c;它背后藏著一個精妙的「動態升級」機制——能在不浪費內存的前提下&#xff0c;靈活適配不同大小的整數。今天我們就來扒…

高性能計算(HPC)集群和工作流:intel-oneapi-hpc-toolkit安裝與使用

成功安裝了 Intel oneAPI HPC Toolkit&#xff01;這個工具包包含了很多強大的工具&#xff0c;可以幫助你優化和加速高性能計算&#xff08;HPC&#xff09;任務&#xff0c;特別是在使用 Intel 的硬件&#xff08;如 Xeon 處理器和 GPU&#xff09;時。 接下來&#xff0c;…

QT vscode cmake 編譯 undefined reference to `vtable for 問題解決

編譯時出現undefined reference to vtable for 問題&#xff0c;是沒有添加頭文件到目標&#xff0c;添加即可&#xff1a; 如果使用的是qt5, 沒有qt_add_executable, 使用qt 5的 自動處理即可&#xff1a; # 啟用 Qt 自動處理功能 set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC …

linux內核奔潰轉儲之kexec、kdump

一、kexec是什么&#xff1f; kexec 是 Linux 內核提供的一種關鍵技術&#xff0c;允許系統?在不經過完整硬件重啟&#xff08;BIOS/UEFI 初始化&#xff09;的情況下&#xff0c;直接從當前正在運行的內核加載并啟動另一個新內核?。以下是其核心要點&#xff1a; ?定義與核…

標題:2025金融護網行動實戰指南:從合規防御到智能免疫的體系化進階

引言 2025年&#xff0c;隨著《中國人民銀行業務領域網絡安全事件報告管理辦法》正式實施&#xff0c;金融護網行動已從“合規檢查”升級為“能力對抗”。面對AI驅動的自適應攻擊、勒索病毒與黑灰產協同威脅&#xff0c;金融機構需構建“技術-管理-人才”三位一體的智能防御體…

NEO4j的安裝部署

windows neo4j新版本安裝需要部署jdk17&#xff0c;下面這個版本是jdk8最新的支持版本 neo4j-community-3.5.9-windows.zipIndex of /doc/neo4j/3.5.9/ 啟動 dos面板中啟動 neo4j.bat console linux neo4j新版本安裝需要部署jdk17&#xff0c;下面這個版本是jdk8最新的支…

八股文——JAVA基礎:說一下C++與java的區別

首先&#xff0c;c與java都是面向對象編程&#xff0c;都包含封裝、繼承、多態的特性。但是c多繼承&#xff0c;而java只能單繼承與多實現。 其次&#xff0c;java無法直接訪問內存&#xff0c;java通過引用對向&#xff0c;比如new一個對象&#xff0c;拿到的對象實例實際上是…

Vue3 Composition API 深度解析:告別Options API的局限性

目錄 一、為什么需要Composition API&#xff1f; 二、核心概念&#xff1a;setup() 函數 三、響應式核心&#xff1a;ref() 和 reactive() 1. ref - 處理基本類型/對象 2. reactive - 處理對象 四、生命周期鉤子新寫法 五、強大的邏輯復用&#xff1a;組合式函數 六、響…

IoT/HCIP實驗-5/基于NB-IoT的智慧農業實驗(平臺側開發+端側編碼+基礎調試分析)

文章目錄 概述擴展板 E53_IA1智慧農業平臺測開發功能定義/模型開發編解碼插件開發-消息編解碼插件開發-關聯編解碼插件開發-部署注冊實際設備 智慧農業端側編碼工程配置數據結構定義數據收集任務數據上報任務設備接入過程正確設置接入參數命令響應任務 程序調試其他 概述 本實…