cs50 的 copy.c 文件如何真正找到位图文件的正确部分?

Posted

技术标签:

【中文标题】cs50 的 copy.c 文件如何真正找到位图文件的正确部分?【英文标题】:how does cs50's copy.c file actually find the correct part of the bitmap file? 【发布时间】:2019-06-22 11:23:29 【问题描述】:

经过长时间的拖延,我回到了完成 cs50x2019 的第 3 周 - 但我意识到我忘记了一些来自 whodunit 练习的位图内容,因此我需要在继续调整大小之前进行学习。

我在理解 copy.c 是如何实际找到 bmp 文件的相关部分以完成工作时遇到了一些麻烦。

这是他们代码的相关部分 -

    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // read infile's BITMAPINFOHEADER
    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

据我了解,他们在这里创建指针并将所有输入文件存储在那里或仅存储特定部分。

// ensure infile is (likely) a 24-bit uncompressed BMP 4.0
    if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
        bi.biBitCount != 24 || bi.biCompression != 0)

他们正在根据 bmp.h 检查结构,以确保在继续之前一切正常。

但是,他们如何以及在哪里说明位图文件的哪一部分被存储?

如果不是,那么 bf.bftype 和 bi.bftype 是否等效?

是否需要同时拥有 bf 和 bi?

我觉得我错过了一些非常明显的东西。

下面的完整副本.c

// Copies a BMP file

#include <stdio.h>
#include <stdlib.h>

#include "bmp.h"

int main(int argc, char *argv[])

    // ensure proper usage
    if (argc != 3)
    
        printf("Usage: copy infile outfile\n");
        return 1;
    

    // remember filenames
    char *infile = argv[1];
    char *outfile = argv[2];

    // open input file
    FILE *inptr = fopen(infile, "r");
    if (inptr == NULL)
    
        printf("Could not open %s.\n", infile);
        return 2;
    

    // open output file
    FILE *outptr = fopen(outfile, "w");
    if (outptr == NULL)
    
        fclose(inptr);
        printf("Could not create %s.\n", outfile);
        return 3;
    

    // read infile's BITMAPFILEHEADER
    BITMAPFILEHEADER bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // read infile's BITMAPINFOHEADER
    BITMAPINFOHEADER bi;
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);

    // ensure infile is (likely) a 24-bit uncompressed BMP 4.0
    if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
        bi.biBitCount != 24 || bi.biCompression != 0)
    
        fclose(outptr);
        fclose(inptr);
        printf("Unsupported file format.\n");
        return 4;
    

    // write outfile's BITMAPFILEHEADER
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    // write outfile's BITMAPINFOHEADER
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

    // determine padding for scanlines
    int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    
        // iterate over pixels in scanline
        for (int j = 0; j < bi.biWidth; j++)
        
            // temporary storage
            RGBTRIPLE triple;

            // read RGB triple from infile
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

            // write RGB triple to outfile
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        

        // skip over padding, if any
        fseek(inptr, padding, SEEK_CUR);

        // then add it back (to demonstrate how)
        for (int k = 0; k < padding; k++)
        
            fputc(0x00, outptr);
        
    

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;

【问题讨论】:

一个 BMP 文件有 4 个不同的部分,它们在文件中按顺序相互跟随,因此读/写它们不需要发生任何戏剧性的事情。首先是文件头,bfType 字段提供了一个基本检查,即这实际上是一个 BMP 文件,而不仅仅是一个文件扩展名错误的文件。接下来是信息标头,它描述了位图的基本属性,例如 biBitCount。它没有 bfType 字段。接下来是颜色表,这里没有编程,因为 24bpp 图像没有。最后是描述像素的字节,这里比较简单,因为代码只支持24bpp。 【参考方案1】:

从 Gaga 那里偷东西:这样定义。

但是,他们如何以及在哪里说位图文件的哪一部分是 被存储了?

第一个fread 正在读取第一个sizeof(BITMAPFILEHEADER) 字节,按照微软的定义是14,在bmp.h 中定义BITMAPFILEHEADER

第二个fread 读取下一个sizeof(BITMAPINFOHEADER) 字节,按照相同的定义是40 个字节。

如果不是,那么 bf.bftype 和 bi.bftype 是否等效?

没有bi.bftype

是否需要同时拥有 bf 和 bi?

当然。每个结构中存储了不同的信息。

也许研究一下规范中的这张图片如何对应于bmp.h

不要忘记按照规范中的建议访问bmp.h 中的 Microsoft 链接。

附录:

是代码能够准确拉取相关的唯一原因 咬是因为 'fread' 记住了文件中的位置?

没错!

【讨论】:

仍然无法理解。 ` 位图文件头 bf; fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr); BITMAPINFOHEDER 双; fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr); ` 正如您所指出的,这两个都定义了差异大小的不同变量,14 和 37。并且输入来自同一个文件“inptr”是因为“fread”记住了文件中的位置,代码能够准确地提取相关内容的唯一原因吗?否则,它怎么知道要查找哪个 14 和 37 字节? 是的,'fread' 是关键,修改了答案。 (而且 BITMAPINFOHEADER 更像是 40 个字节(包括 14 到 53),对于数学来说还为时过早:)

以上是关于cs50 的 copy.c 文件如何真正找到位图文件的正确部分?的主要内容,如果未能解决你的问题,请参考以下文章

我的位图文本文件中的所有字符都是中文

jQuery:如何找到第一个可见的输入/选择/文本区域,不包括按钮?

win32api:在文本行中合并位图

Oracle 在 SQL Server 中的位图索引

如何在我的解决方案的所有 .cs 文件中找到所有以 "" 结尾的字符串?

在图像文件中查找一行