我坚持在 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);
}
}
我被困在调整大小问题的垂直调整大小部分。我从 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);
}
}