Error[8]: Undefined offset: 777, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

PGM格式文件的解析和读取

概述

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. 有什么问题请指出(虚心求教)
    3. [+++]
    )
    File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
    File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
    File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
    ffmpeg学习准备之pgm格式文件的解析_C_内存溢出

    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. 有什么问题请指出(虚心求教)

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

    原文地址: http://outofmemory.cn/langs/578565.html

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

    发表评论

    登录后才能评论

    评论列表(0条)

    保存