如何读取和写入ppm文件

How to read and write a ppm file?

本文关键字:ppm 文件 何读取 读取      更新时间:2023-10-16

我尝试读取一个ppm文件并创建一个相同的新文件。但当我用GIMP2打开它们时,图像就不一样了。

我的代码哪里有问题?

int main()
{
    FILE *in, *out;
    in = fopen("parrots.ppm","r");
    if( in == NULL )
    {
        std::cout<<"Error.n";
        return 0;
    }
    unsigned char *buffer = NULL;
    long size = 0;
    fseek(in, 0, 2);
    size = ftell(in);
    fseek(in, 0, 0);
    buffer = new unsigned char[size];
    if( buffer == NULL )
    {
        std::cout<<"Errorn";
        return 0;
    }
    if( fread(buffer, size, 1, in) < 0 )
    {
          std::cout<<"Error.n";
          return 0 ; 
    }
    out = fopen("out.ppm","w");
    if( in == NULL )
    {
         std::cout<<"Error.n";
         return 0;
    }
    if( fwrite(buffer, size, 1, out) < 0 )
    {
         std::cout<<"Error.n";
         return 0;
    }
    delete[] buffer;
    fcloseall();
    return 0;
}

在此之前,我阅读了一个结构中的ppm文件,当我写它时,我得到了相同的图像,但绿色比原始图片中更强烈。然后我尝试了这种简单的阅读和写作,但我得到了同样的结果。

int main()

缺少include。

FILE *in, *out;

C++程序中的C风格I/O,为什么?此外,在初始化时声明,接近首次使用。

in = fopen("parrots.ppm","r");

这是以文本模式打开文件,这肯定不是您想要的。使用"rb"作为模式

unsigned char *buffer = NULL;

在初始化时声明,接近首次使用。

fseek(in, 0, 2);

您应该使用SEEK_END,它不能保证定义为2

fseek(in, 0, 0);

参见上文,对于不保证定义为0的SEEK_SET

buffer = new unsigned char[size];
if( buffer == NULL )

默认情况下,new不会返回NULL指针,而是抛出std::bad_alloc异常。(由于过度分配是大多数当前操作系统的常态,即使使用malloc(),检查NULL也无法防止内存不足,但很高兴看到你养成了检查的习惯。)

C++11给我们带来了聪明的指针。使用它们。它们是避免内存泄漏的优秀工具(C++为数不多的弱点之一)。

if( fread(buffer, size, 1, in) < 0 )

成功使用fread应返回写入的对象数,应检查其是否等于第三个参数(!= 1),而不是< 0

out = fopen("out.ppm","w");

再次进入文本模式,此处需要"wb"

if( fwrite(buffer, size, 1, out) < 0 )

请参阅上面关于fread返回值的注释。这里也是如此。

fcloseall();

不是标准功能。使用fclose( in );fclose( out );


一个C++11化的解决方案(为了简洁起见,省略了错误检查)看起来有点像这样:

#include <iostream>
#include <fstream>
#include <memory>
int main()
{
    std::ifstream in( "parrots.ppm", std::ios::binary );
    std::ofstream out( "out.ppm", std::ios::binary );
    in.seekg( 0, std::ios::end );
    auto size = in.tellg();
    in.seekg( 0 );
    std::unique_ptr< char[] > buffer( new char[ size ] );
    in.read( buffer.get(), size );
    out.write( buffer.get(), size );
    in.close();
    out.close();
    return 0;
}

当然,智能解决方案将通过Boost.filesystem或标准功能(在撰写本文时是实验性的)执行实际的文件系统复制。