Use el lenguaje C para realizar una lectura simple de imágenes PNG

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 16
tipo 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 bits
Mé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 expandidos
método de filtro 1 byte método de filtro:
0 (actualmente solo se define 0)
otros valores: vacío
mé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;
}

lograr efecto 

Supongo que te gusta

Origin blog.csdn.net/bairimeng16/article/details/129312589
Recomendado
Clasificación