我在pset 4-CS50上无法调整垂直大小

时间:2019-08-26 07:00:46

标签: c cs50

我在调整大小问题的垂直方向上卡住了。我从Zamayla的伪代码知道,我每次都需要在输出文件上写一个数组,但是我不知道如何将值从一个传递到另一个。我是否需要使用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;
}

2 个答案:

答案 0 :(得分:1)

为简单起见,可以说源图像为3x2像素。如果您使用像素坐标将其绘制在“纸”(我真的建议您使用真正的笔和纸)上进行绘制,则其外观将如下所示:

+-----+-----+-----+
| 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个“像素”大,另一个用于{{1} }“像素”大。然后,您使用一个循环从原始图像中获取每个像素,然后嵌套在内部,您将拥有另一个循环,将该像素写入新图像中的所有位置。

代码中,可能是这样的

(W*n)x(H*n)

现在,您可能已经注意到,我没有提到“像素”的类型。那是因为没关系。可以是浮点值,整数值或// 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); } } } } 的结构。

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

答案 1 :(得分:0)

有不同的处理方法。一种选择是:

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

还请注意,在Windows中,您需要"rb""wb"才能以二进制形式读取/写入文件:

示例:

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);
    }
}