ffmpeg学习准备之pgm格式文件的解析

ffmpeg学习准备之pgm格式文件的解析,第1张

PGM格式文件的解析和读取
  • 概述
  • 辅助函数
    • 说明
    • 代码
  • 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格式文件的读写中,在存储多字节数据的时候是有一个字节序的写入的问题;所以要么写入多字节数据的时候,按照要求一个字节的写入;要么就是直接对字节存放的数据进行交换,然后一次写入数据(读取的时候也是需要根据写入的数据来还原)
  • 结果

    遇到的问题
    1. 这篇博客是用来学习根据PGM文件格式来联系二进制数据的读取和解析
    总结
    1. 准备在下一篇博客对代码结构进行封装和两种格式之间进行转换
    2. 有什么问题请指出(虚心求教)

    欢迎分享,转载请注明来源:内存溢出

    原文地址:https://54852.com/langs/578565.html

    (0)
    打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
    上一篇 2022-04-11
    下一篇2022-04-11

    发表评论

    登录后才能评论

    评论列表(0条)

      保存