使用C语言实现简单的PNG图像读取

article/2025/11/6 22:25:37

概述

首先,关于png图像的结构:PNG文件的结构、PNG格式的数据结构。这两篇文章说的比较细。我简单地说一下我使用到的地方:

注:①引于PNG格式的数据结构。②引于PNG文件的结构

“png文件的前8个字节为固定的文件头信息,表明为png文件,其后便为IHDR。
IHDR的前1-4字节表示IHDR的长度(00 00 00 0D),可知长度为13。5-8字节(49 48 44 52)为数据块类型码,表明数据块为IHDR。9-16字节存储了图像的宽高信息(00 00 20 00 00 00 20 00),可知图片的宽高为512x512。其后的5个字节分别表示了图像的色深、颜色类型、滤波器方法、隔行扫描方法,最后四个字节为CRC循环冗余检测。” ①

IHDR由13字节组成:

名称字节数说明
Width4字节图像宽度(像素)
Height4字节图像高度(像素)
Bit depth1字节图像深度:表示每个采样点占用的bit数
索引(indexed)彩色图像:1,2,4或8;
灰度图像:1,2,4,8或16;
真彩色图像:8或16
Colour type1字节颜色类型:
0:灰度图像, 深度为1,2,4,8或16 bit;
2:真彩色(truecolor)图像,深度为8或16 bit;
3:索引彩色图像,深度为1,2,4或8 bit;
4:带α通道数据的灰度图像,深度为8或16 bit;
6:带α通道数据的真彩色(truecolor with alpha)图像,深度为8或16 bit
Compression method1字节压缩方法:
0:LZ77派生算法(目前仅定义了0)
其他值:无效;为未来扩展的压缩方法预留
Filter method1字节滤波器方法:
0(目前仅定义了0)
其他值:无效
Interlace method1字节隔行扫描方法:
0:非隔行扫描;
1: Adam7隔行扫描方法

”②

作为初学者,我个人的想法是创建一个图片结构体,将整张图片以byte[]形式存储,然后设置偏移值跳过不需要的信息,然后使用联合将需要转换的信息转换为相应的数据类型并储存即可。

联合部分:使用联合将4个byte与1个int共用一片存储空间,反向读取整个图片的byte[]数组,对于4字节长的width与height信息,正向存储于联合的byte[]数组,达到byte[]转int的效果。

代码


