使用 C 复制从 tif 文件生成的 8 位灰度 bmp 文件
Copy an 8 bit greyscale bmp file generated from a tif file using C
以下代码是我试图从位图文件中提取图像特征的程序的一部分。我需要提取有关图像的信息(仅宽度和高度)并复制它。这些图像的分辨率为 2048X 2168,8 位灰度。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMELENGTH 301
long getImageInfo(FILE* Finput, long offset, int nchars){
unsigned char *ptrChar;
unsigned char dummy;
long value=0L;
int i;
dummy='0';
ptrChar=&dummy;
fseek(Finput,offset,SEEK_SET);
for (i=1; i<=nchars; i++){
fread(ptrChar,sizeof(char),1,Finput);
value += ((long) ((*ptrChar)*pow(256,(i-1))));
}
return(value);
}
void copyImageInfo(FILE* Finput, FILE* Foutput){
unsigned char *ptrChar;
unsigned char dummy;
long offset;
int i;
dummy='0';
ptrChar=&dummy;
int byte_size = ((int) getImageInfo(Finput,34,4));
/* copying header: signature, image width & height, number bit/pixel, image size, number of colors */
offset=0L;
fseek(Finput,offset,SEEK_SET);
fseek(Foutput,offset,SEEK_SET);
for (i=0; i<=54; i++){
fread(ptrChar,sizeof(char),1,Finput);
fwrite(ptrChar,sizeof(char),1,Foutput);
}
/* copying pixel data */
/* This part of the code may not be complete */
offset=54L;
fseek(Finput,offset,SEEK_SET);
fseek(Foutput,offset,SEEK_SET);
for (i=0; i<=byte_size; i++){
fread(ptrChar,sizeof(char),1,Finput);
fwrite(ptrChar,sizeof(char),1,Foutput);
}
}
int main(int argc, char *argv[]){
FILE* Finput;
FILE* Foutput;
char input_name[NAMELENGTH];
char output_name[NAMELENGTH];
char job_name[NAMELENGTH];
char history_name[NAMELENGTH];
unsigned char *ptrChar;
int pix_width,pix_height;
int bit_pixel,byte_size,ncolors;
strcpy(input_name,argv[1]); /* first argument contains path to the image file */
strcpy(job_name, argv[1]);
job_name[strlen(job_name)-4]='[=10=]';
sprintf(history_name,"%s%s",job_name,"_hist.txt"); /* history file stores image header information */
if( (Finput=fopen(input_name,"r"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for reading\n",input_name);
exit(-1);
}
else{
fseek(Finput,0L,SEEK_END);
if (getImageInfo(Finput,0,2)!=19778) fprintf(stdout,"\n WARNING: wrong BMP signature!\n");
pix_width = ((int) getImageInfo(Finput,18,4));
pix_height = ((int) getImageInfo(Finput,22,4));
bit_pixel = ((int) getImageInfo(Finput,28,2));
byte_size = ((int) getImageInfo(Finput,34,4));
ncolors = ((int) getImageInfo(Finput,46,4));
fprintf(stdout,"\n width pixels=%d",pix_width);
fprintf(stdout,"\n height pixels=%d",pix_height);
fprintf(stdout,"\n bits per pixel=%d",bit_pixel);
fprintf(stdout,"\n image data size=%d",byte_size);
fprintf(stdout,"\n number colors=%d\n",ncolors);
/* history file */
if ( (Foutput=fopen(history_name,"a"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for appending\n",history_name);
exit(-1);
}
else{
fprintf(Foutput,"Path to Image: %s ",input_name);
fprintf(Foutput,"\n\t 18 - biWidth - width pixels=%d",pix_width);
fprintf(Foutput,"\n\t 22 - biHeight - height pixels=%d",pix_height);
fprintf(Foutput,"\n\t 28 - biBitCount - bits per pixel=%d",bit_pixel);
fprintf(Foutput,"\n\t 34 - biSizeImage - image data size=%d",byte_size);
fprintf(Foutput,"\n\t 46 - biClrUsed - number colors=%d\n",ncolors);
fclose(Foutput);
}
sprintf(output_name,"%s%s",job_name,"_copy.bmp");
if ( (Foutput=fopen(output_name,"wb"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for writing\n",output_name);
exit(-1);
}
else{
copyImageInfo(Finput,Foutput);
fclose(Foutput);
}
}
fclose(Finput);
}
不幸的是,我的原始图像文件是 tif 格式。所以当我转换它们时,我无法保留一些 header 文件信息。一个在线工具可以让我保留 bits-per-pixel(8 位),但随后我丢失了 biSizeImage(变为 0)。另一个转换工具正确地得到了我的大小,但图像比特率变为 24。(link1, link2)
我的原始 tif 图片示例 (temporary_link1) and the corresponding BMP image (temporary_link2)
当我 运行 以上时,我能够正确复制 header 信息但不能复制像素数据。如果可以使用其他方法复制(例如通过比较 EOF),这可能是一个不错的选择。我不确定计算填充和书写方向。
从将 tif 格式正确转换为我所需的 bmp 格式开始,我们将不胜感激。显然我是图像格式化和压缩的新手。
输出:
width pixels=2048
height pixels=2168
bits per pixel=8
image data size=0
number colors=0
getImageInfo
不正确。整数值应该以 little-endian 格式保存。应该这样读:
unsigned int getImageInfo(FILE *fin, long offset, int nchars)
{
fseek(fin, offset, SEEK_SET);
unsigned int value = 0;
for(int i = 0; i < nchars; i++)
{
unsigned char dummy = '0';
fread((char*)&dummy, sizeof(char), 1, fin);
value += dummy << (8 * i);
}
return value;
}
byte_size
不保证设置为正确的值。这应该大致等于 width * height * bit_pixel
。使用这个公式。
byte_size = ((pix_width * bit_pixel + 31) / 32) * 4 * pix_height;
此外,8 位图像包含大小为 1024 的颜色 table。此 table 紧接在 54 字节 header 之后和像素数据之前。阅读如下:
unsigned int getImageInfo(FILE *fin, long offset, int nchars)
{
fseek(fin, offset, SEEK_SET);
unsigned int value = 0;
for(int i = 0; i < nchars; i++)
{
unsigned char dummy = '0';
fread((char*)&dummy, sizeof(char), 1, fin);
value += dummy << (8 * i);
}
return value;
}
void copyImageInfo(FILE* Finput, FILE* Foutput)
{
int w = getImageInfo(Finput, 18, 4);
int h = getImageInfo(Finput, 22, 4);
int bit_pixel = getImageInfo(Finput, 28, 2);
int byte_size = ((w * bit_pixel + 31) / 32) * 4 * h;
int ncolors = getImageInfo(Finput, 46, 4);
fprintf(stdout, "\n width pixels=%d", w);
fprintf(stdout, "\n height pixels=%d", h);
fprintf(stdout, "\n bits per pixel=%d", bit_pixel);
fprintf(stdout, "\n image data size=%d", byte_size);
fprintf(stdout, "\n number colors=%d\n", ncolors);
char header[54]; //bitmap header
char *pixels = malloc(byte_size); //pixel data
fseek(Finput, 0, SEEK_SET);
fseek(Foutput, 0, SEEK_SET);
fread(header, sizeof(header), 1, Finput);
fwrite(header, sizeof(header), 1, Foutput);
if(bit_pixel <= 8)
{
//color table
int colors_size = 4 * (1 << bit_pixel);
char *colors = malloc(colors_size);
fread(colors, 1, colors_size, Finput);
fwrite(colors, 1, colors_size, Foutput);
free(colors);
}
fread(pixels, 1, byte_size, Finput);
fwrite(pixels, 1, byte_size, Foutput);
free(pixels);
}
int main(void)
{
char input_name[] = "input.bmp";
char output_name[] = "output.bmp";
FILE *Finput = fopen(input_name, "rb");
if(!Finput)
{
fprintf(stderr, "\n ERROR: file %s\n", input_name);
exit(-1);
}
FILE *Foutput = fopen(output_name, "wb");
if(!Foutput)
{
fprintf(stderr, "\n ERROR: file %s\n", input_name);
fclose(Finput);
exit(-1);
}
if(getImageInfo(Finput, 0, 2) != 19778)
fprintf(stdout, "\n WARNING: wrong BMP signature!\n");
else
copyImageInfo(Finput, Foutput);
fclose(Foutput);
fclose(Finput);
return 0;
}
以下代码是我试图从位图文件中提取图像特征的程序的一部分。我需要提取有关图像的信息(仅宽度和高度)并复制它。这些图像的分辨率为 2048X 2168,8 位灰度。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMELENGTH 301
long getImageInfo(FILE* Finput, long offset, int nchars){
unsigned char *ptrChar;
unsigned char dummy;
long value=0L;
int i;
dummy='0';
ptrChar=&dummy;
fseek(Finput,offset,SEEK_SET);
for (i=1; i<=nchars; i++){
fread(ptrChar,sizeof(char),1,Finput);
value += ((long) ((*ptrChar)*pow(256,(i-1))));
}
return(value);
}
void copyImageInfo(FILE* Finput, FILE* Foutput){
unsigned char *ptrChar;
unsigned char dummy;
long offset;
int i;
dummy='0';
ptrChar=&dummy;
int byte_size = ((int) getImageInfo(Finput,34,4));
/* copying header: signature, image width & height, number bit/pixel, image size, number of colors */
offset=0L;
fseek(Finput,offset,SEEK_SET);
fseek(Foutput,offset,SEEK_SET);
for (i=0; i<=54; i++){
fread(ptrChar,sizeof(char),1,Finput);
fwrite(ptrChar,sizeof(char),1,Foutput);
}
/* copying pixel data */
/* This part of the code may not be complete */
offset=54L;
fseek(Finput,offset,SEEK_SET);
fseek(Foutput,offset,SEEK_SET);
for (i=0; i<=byte_size; i++){
fread(ptrChar,sizeof(char),1,Finput);
fwrite(ptrChar,sizeof(char),1,Foutput);
}
}
int main(int argc, char *argv[]){
FILE* Finput;
FILE* Foutput;
char input_name[NAMELENGTH];
char output_name[NAMELENGTH];
char job_name[NAMELENGTH];
char history_name[NAMELENGTH];
unsigned char *ptrChar;
int pix_width,pix_height;
int bit_pixel,byte_size,ncolors;
strcpy(input_name,argv[1]); /* first argument contains path to the image file */
strcpy(job_name, argv[1]);
job_name[strlen(job_name)-4]='[=10=]';
sprintf(history_name,"%s%s",job_name,"_hist.txt"); /* history file stores image header information */
if( (Finput=fopen(input_name,"r"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for reading\n",input_name);
exit(-1);
}
else{
fseek(Finput,0L,SEEK_END);
if (getImageInfo(Finput,0,2)!=19778) fprintf(stdout,"\n WARNING: wrong BMP signature!\n");
pix_width = ((int) getImageInfo(Finput,18,4));
pix_height = ((int) getImageInfo(Finput,22,4));
bit_pixel = ((int) getImageInfo(Finput,28,2));
byte_size = ((int) getImageInfo(Finput,34,4));
ncolors = ((int) getImageInfo(Finput,46,4));
fprintf(stdout,"\n width pixels=%d",pix_width);
fprintf(stdout,"\n height pixels=%d",pix_height);
fprintf(stdout,"\n bits per pixel=%d",bit_pixel);
fprintf(stdout,"\n image data size=%d",byte_size);
fprintf(stdout,"\n number colors=%d\n",ncolors);
/* history file */
if ( (Foutput=fopen(history_name,"a"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for appending\n",history_name);
exit(-1);
}
else{
fprintf(Foutput,"Path to Image: %s ",input_name);
fprintf(Foutput,"\n\t 18 - biWidth - width pixels=%d",pix_width);
fprintf(Foutput,"\n\t 22 - biHeight - height pixels=%d",pix_height);
fprintf(Foutput,"\n\t 28 - biBitCount - bits per pixel=%d",bit_pixel);
fprintf(Foutput,"\n\t 34 - biSizeImage - image data size=%d",byte_size);
fprintf(Foutput,"\n\t 46 - biClrUsed - number colors=%d\n",ncolors);
fclose(Foutput);
}
sprintf(output_name,"%s%s",job_name,"_copy.bmp");
if ( (Foutput=fopen(output_name,"wb"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for writing\n",output_name);
exit(-1);
}
else{
copyImageInfo(Finput,Foutput);
fclose(Foutput);
}
}
fclose(Finput);
}
不幸的是,我的原始图像文件是 tif 格式。所以当我转换它们时,我无法保留一些 header 文件信息。一个在线工具可以让我保留 bits-per-pixel(8 位),但随后我丢失了 biSizeImage(变为 0)。另一个转换工具正确地得到了我的大小,但图像比特率变为 24。(link1, link2)
我的原始 tif 图片示例 (temporary_link1) and the corresponding BMP image (temporary_link2)
当我 运行 以上时,我能够正确复制 header 信息但不能复制像素数据。如果可以使用其他方法复制(例如通过比较 EOF),这可能是一个不错的选择。我不确定计算填充和书写方向。
从将 tif 格式正确转换为我所需的 bmp 格式开始,我们将不胜感激。显然我是图像格式化和压缩的新手。
输出:
width pixels=2048
height pixels=2168
bits per pixel=8
image data size=0
number colors=0
getImageInfo
不正确。整数值应该以 little-endian 格式保存。应该这样读:
unsigned int getImageInfo(FILE *fin, long offset, int nchars)
{
fseek(fin, offset, SEEK_SET);
unsigned int value = 0;
for(int i = 0; i < nchars; i++)
{
unsigned char dummy = '0';
fread((char*)&dummy, sizeof(char), 1, fin);
value += dummy << (8 * i);
}
return value;
}
byte_size
不保证设置为正确的值。这应该大致等于 width * height * bit_pixel
。使用这个公式。
byte_size = ((pix_width * bit_pixel + 31) / 32) * 4 * pix_height;
此外,8 位图像包含大小为 1024 的颜色 table。此 table 紧接在 54 字节 header 之后和像素数据之前。阅读如下:
unsigned int getImageInfo(FILE *fin, long offset, int nchars)
{
fseek(fin, offset, SEEK_SET);
unsigned int value = 0;
for(int i = 0; i < nchars; i++)
{
unsigned char dummy = '0';
fread((char*)&dummy, sizeof(char), 1, fin);
value += dummy << (8 * i);
}
return value;
}
void copyImageInfo(FILE* Finput, FILE* Foutput)
{
int w = getImageInfo(Finput, 18, 4);
int h = getImageInfo(Finput, 22, 4);
int bit_pixel = getImageInfo(Finput, 28, 2);
int byte_size = ((w * bit_pixel + 31) / 32) * 4 * h;
int ncolors = getImageInfo(Finput, 46, 4);
fprintf(stdout, "\n width pixels=%d", w);
fprintf(stdout, "\n height pixels=%d", h);
fprintf(stdout, "\n bits per pixel=%d", bit_pixel);
fprintf(stdout, "\n image data size=%d", byte_size);
fprintf(stdout, "\n number colors=%d\n", ncolors);
char header[54]; //bitmap header
char *pixels = malloc(byte_size); //pixel data
fseek(Finput, 0, SEEK_SET);
fseek(Foutput, 0, SEEK_SET);
fread(header, sizeof(header), 1, Finput);
fwrite(header, sizeof(header), 1, Foutput);
if(bit_pixel <= 8)
{
//color table
int colors_size = 4 * (1 << bit_pixel);
char *colors = malloc(colors_size);
fread(colors, 1, colors_size, Finput);
fwrite(colors, 1, colors_size, Foutput);
free(colors);
}
fread(pixels, 1, byte_size, Finput);
fwrite(pixels, 1, byte_size, Foutput);
free(pixels);
}
int main(void)
{
char input_name[] = "input.bmp";
char output_name[] = "output.bmp";
FILE *Finput = fopen(input_name, "rb");
if(!Finput)
{
fprintf(stderr, "\n ERROR: file %s\n", input_name);
exit(-1);
}
FILE *Foutput = fopen(output_name, "wb");
if(!Foutput)
{
fprintf(stderr, "\n ERROR: file %s\n", input_name);
fclose(Finput);
exit(-1);
}
if(getImageInfo(Finput, 0, 2) != 19778)
fprintf(stdout, "\n WARNING: wrong BMP signature!\n");
else
copyImageInfo(Finput, Foutput);
fclose(Foutput);
fclose(Finput);
return 0;
}