descripción general
Primero, sobre la estructura de las imágenes png: la estructura de los archivos PNG , la estructura de datos del formato PNG . Estos dos artículos son más detallados. Permítanme describir brevemente dónde lo uso:
Nota: ① Citado de la estructura de datos en formato PNG. ②Citado de la estructura del archivo PNG
"Los primeros 8 bytes del archivo png son información de encabezado de archivo fijo, lo que indica que es un archivo png, y luego es IHDR. Los primeros
1-4 bytes de IHDR indican la longitud de IHDR (00 00 00 0D), y la longitud conocida es 13 .5-8 bytes (49 48 44 52) son códigos de tipo de bloque de datos, lo que indica que el bloque de datos es IHDR. 9-16 bytes almacenan la información de ancho y alto de la imagen (00 00 20 00 00 00 20 00), que muestra la imagen El ancho y la altura son 512 x 512. Los siguientes 5 bytes representan la profundidad de color, el tipo de color, el método de filtro y el método de entrelazado de la imagen, y los últimos cuatro bytes son Detección de redundancia cíclica CRC". ①“
IHDR consta de 13 bytes:
nombre bytes ilustrar Ancho 4 bytes Ancho de la imagen (píxeles) Altura 4 bytes Altura de la imagen (píxeles) Profundidad de bits 1 byte Profundidad de imagen: indica el número de bits ocupados por cada punto de muestreo
Imagen en color indexada (indexada): 1, 2, 4 u 8;
imagen en escala de grises: 1, 2, 4, 8 o 16;
imagen en color verdadero: 8 o 16tipo de color 1 byte Tipo de color:
0: imagen en escala de grises, la profundidad es de 1, 2, 4, 8 o 16 bits;
2: imagen en color verdadero (truecolor), la profundidad es de 8 o 16 bits;
3: imagen en color indexada, la profundidad es de 1, 2, 4 o 8 bits;
4: imagen en escala de grises con datos de canal α, la profundidad es de 8 o 16 bits;
6: imagen en color verdadero (color verdadero con alfa) con datos de canal α, la profundidad es de 8 o 16 bitsMétodo de compresión 1 byte Método de compresión:
0: algoritmo derivado de LZ77 (actualmente solo se define 0)
Otros valores: no válido; reservado para futuros métodos de compresión expandidosmétodo de filtro 1 byte método de filtro:
0 (actualmente solo se define 0)
otros valores: vacíométodo de entrelazado 1 byte Método de entrelazado:
0: no entrelazado;
1: método de entrelazado Adam7”②
Como principiante, mi idea personal es crear una estructura de imagen, almacenar la imagen completa en forma de byte [], luego establecer el valor de compensación para omitir información innecesaria y luego usar la unión para convertir la información que debe convertirse en el tipo de datos correspondiente y guárdelo.
Parte conjunta: use la unión para compartir un espacio de almacenamiento entre 4 bytes y 1 int, lea la matriz de bytes [] de la imagen completa al revés y almacene la información de ancho y alto de 4 bytes en la dirección de avance en el byte conjunto [] Array, para lograr el efecto de convertir byte[] a int.
el código
/* * 处理PNG图片的c文件 * */ #include <stdio.h> #include <windows.h> //定义PNG图片体 typedef struct pictureTypedPNG{ //存储图片路径 char* path; //图像宽度、图像高度 int width, height; //图片大小 long long pictureSize; //图像深度、颜色类型、压缩方法、滤波器方法、隔行扫描方法 byte depth, colorType, compressionMethod, filterMethod, interlaceMethod; //图像本体存储在这里 byte* body; }png; //定义byte转int的联合体 typedef union byteToInt{ __attribute__((unused)) byte b[4];//只做转换用,不直接调用 int i; }byteToInt; //图片读取 png* getPNG(char* path){ png* p = (png*)malloc(sizeof(png)); FILE *fp = fopen(path, "rb");//打开文件。 if (fp == NULL) // 打开文件失败 return p; //存储路径 p->path = (char*) malloc((sizeof(char) * strlen(path))); strcpy(p->path, path); //获取文件大小 fseek(fp, 0, SEEK_END);//定位文件指针到文件尾。 p->pictureSize = ftell(fp);//获取文件指针偏移量,即文件大小。 fseek(fp, 0, SEEK_SET);//定位文件指针到文件头。 //获取图片体 p->body = (byte*) malloc(sizeof(byte) * p->pictureSize);//分配存储图片文件的内存 fread(p->body, 1, p->pictureSize, fp);//读取图片体 //多byte转int byteToInt bti; //获取图片部分信息。设置偏移值滤除文件头、IHDR标识信息 int offset = 8 + 8; //获取图像宽度 for(int i = 3, j = 0; i >= 0; i--, j++){ bti.b[i] = p->body[j + offset]; } p->width = bti.i; //获取图像高度 for(int i = 3, j = 0; i >= 0; i--, j++){ bti.b[i] = p->body[j + offset + 4]; } p->height = bti.i; //获取图像深度 p->depth = p->body[8 + offset]; //获取颜色类型 p->colorType = p->body[9 + offset]; //获取压缩方法 p->compressionMethod = p->body[10 + offset]; //获取滤波器方法 p->filterMethod = p->body[11 + offset]; //获取隔行扫描方法 p->interlaceMethod = p->body[12 + offset]; fclose(fp);//关闭文件。 return p; } void printPNG(const png* p){ const char* colorType = NULL; const char* compressionMethod = NULL; const char* filterMethod = NULL; const char* interlaceMethod = NULL; switch(p->colorType){ case 0: colorType = "灰度图像";break; case 2: colorType = "真彩色图像";break; case 3: colorType = "索引彩色图像";break; case 4: colorType = "带α通道的灰度图像";break; case 6: colorType = "带α通道的真彩色图像";break; } if(!p->compressionMethod){ compressionMethod = "LZ77派生算法"; } if(!p->filterMethod){ filterMethod = "0"; } if(p->interlaceMethod){ interlaceMethod = "Adam7隔行扫描方法"; }else{ interlaceMethod = "非隔行扫描"; } printf("图像路径:%s\n" "图像大小:%lld\n" "图像宽度(像素):%d\n" "图像高度(像素):%d\n" "图像深度:%hhu\n" "颜色类型:%s\n" "压缩方法:%s\n" "滤波器方法:%s\n" "隔行扫描方法:%s\n", p->path, p->pictureSize, p->width, p->height, p->depth, colorType, compressionMethod, filterMethod, interlaceMethod); } int main() { printf("请输入图片路径: \n"); char* path = (char*)malloc(sizeof(char) * 100); fgets(path, 100, stdin); int len = (int)strlen(path); *(path + len - 1) = '\0'; png* picture = getPNG(path); printPNG(picture); return 0; }