我坚持在 pset 4 - CS50 上调整垂直大小

I'm stuck on vertical resizing on pset 4 - CS50

我被困在调整大小问题的垂直调整大小部分。我从 Zamayla 的伪代码中知道我每次都需要在 outfile 上写一个数组,但我不知道如何将值从一个传递到另一个。我是否需要使用 malloc 函数并通过指针传递?我使用这个不是很有经验,因为我是编程新手。请告诉我我的代码是否朝着正确的方向前进。

// Resize a bmp file 

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

#include "bmp.h"

int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
    fprintf(stderr, "Usage: resize queficient infile outfile\n");
    return 1;
}
int n = atoi(argv[1]);

if (n < 1 || n > 100)
    {
        printf ("Resize queficient should be between 1 and 100\n");
        return 1;
    }


// remember filenames
char *infile = argv[2];
char *outfile = argv[3];
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
    fprintf(stderr, "Could not open %s.\n", infile);
    return 2;
}

// open output file
FILE *outptr = fopen(outfile, "w");
if (outptr == NULL)
{
    fclose(inptr);
    fprintf(stderr, "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);
    fprintf(stderr, "Unsupported file format.\n");
    return 4;
}
/* Update header info
*saving old information
*/
BITMAPINFOHEADER old_bi;
BITMAPFILEHEADER old_bf;
old_bi = bi;
old_bf = bf;
old_bi.biHeight = bi.biHeight;
old_bi.biWidth = bi.biWidth;
int old_padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

// assign new header
bi.biHeight = bi.biHeight * n;
bi.biWidth = bi.biWidth * n;
int new_padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + new_padding) * abs(bi.biHeight);
bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

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

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



// Resize horizontally
for (int i = 0, old_biHeight = abs(old_bi.biHeight); i < old_biHeight; i++)
{
    // iterate over pixels in scanline
    for (int j = 0; j < old_bi.biWidth; j++)
    {

        // temporary storage
        RGBTRIPLE triple;

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

        triple.rgbtBlue = n * triple.rgbtBlue;
        triple.rgbtRed = n * triple.rgbtRed;
        triple.rgbtGreen = n * triple.rgbtGreen;

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

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

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

/*Resize vertically
for (int i = 0, old_biHeight = abs(old_bi.biHeight); i < old_biHeight; i++ )
{
    for (int j = 0; j < old_bi.biWidth; j++)
    {
        RGBTRIPLE triple;
        char *array_of_pixels_Blue  = { "n * triple.rgbtBlue" };
        char *array_of_pixels_Red  = { "n * triple.rgbtRed" };
        char *array_of_pixels_Green  = { "n * triple.rgbtGreen" };
    }

    for (int k = 0; k < n; k++)
    {
        fwrite(&array_of_pixels_Blue, sizeof(RGBTRIPLE), 1, outptr);
        fwrite(&array_of_pixels_Red, sizeof(RGBTRIPLE), 1, outptr);
        fwrite(&array_of_pixels_Green, sizeof(RGBTRIPLE), 1, outptr);

        for (int l = 0; l < new_padding; l++)
        {
            fputc(0x00, outptr);
        }
    }
}
    fseek(inptr, new_padding, SEEK_CUR);
*/

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// success
return 0;
}

为简单起见,假设源图像为 3x2 像素。如果你用像素坐标在 "paper" 上画出来(我真的建议你这样做,用真正的笔和纸)它看起来像这样:

+-----+-----+-----+
| 0,0 | 1,0 | 2,0 |
+-----+-----+-----+
| 0,1 | 1,1 | 2,1 |
+-----+-----+-----+

如果将其与 2 相乘(以获得双倍大小的图像),那么它就变成了 6x4 像素的图像。放大像素最简单的方法就是在所有方向上也将它们加倍。然后放大的图像看起来像这样(使用原始图像的像素坐标):

+-----+-----+-----+-----+-----+-----+
| 0,0 | 0,0 | 1,0 | 1,0 | 2,0 | 2,0 |
+-----+-----+-----+-----+-----+-----+
| 0,0 | 0,0 | 1,0 | 1,0 | 2,0 | 2,0 |
+-----+-----+-----+-----+-----+-----+
| 0,1 | 0,1 | 1,1 | 1,1 | 2,2 | 2,2 |
+-----+-----+-----+-----+-----+-----+
| 0,1 | 0,1 | 1,1 | 1,1 | 2,2 | 2,2 |
+-----+-----+-----+-----+-----+-----+

原始图像中的每个像素现在是新图像中的四个像素。大小按乘数的平方增长(因此 3 的乘数意味着原始图像中的每个像素在新图像中变为 9 像素)。

有几种不同的代码处理方式,但最简单的是分配两个内存区域,一个用于原始图像 WxH "pixels" 大,另一个用于(W*n)x(H*n) "pixels" 大。然后,您使用一个循环从原始图像中获取每个像素,并在内部嵌套另一个循环,该循环将该像素写入新图像中的所有位置。

代码中可能是这样的

// Loops over all the pixels in the original source image
for (unsigned orig_x = 0; orig_x < ORIG_WIDTH; ++orig_x)
{
    for (unsigned orig_y = 0; orig_y < ORIG_HEIGHT; ++orig_y)
    {
        orig_pixel = GetPixelAt(orig_pixel_data, orig_x, orig_y);

        // Write the original pixel (orig_pixel) N*N times in the new image data
        for (unsigned new_x = 0; new_x < N; ++new_x)
        {
            for (unsigned new_y = 0; new_y < N; ++new_y)
            {
                SetPixelAt(new_pixel_data, new_x + orig_x * N, new_y + orig_y * N, orig_pixel);
            }
        }
    }
}

现在您可能已经注意到,我没有提到 "pixels" 的类型。那是因为没关系。它可以是浮点值、整数值或 RGBTRIPLE.

的结构

正如我之前提到的,首先使用笔和纸完成所有操作

有不同的方法来处理这个问题。一种选择是:

  • 每行读取一次,并将该行写入 n 次。
  • 读取每个像素一次,写入该像素 n 次。

另请注意,在 Windows 中,您需要 "rb""wb" 到 read/write 二进制文件:

示例:

FILE *outptr = fopen(outfile, "wb");
...
FILE *inptr = fopen(infile, "rb");
...
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);

int old_width_in_bytes = old_bi.biWidth * 3 + old_padding;

for(int i = 0, old_biHeight = abs(old_bi.biHeight); i < old_biHeight; i++)
{
    //skip bytes for each row, 54 bytes to account for header size
    //old_width_in_bytes to account for padding
    fseek(inptr, 54 + old_width_in_bytes * i, SEEK_SET);

    //read/write each row, n-times
    for(int resize_height = 0; resize_height < n; resize_height++)
    {
        // iterate over pixels in scanline
        for(int j = 0; j < old_bi.biWidth; j++)
        {
            RGBTRIPLE triple;
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

            // write each pixel n-times
            for(int resize_width = 0; resize_width < n; resize_width++)
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }

        //padding for output
        for(int k = 0; k < new_padding; k++)
            fputc(0x00, outptr);
    }
}