В выходном файле отсутствует заполнение в конце файла для растрового изображения. Почему это? - PullRequest
0 голосов
/ 04 октября 2019

В этой программе я пытаюсь использовать файлы в стиле C для чтения и записи этих файлов. Я также динамически распределяю память в кучу с помощью new () и удаляю ее, чтобы затем записать этот блок памяти в другой файл. По какой-то причине, когда я готовлю шестнадцатеричный горб, файлы почти одинаковы. Только конечные байты отличаются. Вот мои дампы.

INPUT FILE (mino.bmp)

Это для моего входного файла. Вывод должен иметь те же данные.

OUTPUT FILE (test.bmp)

Это мой выходной файл. Из дампа видно, что он отличается в конце файла. Почему это происходит, если я использую fseek (), чтобы пропустить заполнение?

#include <cstdint>
#include <cstdio>

#pragma pack(push, 2)
struct BitmapFileHeader {

    uint16_t type;
    uint32_t size;
    uint16_t reserved_1;
    uint16_t reserved_2;
    uint32_t offset;

};
struct BitmapInfoHeader {

    uint32_t size;
    uint32_t width;
    uint32_t height;
    uint16_t planes;
    uint16_t bitcount;
    uint32_t compression;
    uint32_t imagesize;
    uint32_t x_pixels_per_meter;
    uint32_t y_pixels_per_meter;
    uint32_t color_used;
    uint32_t color_important;
};
#pragma pack(pop)

struct Pixel {
    uint8_t blue;
    uint8_t green;
    uint8_t red;
};

int main(int argc, char* argv[])
{
    if(argc != 3) {
        printf("Usage : %s input_file output_file\n", argv[0]);
        return 1;
    }

    FILE *fin;
    FILE *fout;
    BitmapFileHeader bfh;
    BitmapInfoHeader bih;

    fin = fopen(argv[1], "rb");

    if (nullptr == fin) {
        perror(argv[1]);
        return -1;
    }

    if (sizeof(BitmapFileHeader) != fread(
        &bfh,
        1,
        sizeof(bfh),
        fin
    )) {
        printf("Unable to read bitmap file header. \n");
        return -2;
    }

    if (sizeof(BitmapInfoHeader) != fread(
        &bih,
        1,
        sizeof(bih),
        fin
    )) {
        printf("Unable to read bitmap info header. \n");
        return -3;
    }

    printf("Size of File Header = %lu\n", sizeof(BitmapFileHeader));

    int8_t first = (bfh.type >> 8) & 0xff;
    int8_t second = bfh.type & 0xff;

    if ( (first != 'M') && (second != 'B') ){
        printf("Input file is not a Bitmap file. \n");
        return -4;
    }

    printf("File type = %c%c\n", first, second);
    printf("File size = %u\n", bfh.size);
    printf("File offset = %u\n", bfh.offset);
    printf("File width = %u\n", bih.width);
    printf("Info size = %u\n", bih.size);

    uint32_t padding_bytes = 0;
    uint32_t row_bytes_final = bih.width * sizeof(Pixel);
    uint32_t row_bytes_initial = row_bytes_final;

    do{
        uint32_t rem = row_bytes_final % 4;

        if (rem != 0) {
            row_bytes_final += 1;
        }

        padding_bytes = row_bytes_final - row_bytes_initial;

    } while( (row_bytes_final % 4) != 0);


    fseek(fin, bfh.offset, SEEK_SET);

    Pixel *p = new Pixel[bih.height * bih.width];

    for (uint32_t i = 0; i < bih.height; i++) {

        for (uint32_t j = 0; j < bih.width; j++) {

            uint32_t index = i * bih.width + j;

            fread(&p[index], 1, sizeof(p[0]), fin);
        }

        fseek(fin, padding_bytes, SEEK_CUR);

    }

    fclose(fin);


    fout = fopen(argv[2], "wb");

    if(nullptr == fout) {
        perror(argv[2]);
        return -5;
    }

    if( sizeof(BitmapFileHeader) != fwrite(
    &bfh, 
    1, 
    sizeof(bfh), 
    fout
    )) {
        printf("Unable to write bitmap file header.\n");
        return -6;
    }

    if( sizeof(BitmapInfoHeader) != fwrite(
        &bih, 
        1, 
        sizeof(bih), 
        fout
        )) {
            printf("Unable to write bitmap info header.\n");
            return -7;
        }

    fseek(fout, bfh.offset, SEEK_SET);

    for (uint32_t i = 0; i < bih.height; i++) {

        for (uint32_t j = 0; j  < bih.width; j++) {

            uint32_t index = i * bih.width + j;

            fwrite(&p[index], 1, sizeof(p[0]), fout);

        }

        fseek(fout, padding_bytes, SEEK_CUR);

    }


    fclose(fout);
    delete p;


    //fseek(fin, bfh.offset, SEEK_SET);
    //Pixel p;
    //fread(&p, 1, sizeof(p), fin);
    //printf("R = %u, G = %u, B = %u\n", p.red, p.green, p.blue);
    return 0;

}

1 Ответ

1 голос
/ 04 октября 2019

Поиск позиции за концом файла не дополняет его автоматически. Байты заполнения будут записываться только при последующей записи.

Вы можете принудительно записать этот последний заполнитель после завершения цикла следующим образом:

if (padding_bytes > 0) {
    fseek(fout, -1, SEEK_CUR);
    fputc('\0', fout);
}

Кстати, вы используетенеправильно delete для вашего массива. Вместо этого используйте array-delete (соответствует array-alloc):

delete[] p;
...