bmp.h
// BMP-related data types based on Microsoft's own
#include <stdint.h>
// aliases for C/C++ primitive data types
// https://msdn.microsoft.com/en-us/library/cc230309.aspx
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
// information about the type, size, and layout of a file
// https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;
// information about the dimensions and color format
// https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx
typedef struct
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} __attribute__((__packed__))
BITMAPINFOHEADER;
// relative intensities of red, green, and blue
// https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
resize.c
#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 n infile outfile\n");
return 1;
}
// remember factor and filenames
int factor = atoi(argv[1]);
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 outfile's BITMAPINFOHEADER
BITMAPINFOHEADER obi = bi;
obi.biWidth *= factor;
obi.biHeight *= factor;
// write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&obi, sizeof(BITMAPINFOHEADER), 1, outptr);
// determine padding for scanlines
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// determine outfile's padding
int out_padding = (4 - (obi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// remember pixels in an array
RGBTRIPLE * array[obi.biWidth];
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
array[0] = NULL;
int idx = 0;
printf("----------------------\nReading from file.\n----------------------\n");
// 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 to array n times
for(int k = 0; k < factor; k++)
{
array[idx] = &triple;
printf("scanline n°%d, pixel n°%d, array[%d] = %p, blue: %i, green: %i, red: %i\n", i, j, k, array[k], triple.rgbtBlue, triple.rgbtGreen, triple.rgbtRed);
++idx;
}
}
printf("\nNow writing to outfile...\n\n");
// for n times
for (int x = 0; x < factor; x++)
{
// write array to outfile
for(int y = 0; y < obi.biWidth; y++)
{
fwrite(array[y], sizeof(RGBTRIPLE), 1, outptr);
printf("scanline n°%d, array[%d] = %p\n", i, y, array[y]);
}
// write padding to outfile
for(int k = 0; k < out_padding; k++)
{
fputc(0x00, outptr);
}
}
// skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}
我正在尝试用C编写一个程序来调整BMP文件的大小。该程序采用三个参数(一个小BMP文件,要从该小BMP创建的大BMP文件的名称,以及增加该小BMP的因子)。
为此,我将要重复n次的每个像素扫描线存储在一个指针数组中,该数组将用于写入新的输出文件。我的问题是,尽管RGB值到达白色像素时会改变,但每个指针都有相同的地址。因此,输出文件只是一个绿色框,而不是中间带有白色像素的绿色框。我不知道为什么,有人可以解释为什么地址总是相同的
答案 0 :(得分:1)
RGBTRIPLE * array[obi.biWidth];
根据注释中的建议将其更改为RGBTRIPLE array[obi.biWidth];
或RGBTRIPLE *array = malloc(...)
。
将array[idx] = &triple;
更改为array[idx] = triple;
for(int y = 0; y < obi.biWidth; y++) { fwrite(array[y], sizeof(RGBTRIPLE), 1, outptr); }
您可以编写整个数组,而不必一次写一个元素:
RGBTRIPLE *array = malloc(obi.biWidth * sizeof(RGBTRIPLE));
for(int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
for(int j = 0; j < bi.biWidth; j++)
{
RGBTRIPLE triple;
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
for(int k = 0; k < factor; k++)
array[j * factor + k] = triple;
}
for(int x = 0; x < factor; x++)
{
fwrite(array, sizeof(RGBTRIPLE), obi.biWidth, outptr);
for(int k = 0; k < out_padding; k++)
fputc(0x00, outptr);
}
fseek(inptr, padding, SEEK_CUR);
}
free(array);
您还应该更改BITMAPFILEHEADER
的{{1}}的值:
bfSize