【发布时间】:2023-03-03 10:54:01
【问题描述】:
我正在学习如何在 OpenGL 中添加纹理,出于教育目的,我决定不使用“stb_image.h”之类的库来加载图像,而是为 .bmp 图像编写自己的库。
我使用的图片尺寸为 1920x1080(全高清),文件大小为 6.2 MB(6,220,922 字节)。在加载图像并将其从蓝色、绿色、红色 (BGR) 转换为红色、绿色、蓝色 (RGB) 后,我决定释放 BGR 版本,但在这样做时发生了“分段错误(核心转储)”。
我尝试过的其中一个方法是使用不同的图像,这会导致错误消失。 新的图像分辨率为 1280x1920,文件大小为 7.4 MB(7,372,922 字节)。
我决定翻转早期图像的尺寸(从 1920x1080 到 1080x1920),“分段错误(核心转储)”又回来了。
这是 C 中的相关代码(删除了所有 OpenGL 和 GLFW 的东西)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct
{
uint16_t type;
uint32_t size;
uint16_t reserved1;
uint16_t reserved2;
uint32_t offbit;
}BITMAPFILEHEADER;
typedef struct {
uint32_t size;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitcount;
uint32_t comprestiontype;
uint32_t sizeimage;
uint32_t xres;
uint32_t yres;
uint32_t crlused;
uint32_t crlimportant;
}BITMAPINFOHEADER;
typedef struct{
uint8_t r;
uint8_t g;
uint8_t b;
}RGB;
void ReadFileHeader(FILE* file, BITMAPFILEHEADER* fileHeader){
fread(&(fileHeader->type),2,1,file);
fread(&(fileHeader->size),4,1,file);
fread(&(fileHeader->reserved1),2,1,file);
fread(&(fileHeader->reserved2),2,1,file);
fread(&(fileHeader->offbit),4,1,file);
}
void ReadInfoHeader(FILE* file, BITMAPINFOHEADER* fileHeader){
fread(&(fileHeader->size),4,1,file);
fread(&(fileHeader->width),4,1,file);
fread(&(fileHeader->height),4,1,file);
fread(&(fileHeader->planes),2,1,file);
fread(&(fileHeader->bitcount),2,1,file);
fread(&(fileHeader->comprestiontype),4,1,file);
fread(&(fileHeader->sizeimage),4,1,file);
fread(&(fileHeader->xres),4,1,file);
fread(&(fileHeader->yres),4,1,file);
fread(&(fileHeader->crlused),4,1,file);
fread(&(fileHeader->crlimportant),4,1,file);
}
unsigned char* ReadBMP(const char * p_path, int* width, int* hight){
FILE* image = fopen(p_path,"rb");
if(image == NULL){
printf("file not found\n");
}
BITMAPFILEHEADER file_header;
BITMAPINFOHEADER info_header;
ReadFileHeader(image,&file_header);
ReadInfoHeader(image,&info_header);
if (width != NULL)
{
*width = info_header.width;
}
if (hight != NULL)
{
*hight = info_header.height;
}
unsigned char* pixelData = (unsigned char*)malloc(sizeof(RGB)*info_header.width*info_header.height);
fread(pixelData,sizeof(RGB),info_header.width*info_header.height,image);
fclose(image);
return pixelData;
}
unsigned char* BmpToRgb(unsigned char* input, int width,int hight){
RGB* data = (RGB*)malloc(width*hight*3);
int y = 0;
int x = 0;
memcpy(data,input,width*hight*3);
for (y = 0; y < hight; y++)
{
for (x = 0; x < width; x++)
{
// the problem is probably in these 3 lines, if i comment
// them out no "Segmentation fault (core dumped)" happens.
data[x+(hight-y)*width].r = input[x+y*width+2];
data[x+(hight-y)*width].g = input[x+y*width];
data[x+(hight-y)*width].b = input[x+y*width+1];
}
}
return (unsigned char*)data;
}
int main(){
int width;
int hight;
unsigned char* imageBMP = ReadBMP("image.bmp",&width,&hight);
printf("width: %d hight: %d\n",width,hight);
unsigned char* image = BmpToRgb(imageBMP,width,hight);
free(image);
printf("freeing\n");
free(imageBMP); // segmentation fault (core dumped) for 1920x1080 images
printf("done\n"); // "done" not printed
return 0;
}
我想知道为什么不同的图像分辨率(或者可能是文件大小)可能导致“分段错误(核心转储)”。
一些可能相关的额外信息:
Operating system : Ubuntu 20.04
c compiler: gcc
【问题讨论】:
-
首先,您需要使用调试器来捕获崩溃并定位代码中发生崩溃的时间和位置。我还推荐使用 Valgrind 等工具来帮助您找到此类问题。
-
还有
RGB结构might not be what you expect的大小,在这种情况下你没有分配足够的内存。 -
struct RGB的大小是3字节,没有struct padding,我查了。
-
data[x+(hight-y)*width].r = input[x+y*width+2];当y == 0写入超过分配的data缓冲区的末尾。input索引看起来也不正确。 -
附带说明,“width”和“hight”局部变量应定义为 uint32_t (unsigned int) 而不是 int。否则你可能会面临整数溢出。
标签: c