/** 处理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转intbyteToInt 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;
}

实现效果 


http://chatgpt.dhexx.cn/article/NpjE59mk.shtml

相关文章

RK3588平台开发系列讲解(Display篇)开机视频的设置

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、开机视频功能介绍二、使用方法2.1、开启与关闭2.2、视频放置位置2.3、编译结果2.4、视频素材要求2.5、参数控制说明沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍RK3588平台开机视频的使用方法…

NR PUCCH(一) PUCCH format 0/1

欢迎关注同名微信公众号“modem协议笔记”。 NR中PUCCH物理信道用来发送上行控制信息Uplink Control Information(UCI)&#xff0c;当然UCI也可以在PUSCH上发送。UCI 内容包括&#xff1a;CSI,HARQ ACK/NACK ,SR 及上述三者的组合信息。 那先看下PUCCH format &#xff0c;序…

NR PUSCH(三) 频域资源分配方式

微信公众号同步更新欢迎关注同名modem协议笔记 这篇看下频域资源分配&#xff0c;本篇内容主要在38.214 6.1.2.2 resource allocation in frequency domain章节中。 相比于R15&#xff0c;R16 频域资源分配有3种类型 Uplink resource allocation scheme type 0/1/2&#xff08…

NR PUSCH(四) Frequency hopping

微信公众号同步更新&#xff0c;欢迎关注同名modem协议笔记 上篇PUSCH 介绍了频域分配方式resource allocation type0/1/2&#xff0c;其中type 0 RBG位图的分配方式比较灵活&#xff0c;type 2对应的interlaced RB 本身就是一种频域的离散化&#xff0c;都可以实现类似的效果…

halcon中阈值分割算子用法

1.threshold(Image : Region : MinGray, MaxGray : )&#xff1a;通过给定的阈值区间对图像进行分割 效果图&#xff1a; read_image (Audi2, audi2) fill_interlace (Audi2, ImageFilled, odd) threshold (ImageFilled, Region, 0, 90) 2.binary_threshold(Image : Region : …

De-interlace 反交错 简介

<script type"text/javascript"> </script> <script type"text/javascript"> </script> 为了更好的理解新的逐行扫瞄的概念&#xff0c;必须先弄清楚电视传输的一些基本知识&#xff0c;一副图像是如何传输的&#xff0c;它与新的…

pygame加载png出现known incorrect sRGB,Interlace handling should be turned on when using png_read_image问题

使用pygame加载png出现libpng warning: iCCP: known incorrect sRGB profile和Interlace handling should be turned on when using png_read_image警告的问题 一、解决Interlace handling should be turned on when using png_read_image警告 最近使用Python实现强化学习走迷…

计算机视觉之旅(Day3)

对不起大家&#xff0c;opencv的坑我尽量在年底更完&#xff0c;C的坑已经基本更完了&#xff0c;在没有进一步深入学习C之前可能这个系列已经算完了。不多说&#xff0c;我看看机器视觉的基本内容吧。 &#xff08;一&#xff09;基本构成 传统的机器视觉系统是由待测目标、…

交错(拉丝)(Interlace) 与 反胶卷过带

第一部分——交错&#xff08;拉丝&#xff09;&#xff08;Interlace&#xff09;的产生 引用了相当多网友的分析与结论&#xff0c;恕我不能依次注明。分析主要来自“[SilkyBible] 视频知识系列”&#xff0c;就主要概念的主要影响因素进行了一点分析。如果有错误&#xff0c…

二分法之最大子段和

1.问题描述&#xff1a;给定一个数组&#xff0c;找出其中可以构成最大数的子段&#xff0c;子段和是由连续的子段构成的&#xff1b;给定有n个整数(可能为负整数)组成的序列a1,a2,...,an,求该序列连续的子段和的最大值。 2.设计思路&#xff1a;对于一个连续的子段和&#xf…

java动态规划求最大子段和_动态规划-最大子段和

2018-01-14 21:14:58 一、最大子段和问题 问题描述&#xff1a;给定n个整数(可能有负数)组成的序列a1&#xff0c;a2&#xff0c;...&#xff0c;an&#xff0c;求该序列的最大子段和。如果所有整数都是负数&#xff0c;那么定义其最大子段和为0。 方法一、最大子段和的简单算法…

四种方法求解最大子段和问题

题目描述 给定一段长度为n的序列&#xff0c;我们需要找到其中一个连续的子段&#xff0c;使这个子段中各个元素加和最大&#xff0c;如果这个数组中全为负整数&#xff0c;我们就定义这个子段和为0. 题目分析 首先我们的目的是找一个局部的子段但加和是全局最大&#xff0c;…

最大子段和问题(分治法和动态规划)

什么是最大子段和&#xff0c;通俗点讲&#xff1a; 最大子段和就是给了一些数&#xff0c;然后你从中找了几个连续的数&#xff0c;这组连续的数的和比任意一组连续的数的和都大&#xff0c;那么你找的这几个连续的数的和就是这些数的最大子段和。 通俗的听不懂你就看这里&am…

最大子段求和

3种算法&#xff1a;最大子段求和 一、问题分析 问题&#xff1a;给定有n个整数(可能为负整数)组成的序列 a 1 , a 2 , . . . , a n , a_1,a_2,...,a_n, a1​,a2​,...,an​,求该序列连续的子段和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。 简易算法…

最大子段和问题(3种方法)

给定由n个整数(可能为负整数)组成的序列a1&#xff0c;a2&#xff0c; a3… &#xff0c; an&#xff0c; 寻找它的某个连续子段&#xff0c;使得其和最大。例如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20。 1、最大字段和问题的简单算法 (1)枚举法求解&#xff1…

最大子段和(动态规划算法)

最大子段和&#xff08;动态规划算法&#xff09; 文章目录 最大子段和&#xff08;动态规划算法&#xff09;一、思路二、伪代码三、C代码四、输入实例 一、思路 D[i]表示从i开始的最大字段和。&#xff08;但我们不是从前往后找字段结束位置&#xff09; 根据递推公式&#x…

最大子段和——用蛮力算法,分治策略,动态规划算法三种求法(C语言)

目录 一、题目 二、算法求解 1、蛮力算法 伪代码 算法分析 程序 2、分治策略 伪代码 算法分析 程序 3、动态规划算法 伪代码 算法分析 程序 一、题目 设A<a1,a2,...,an>是n个整数的序列&#xff0c;称<ai,....,aj>为该序列的连续子序列&#xff0c;其…

归并排序 java实现_java实现归并排序

归并排序 归并排序&#xff0c;指的是将两个已经排序的序列合并成一个序列的操作。 归并操作的过程如下&#xff1a; 申请空间&#xff0c;使其大小为两个已经排序序列之和&#xff0c;该空间用来存放合并后的序列 设定两个指针&#xff0c;最初位置分别为两个已经排序序列的起…

Java八大算法:归并排序

一、什么是归并排序&#xff1f; 1.概念 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效的排序算法&#xff0c;归并排序对序列的元素进行逐层折半分组&#xff0c;然后从最小分组开始比较排序&#xff0c;合并成一个大的分组&#xff0c;逐层进行…

归并排序(Java代码实现)

基本思想&#xff1a; 将两个或两个以上的有序表合并成一个有序表的过程。常用的归并为2-路归并&#xff0c;就是将两个有序表合为一个有序表。 过程&#xff1a; 先来看一张示意图&#xff1a; 可以看出&#xff0c;归并排序分为分解和合并两个步骤。 分解就是将原数组分解…