在控制台上显示BMP图像时损坏的堆

时间:2018-03-19 05:41:31

标签: c++ console heap heap-memory bmp

我有一个练习。它说,C程序应该能够读取位图文件的信息,然后它应该在控制台上显示图片。

我已经编写了代码,但是当它无法正常工作时。 当我调试代码时,它看起来像堆已损坏。我认为我在ScanPixelline函数中有一个已知的故障/错误。

我不知道如何修复它。有人可以帮我查一下吗? 我对C编程比较陌生。

#include "stdafx.h"
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "stdint.h"
#include "windows.h"
#pragma pack(1)
struct BMP
{
    char Type[2];           //File type. Set to "BM".
    int32_t Size;     //Size in BYTES of the file.
    int16_t Reserved1;      //Reserved. Set to zero.
    int16_t Reserved2;      //Reserved. Set to zero.
    int32_t OffSet;   //Offset to the data.
    int32_t headsize; //Size of rest of header. Set to 40.
    int32_t Width;     //Width of bitmap in pixels.
    int32_t Height;     //  Height of bitmap in pixels.
    int16_t Planes;    //Number of Planes. Set to 1.
    int16_t BitsPerPixel;       //Number of Bits per pixels.
    int32_t Compression;   //Compression. Usually set to 0.
    int32_t SizeImage;  //Size in bytes of the bitmap.
    int32_t XPixelsPreMeter;     //Horizontal pixels per meter.
    int32_t YPixelsPreMeter;     //Vertical pixels per meter.
    int32_t ColorsUsed;   //Number of colors used.
    int32_t ColorsImportant;  //Number of "important" colors.
};
struct Color
{
    unsigned char B;
    unsigned char G;
    unsigned char R;

};
struct ColorTable
{
    Color    *colors;
    unsigned long length;
};

struct PixelArray
{
    Color    **pixels;
    unsigned long rowCount;
    unsigned long columnCount;
};
void readBMP(char *File_Name, BMP &a)
{
    FILE *p = fopen(File_Name, "rb");
    if (p == NULL)
    {
        printf("Can't open file!");
        fclose(p);
        return;
    }
    else
    {
        fread(&a, sizeof(BMP), 1, p);
    }
    fclose(p);
}
void Get_Inf(BMP a)
{
    if (a.Type[0] != 'B' || a.Type[1] != 'M')
    {
        printf("This is not a BMP file");
    }
    else
    {
        printf("This is a BMP file\n");
        printf("The size of this file is %lu bytes\n", a.Size);
        printf("The witdth of this image is %lu pixels\n", a.Width);
        printf("The height of this image is %lu pixels\n", a.Height);
        printf("The number of bits per pixels in this image is %u\n", a.BitsPerPixel);
    }

}
void scanBmpPixelLine(Color *&line, unsigned long length)
{
    FILE *pointer_ = fopen("test.bmp", "rb");
    line = new Color[length];
    fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
    fclose(pointer_);
    //file.read((char *)line, length * sizeof(Color));
}
void skipBmpPadding(char count)
{
    FILE *pointer__ = fopen("test.bmp", "rb");
    if (count == 0)
    {
        fclose(pointer__);
        return;
    }
    char padding[3];
    fread(&padding, sizeof(char), count, pointer__);
    fclose(pointer__);
    //file.read((char *)&padding, count);
}
void ReadPixelArray(BMP a, PixelArray &data)
{
    FILE *pointer = fopen("test.bmp", "rb");
    data.rowCount = a.Height;
    data.columnCount = a.Width;
    data.pixels = new Color*[data.rowCount];
    char paddingCount = (4 - (a.Width * (a.BitsPerPixel / 8) % 4)) % 4;
    fseek(pointer, 54, SEEK_SET);
    for (int i = 0; i < data.rowCount; i++)
    {
        scanBmpPixelLine(data.pixels[data.rowCount - i - 1], a.Width);
        skipBmpPadding(paddingCount);
    }
}
void drawBmp(BMP a, PixelArray data)
{
    HWND console = GetConsoleWindow();
    HDC hdc = GetDC(console);

    for (int i = 0; i < a.Height; i++)
        for (int j = 0; j < a.Width; j++)
        {
            Color pixel = data.pixels[i][j];
            SetPixel(hdc, j, i, RGB(pixel.R, pixel.G, pixel.B));
        }

    ReleaseDC(console, hdc);
}

void releaseBmpPixelArray(PixelArray data)
{
    for (int i = 0; i < data.rowCount; i++)
        delete[]data.pixels[i];

    delete[]data.pixels;
}
int main()
{
    char file_name[] = "test.bmp";
    BMP a;
    PixelArray data;
    readBMP(file_name, a);
    Get_Inf(a);
    ReadPixelArray(a, data);
    drawBmp(a, data);
    releaseBmpPixelArray(data);
}

1 个答案:

答案 0 :(得分:1)

此功能:

void scanBmpPixelLine(Color *&line, unsigned long length)
{
    FILE *pointer_ = fopen("test.bmp", "rb");
    line = new Color[length];
    fread(line, sizeof(Color), sizeof(Color)*length, pointer_);
    fclose(pointer_);
    //file.read((char *)line, length * sizeof(Color));
}

对于初学者来说,该功能的目的似乎是从文件中读取一行像素数据。但相反,它重新打开文件并从头开始读取(头部字节所在的位置)。我不确定你是否意识到这一点...

但崩溃是这一行的结果:

    fread(line, sizeof(Color), sizeof(Color)*length, pointer_);

第二个参数sizeof(Color)是每个元素的大小。第三个参数是要读取的元素数。从文件读取的总字节数将是第二个参数乘以第三个参数。所以你多次乘以sizeof(Color)多次。结果是它将覆盖line缓冲区。

要修复,它应该是:

fread(line, sizeof(Color), length, pointer_);

您可能希望将从FILE* pointer函数获取的ReadPixelArray传递给此函数,而不是为每一行重新打开文件。

另一个代码审核评论。您应该将整个文件读入内存,而不是为每个操作冗余地打开和关闭文件。然后解析标题并设置指向第一个&#34;行的指针&#34;标题之后。