# LodePNG
D1285223 賴嘉安 D1285195 陳均睿
# **用途介紹**
1.用於C語言 PNG 圖像解碼和編碼。
2.完全開源,可以在 GitHub 上找到相關代碼。
# LodePNG是做什麼的?
1.圖片解碼: LODEPNG 可以用於將 PNG 格式的圖片文件解碼為內存中的像素數據。這使得開發者可以在程序中輕鬆地讀取和操作 PNG 圖片。
2.圖片編碼: LODEPNG 允許開發者將內存中的像素數據編碼為 PNG 格式的圖片文件。這使得用戶可以生成 PNG 圖片,例如,用於保存程式生成的圖形或遊戲中的紋理。
3.與其他庫集成:LODEPNG 可以方便地與其他庫和框架集成。例如,可以將其與 OpenGL、SDL 或其他圖形庫一起使用,以實現更複雜的圖形應用。
4.跨平台應用: LODEPNG 的 C 和 C++ 支持使其能夠在各種平台上使用。這使得它成為跨平台應用開發中處理 PNG 圖片的一個選擇。
5.嵌入式系統應用:LODEPNG適用於一些資源有限的嵌入式系統,例如嵌入式設備或 IoT 設備,用於處理 PNG 圖片。
# LodePNG的特色
1.輕量且無依賴性: LodePNG 是一個輕量級的 PNG 圖片編碼和解碼庫,並且不需要依賴其他庫,如 zlib 或 libpng。這使得它使用上變得更加簡單,這也有助於簡化項目的構建和部署。
2.簡單易用: LodePNG 提供了簡單且易於使用的介面,讓開發者可以輕鬆地進行 PNG 圖片的編碼和解碼。
3.支持C 和 C++: LodePNG 支持 C 和 C++,同時提供了 C++ 的方便包裝器。這使得它在各種項目中都能夠方便地使用。
4.開放源碼: LodePNG 是開放源碼項目,允許開發者檢視、修改和自由使用代碼,以滿足其特定需求。
# LodePNG範例程式碼 1
``` c
#include "lodepng.h"
#include <stdio.h>
#include <stdlib.h>
void decodeOneStep(const char* filename) {
unsigned error;
unsigned char* image = 0;
unsigned width, height;
error = lodepng_decode32_file(&image, &width, &height, filename);
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
free(image);
}
void decodeTwoSteps(const char* filename) {
unsigned error;
unsigned char* image = 0;
unsigned width, height;
unsigned char* png = 0;
size_t pngsize;
error = lodepng_load_file(&png, &pngsize, filename);
if(!error) error = lodepng_decode32(&image, &width, &height, png, pngsize);
if(error) printf("error %u: %s\n", error, lodepng_error_text(error));
free(png);
free(image);
}
int main(int argc, char *argv[]) {
const char* filename = argc > 1 ? argv[1] : "test.png";
decodeOneStep(filename);
return 0;
}
```
# 程式碼講解
```c
void decodeOneStep(const char* filename) {
unsigned error;
unsigned char* image = 0; // 儲存解碼後的像素數據
unsigned width, height; // 圖片的寬度和高度
// 使用 LodePNG 解碼指定的 PNG 檔案
error = lodepng_decode32_file(&image, &width, &height, filename);
// 如果有錯誤,顯示錯誤訊息
if(error)
printf("error %u: %s\n", error, lodepng_error_text(error));
// 釋放解碼後的像素數據的內存
free(image);
}
```
使用 lodepng_decode32_file 函數,從文件中解碼PNG圖像,並將結果存儲在 image 中。
```c
void decodeTwoSteps(const char* filename) {
unsigned error;
unsigned char* image = 0; // 儲存解碼後的像素數據
unsigned width, height; // 圖片的寬度和高度
unsigned char* png = 0; // 儲存讀取的 PNG 檔案數據
size_t pngsize; // 儲存 PNG 檔案大小
// 讀取 PNG 檔案到內存
error = lodepng_load_file(&png, &pngsize, filename);
// 如果沒有錯誤,使用 LodePNG 解碼 PNG 檔案
if(!error)
error = lodepng_decode32(&image, &width, &height, png, pngsize);
// 如果有錯誤,顯示錯誤訊息
if(error)
printf("error %u: %s\n", error, lodepng_error_text(error));
// 釋放讀取的 PNG 檔案數據的內存
free(png);
// 釋放解碼後的像素數據的內存
free(image);
}
```
使用 lodepng_load_file 函數將PNG文件從磁盤加載到內存,然後使用 lodepng_decode32 函數在內存中進行解碼。
# LodePNG範例程式碼 2
``` c
#include "lodepng.h"
#include <SDL2/SDL.h>
int show(const char* filename) {
unsigned error;
unsigned char* image;
unsigned w, h, x, y;
int done;
size_t jump = 1;
SDL_Window* sdl_window;
SDL_Renderer* sdl_renderer;
SDL_Texture* sdl_texture;
SDL_Event sdl_event;
size_t screenw, screenh, pitch;
Uint32* sdl_pixels;
printf("showing %s\n", filename);
error = lodepng_decode32_file(&image, &w, &h, filename);
if(error) {
printf("decoder error %u: %s\n", error, lodepng_error_text(error));
return 0;
}
if(w / 1024 >= jump) jump = w / 1024 + 1;
if(h / 1024 >= jump) jump = h / 1024 + 1;
screenw = w / jump;
screenh = h / jump;
pitch = screenw * sizeof(Uint32);
SDL_CreateWindowAndRenderer(screenw, screenh, SDL_WINDOW_OPENGL, &sdl_window, &sdl_renderer);
SDL_SetWindowTitle(sdl_window, filename);
if(!sdl_window) {
printf("Error, no SDL screen\n");
return 0;
}
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, screenw, screenh);
sdl_pixels = (Uint32*)malloc(screenw * screenh * sizeof(Uint32));
if(!sdl_pixels) {
printf("Failed to allocate pixels\n");
return 0;
}
for(y = 0; y + jump - 1 < h; y += jump)
for(x = 0; x + jump - 1 < w; x += jump) {
Uint32 r = image[4 * y * w + 4 * x + 0];
Uint32 g = image[4 * y * w + 4 * x + 1];
Uint32 b = image[4 * y * w + 4 * x + 2];
Uint32 a = image[4 * y * w + 4 * x + 3];
int checkerColor = 191 + 64 * (((x / 16) % 2) == ((y / 16) % 2));
r = (a * r + (255 - a) * checkerColor) / 255;
g = (a * g + (255 - a) * checkerColor) / 255;
b = (a * b + (255 - a) * checkerColor) / 255;
sdl_pixels[(y * screenw + x) / jump] = 65536 * r + 256 * g + b;
}
SDL_UpdateTexture(sdl_texture, NULL, sdl_pixels, pitch);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
SDL_RenderPresent(sdl_renderer);
done = 0;
while(done == 0) {
while(SDL_PollEvent(&sdl_event)) {
if(sdl_event.type == SDL_QUIT) done = 2;
else if(SDL_GetKeyboardState(NULL)[SDLK_ESCAPE]) done = 2;
else if(sdl_event.type == SDL_KEYDOWN) done = 1;
}
SDL_Delay(5);
}
SDL_Quit();
free(sdl_pixels);
return done == 2 ? 1 : 0;
}
int main(int argc, char* argv[]) {
int i;
if(argc <= 1) printf("Please enter PNG file name(s) to display\n");;
for(i = 1; i < argc; i++) {
if(show(argv[i])) return 0;
}
return 0;
}
```
# 解釋
```c
int show(const char* filename) {
unsigned error;
unsigned char* image;
unsigned w, h, x, y;
int done;
size_t jump = 1;
SDL_Window* sdl_window;
SDL_Renderer* sdl_renderer;
SDL_Texture* sdl_texture;
SDL_Event sdl_event;
size_t screenw, screenh, pitch;
Uint32* sdl_pixels;
printf("showing %s\n", filename);
```
這裡開始定義了 show 函數,該函數用於展示PNG圖像。它聲明了一些變量用於處理圖像數據和SDL窗口
```c
error = lodepng_decode32_file(&image, &w, &h, filename);
/*stop if there is an error*/
if(error) {
printf("decoder error %u: %s\n", error, lodepng_error_text(error));
return 0;
}
```
這裡使用 lodepng_decode32_file 函數解碼PNG文件,將其讀入 image 中。如果解碼出現錯誤,會打印相應的錯誤信息並返回0。
```c
if(w / 1024 >= jump) jump = w / 1024 + 1;
if(h / 1024 >= jump) jump = h / 1024 + 1;
screenw = w / jump;
screenh = h / jump;
pitch = screenw * sizeof(Uint32);
/* init SDL */
SDL_CreateWindowAndRenderer(screenw, screenh, SDL_WINDOW_OPENGL, &sdl_window, &sdl_renderer);
SDL_SetWindowTitle(sdl_window, filename);
if(!sdl_window) {
printf("Error, no SDL screen\n");
return 0;
}
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, screenw, screenh);
sdl_pixels = (Uint32*)malloc(screenw * screenh * sizeof(Uint32));
if(!sdl_pixels) {
printf("Failed to allocate pixels\n");
return 0;
}
```
這裡計算圖像的顯示尺寸,初始化SDL窗口和渲染器,並創建用於顯示圖像的紋理(texture)和像素數組。
```c
for(y = 0; y + jump - 1 < h; y += jump)
for(x = 0; x + jump - 1 < w; x += jump) {
/* get RGBA components */
Uint32 r = image[4 * y * w + 4 * x + 0]; /* red */
Uint32 g = image[4 * y * w + 4 * x + 1]; /* green */
Uint32 b = image[4 * y * w + 4 * x + 2]; /* blue */
Uint32 a = image[4 * y * w + 4 * x + 3]; /* alpha */
/* make translucency visible by placing checkerboard pattern behind image */
int checkerColor = 191 + 64 * (((x / 16) % 2) == ((y / 16) % 2));
r = (a * r + (255 - a) * checkerColor) / 255;
g = (a * g + (255 - a) * checkerColor) / 255;
b = (a * b + (255 - a) * checkerColor) / 255;
/* give the color value to the pixel of the screenbuffer */
sdl_pixels[(y * screenw + x) / jump] = 65536 * r + 256 * g + b;
}
```
這裡處理圖像數據,為每個像素計算RGBA(紅綠藍透明度)分量,並根據透明度在圖像後面放置了棋盤格紋理模擬透明效果。
```c
SDL_UpdateTexture(sdl_texture, NULL, sdl_pixels, pitch);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL);
SDL_RenderPresent(sdl_renderer);
```
這一段代碼將處理後的像素數據更新到SDL紋理中,然後將紋理渲染到窗口上,實現圖像的顯示。
```c
while(done == 0) {
while(SDL_PollEvent(&sdl_event)) {
if(sdl_event.type == SDL_QUIT) done = 2;
else if(SDL_GetKeyboardState(NULL)[SDLK_ESCAPE]) done = 2;
else if(sdl_event.type == SDL_KEYDOWN) done = 1;
}
SDL_Delay(5);
}
SDL_Quit();
free(sdl_pixels);
return done == 2 ? 1 : 0;
```
這裡使用SDL等待用戶輸入,如果檢測到退出信號或者按下任意鍵,就會退出或者顯示下一張圖片。
```c
int main(int argc, char* argv[]) {
int i;
if(argc <= 1) printf("Please enter PNG file name(s) to display\n");
for(i = 1; i < argc; i++) {
if(show(argv[i])) return 0;
}
return 0;
}
```
main 函數處理命令行參數,調用 show 函數來顯示每個命令行傳入的PNG文件。