使用字节数组 C++ 时出错

Posted

技术标签:

【中文标题】使用字节数组 C++ 时出错【英文标题】:Error when using byte array C++ 【发布时间】:2013-03-31 09:52:11 【问题描述】:

我正在尝试将标准 24 位 BMP 文件读入字节数组,以便我可以将该字节数组发送到 libpng 以保存为 png。我的代码,编译:

#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <Windows.h>
#include "png.h"

using namespace std;

namespace BMP2PNG 
long getFileSize(FILE *file)
    
        long lCurPos, lEndPos;
        lCurPos = ftell(file);
        fseek(file, 0, 2);
        lEndPos = ftell(file);
        fseek(file, lCurPos, 0);
        return lEndPos;
    


private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
         
             std::string filenamePNG = "D:\\TEST.png";
             FILE *fp = fopen(filenamePNG.c_str(), "wb");

             png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);

             png_info *info_ptr = png_create_info_struct(png_ptr);

             png_init_io(png_ptr, fp);

             png_set_IHDR(png_ptr,info_ptr,1920,1080,16,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);

             png_write_info(png_ptr,info_ptr);
             png_set_swap(png_ptr);

             const char *inputImage = "G:\\R-000.bmp";
             BYTE *fileBuf;
             BYTE *noHeaderBuf;
             FILE *inFile = NULL;

             inFile = fopen(inputImage, "rb");

             long fileSize = getFileSize(inFile);

             fileBuf = new BYTE[fileSize];
             noHeaderBuf = new BYTE[fileSize - 54];

             fread(fileBuf,fileSize,1,inFile);

             for(int i = 54; i < fileSize; i++) //gets rid of 54-byte bmp header
             
                noHeaderBuf[i-54] = fileBuf[i];
             

             fclose(inFile);

             png_write_rows(png_ptr, (png_bytep*)&noHeaderBuf, 1);

             png_write_end(png_ptr, NULL);

             fclose(fp);
         
;

不幸的是,当我单击运行代码的按钮时,我收到错误消息“尝试读取或写入受保护的内存...”。我对 C++ 很陌生,但我认为我正确地读取了文件。为什么会发生这种情况,我该如何解决?

另外,我的最终目标是一次读取一个像素行的 BMP,这样我就不会使用太多内存。如果 BMP 是 1920x1080,我只需要为每行读取 1920 x 3 个字节。我将如何一次将文件读入一个字节数组 n 个字节?

【问题讨论】:

没有错误检查 - fopen 调用成功了吗? 而不是 fseek(file, 0, 2) 中的“通配符”,您应该使用 fseek(file, 0, SEEK_END)。 SEEK_SET 和第三个 SEKK_ 也是如此。它的可读性更高,而不是代码不那么混乱。 您显然在使用 C++/CLI。我不确定您使用的是 WinForms 还是 WPF。如果您是 C++ 新手,这可能不是最好的起点。您最好使用 C# 并使用 .NET 框架的工具来转换您的图像。看看***.com/questions/1060442/png-to-bmp。我知道您正在以另一种方式进行转换,但它同样简单。 @suspectus- 是的 fopen 调用成功,我只是无法读取文件。 @ ferruccio-我只是将 Visual C++ Express 与 Windows 窗体应用程序一起使用。如果可以的话,我绝对会使用 C#,因为我在这方面有更多经验,但是 libpng 仅针对 C 和 C++ 编写(当然,除非你可以告诉我如何在 C# 中使用 .lib 和 .h 文件)。我已经尝试过 .NET BMPEncoder 的东西,但它不能正确保存 PNG 文件,而且由于内存限制,我需要能够一次完成这一行。 如果出现错误,您是否尝试在调试器中运行代码,查看错误发生在哪里?你对错误的定义有点模糊。 【参考方案1】:

您的getFileSize() 方法实际上并未返回文件大小。您基本上移动到 BMP 标头中的正确位置,但不是实际读取表示大小的下 4 个字节,而是返回文件中的位置(始终为 2)。 然后在调用函数中,您没有任何错误检查,并且您的代码假定文件大小始终大于 54(例如读取缓冲区的分配)。

另外请记住,BMP 标头中的文件大小字段可能并不总是正确的,您还应该考虑实际文件大小。

【讨论】:

getFileSize() 是正确的,他不是从标题中读取大小,而是在磁盘上获取“真实”文件大小。 马丁是正确的。我不是试图从 BMP 标头本身读取文件大小——这永远不可靠。 你说得对,我完全误读了该函数中的第一个 fseek() 调用。 getFileSize() 确实是正确的,对此我很抱歉。【参考方案2】:

您正在读取 *.bmp 文件的文件大小,但“真实”数据可能更大。 BMP 可以进行压缩 (RLE)。之后,当您将解压缩的PNG写入该数组时,您可能会溢出图像大小,因为您预先获得了压缩BMP文件的大小。

【讨论】:

这里没有压缩——我希望未压缩的 bmp 的大小正好是 width*height*3 + 54 bytes,而这些文件是。【参考方案3】:

在函数中

png_set_IHDR(png_ptr,info_ptr,1920,1080,16,PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);

为什么将位深度设置为 16 ?不应该是 8,因为 BMP 的每个 RGB 通道都是 8 位的。

对于 PNG 处理,我正在使用这个库:http://lodev.org/lodepng/。它工作正常。

【讨论】:

以上是关于使用字节数组 C++ 时出错的主要内容,如果未能解决你的问题,请参考以下文章

C++ 数组中的多字节 UTF-8

net5.0 - 在微服务之间接收不同大小的字节数组时出错

调用外部 C++ 方法时无法识别字节数组

从 C++ 将字节数组传递给 lua 脚本方法

C++ <--> C# 修改编组的字节数组

从 c++ 到 c# 的 pinvoke 字节数组