- 概述
- 辅助函数
- 说明
- 代码
- P2格式创建和读取
- 创建
- 读取
- P5格式
- 创建
- 读取
- P2格式和P5格式文件的比较
- 遇到的问题
- 总结
PGM是存储和交换图像数据的简单文件格式之一。
网上有许多博客都有介绍,不多做介绍;只做记录自己学习的过程;
链接信息
如果下面代码有什么问题请指出来;下面采用的是C语言
代码peek函数(C语言是没有这个函数,自己写的,类似于C++里面的peek函数)
int peek(FILE *fp) {
// todo 判空未做
// 保存当前文件指针的位置
fpos_t pos;
fgetpos(fp, &pos);
int ch;
// 读取文件指针当前指向的字符,文件指针的位置自动指向下一个位置
// 类似于其它高级语言里面的迭代器
ch = fgetc(fp);
fsetpos(fp, &pos);
return ch;
}
skip_comment函数(用来跳过换行和注释信息)
void skip_comment(FILE *fp) {
// 检测当前字符是注释开或者是换行,后面的判断是过滤多个空行
while (peek(fp) == '#'||peek(fp) == '\n') {
// 过滤注释信息,直到换行
while (fgetc(fp) != '\n');
}
}
swap_two_byte函数(用来交换双字节存放的值)
// 移位版
unsigned short swap_two_byte(unsigned short data) {
return ((0xff & data) << 8) | ((0xff00 & data) >> 8);
}
// 指针版
void swap_two_byte_pointer(unsigned short *ptr) {
// 取出第一个字节数据
unsigned char tmp = *((unsigned char *) ptr);
*((unsigned char *) ptr) = *((unsigned char *) ptr + 1);
*((unsigned char *) ptr + 1) = tmp;
}
P2格式创建和读取
创建
封装的方法
void pgm_p2_write(const char *fileName, int width, int height, int maxValue) {
FILE *fp = fopen(fileName, "w");
if (fp == nullptr) exit(-1);
const char *comment = "#这是注释信息";
// fputs是一个函数,具有的功能是向指定的文件写入一个字符串(不自动写入字符串结束标记符‘fputs’)
("P2",) fp;fputc
('\n',) fp;fprintf
(,fp"%s\n",)comment;fprintf
(,fp"%d %d\n" ,, width) height;// max value
fprintf
(,fp"%d" ,) maxValue;fputc
('\n',) fp;// 数据
for
( int= i 0 ;< i ; width++ )ifor {
( int= j 0 ;< j ; height++ )jfprintf {
(,fp"%d" ,( +i ) j& ) maxValue;}
fputc
('\n',) fp;}
fclose
()fp;}
int
测试
main ()pgm_p2_write{
("pgm2.pgm",30 ,30 ,50 );}
void
读取生成文件结果
封装方法
pgm_p2_read (constchar * )fileName* {
FILE =fp fopen (,fileName"r" );char
[ buf1024];fgets
(,buf1024 ,) fp;printf
("协议:%s",) buf;// 跳过空格或注释
skip_comment
()fp;int
, width; heightfscanf
(,fp"%d %d" ,& ,width& )height;printf
("%d %d\n",, width) height;// 跳过空格或注释
skip_comment
()fp;int
; maxfscanf
(,fp"%d" ,& )max;printf
("%d\n",) max;// 跳过空格或注释
skip_comment
()fp;unsigned
[ data]width[]height;for
( int= i 0 ;< i ; width++ )ifor {
( int= j 0 ;< j ; height++ )jfscanf {
(,fp"%d" ,& [data]i[]j);printf
("%d ",[ data]i[]j);}
printf
("\n");}
fclose
()fp;}
void
P5格式
创建
封装方法
pgm_p5_write (constchar * ,fileNameint , widthint , heightint ) maxValue* {
FILE =fp fopen (,fileName"wb+" );if
( ==fp ) nullptrexit (-1);fprintf
(,fp"P5\n" );fprintf
(,fp"%d %d\n" ,, width) height;// max value
fprintf
(,fp"%d\n" ,) maxValue;// 判断数据写入占用的字节数,只做1字节和2字节的
int
= dataSize 1 ;if
( )maxValue > UCHAR_MAX= {
dataSize 2 ;}
for
( int= i 0 ;< i ; width++ )ifor {
( int= j 0 ;< j ; height++ )junsigned {
short = value ( +i ) j% == maxValue 0 ? : maxValue ( +i ) j% ; maxValueif
( ==dataSize 2 )= {
value swap_two_byte ()value;}
// printf("%d ", value);
fwrite
(&,value, dataSize1 ,) fp;}
// printf("\n");
}
fclose
()fp;}
void
读取
封装方法
pgm_p5_read (constchar * )fileName* {
FILE =fp fopen (,fileName"rb" );char
[ buf1024];fscanf
(,fp"%s" ,) buf;printf
("%s\n",) buf;skip_comment
()fp;skip_comment
()fp;int
, width; heightfscanf
(,fp"%d %d" ,& ,width& )height;printf
("%d %d\n",, width) height;skip_comment
()fp;unsigned
= max 0 ;fscanf
(,fp"%d" ,& )max;printf
("%d\n",) max;if
( peek()fp== '\n' )fgetc {
()fp;}
// data
unsigned
; numif
( )max > UCHAR_MAX= {
num 2 ;}
else = {
num 1 ;}
for
( int= i 0 ;< i ; width++ )ifor {
( int= j 0 ;< j ; height++ )junsigned {
short ; datafread
(&,data, num1 ,) fp;// if (num == 2) data = swap_two_byte(data); // 移位 *** 作
if
( ==num 2 )swap_two_byte_pointer (&)data;// 地址 *** 作 printf
("%d ",) data;}
printf
("\n");}
fclose
()fp;}
int
P2格式和P5格式文件的比较
测试代码
main ()pgm_p2_write {
("p2_file.pgm",100 ,200 ,257 );pgm_p5_write
("p5_file.pgm",100 ,200 ,257 );}
在P5格式文件的读写中,在存储多字节数据的时候是有一个字节序的写入的问题;所以要么写入多字节数据的时候,按照要求一个字节的写入;要么就是直接对字节存放的数据进行交换,然后一次写入数据(读取的时候也是需要根据写入的数据来还原)
遇到的问题结果
- 这篇博客是用来学习根据PGM文件格式来联系二进制数据的读取和解析
- 准备在下一篇博客对代码结构进行封装和两种格式之间进行转换
- 有什么问题请指出(虚心求教)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)