I'm trying to read a BMP file and save it in a buffer with 2 dimension in order to rotate it in a right angle. However, the final file is not correct and cannnot be displayed. What is the problem in the following code?
#include <fstream.h>
#include <iostream.h>
int main() {
long int width=686;
long int height=800 ;
/* open file */
FILE * bitmap_file= fopen("filename.bmp", "rb");
if(!bitmap_file) {
printf("Could not find file.\n");
fclose(bitmap_file);
return 0;
}
printf("File opened.\n");
typedef struct buffer1
{
int red;
int green;
int blue;
} buffer1;
static buffer1 buffer_bitmap1[686][800];
fseek(bitmap_file, 0, SEEK_SET);
int count=0;
for(int i = 0; i <8; ++i){
for(int j = 0; j <6; ++j){
fread(&buffer_bitmap1[j][i].red , 1, 1, bitmap_file); /*for rotate bmp exchange the width with height in matrix.*/
fread(&buffer_bitmap1[j][i].green, 1, 1, bitmap_file);
fread(&buffer_bitmap1[j][i].blue, 1, 1, bitmap_file);
count=count+8;
fseek(bitmap_file,count, SEEK_CUR); /*move pointer*/
}
}
fclose(bitmap_file);
FILE *bitmap_file1= fopen("filename.bmp", "a");
count=0;
fseek(bitmap_file, 0, SEEK_SET);
char * a ="a";
for(int i = 0; i <6; ++i){
for(int j = 0; j <8; ++j) {
fwrite(&buffer_bitmap1[i][j],1,1,bitmap_file1);
fwrite(&buffer_bitmap1[i][j].blue,1,1,bitmap_file1);
fwrite(&buffer_bitmap1[i][j].green,1,1,bitmap_file1);
count=count+8;
fseek(bitmap_file, 8, SEEK_CUR); /*move pointer*/
}
}
fclose(bitmap_file);
return 0;
}
At least, You can not simply read a BMP file from the beginning as it has a BMP Header.
The first of all you need to read a header int order to get the BMP parameters (image size, data offset, bits per pixel etc.)
The second, in order to rotate the image and to be able to see the result, you also will need to modify the header.
Related
I'm looking for a way to convert a BMP image of 256 grey levels to a 1-bit BMP image. The conversion rule is that the bit should be 0 for grey levels from 0 - 127, and 1 from 128 - 255. So far I have attempted to make a program in C. The problem is even though I changed the bits per pixel in the information header to 1 BBP, the output is a black image (I'm using Lena as the input file btw) as if the colour depth is still 8-bit (while in Properties it says 1-bit).
I tried to open the BMP file in a hex editor and saw that the pixel data had been changed to 0 and 1 as expected and the headers of the input and output files were the same except the colour depth. Am I missing anything? What changes do I need to make for the image to show what is expected?
Here is my program:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#pragma pack(1) //avoid padding in a struct
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
typedef struct
{
WORD Signature;
DWORD fSize;
WORD fReserved_1;
WORD fReserved_2;
DWORD fOffset;
} BITMAP_HEADER;
typedef struct
{
DWORD Size;
LONG Width;
LONG Height;
WORD Planes;
WORD BitsPerPixel;
DWORD Compression;
DWORD imgSize;
LONG ResX;
LONG ResY;
DWORD Color;
DWORD ImpColor;
} INFO_HEADER;
typedef struct
{
BYTE rgbtBlue; //since I'm only dealing with 8-bit colour depth
//so only one value is needed I guess?
// BYTE rgbtGreen;
// BYTE rgbtRed;
} RGBTRIPLE;
void BinaryConvert(DWORD height, DWORD width, RGBTRIPLE img[height][width]);
int main()
{
FILE* fp, *cp;
fp = fopen("Resources/test.bmp", "rb"); //bmp is binary file, therefore use "rb" permission
cp = fopen("Resources/output.bmp", "wb");
BITMAP_HEADER fHeader;
INFO_HEADER fInfo;
//read headers
fread(&fHeader, sizeof(BITMAP_HEADER), 1, fp);
fread(&fInfo, sizeof(INFO_HEADER), 1, fp);
int width = fInfo.Width;
int height = fInfo.Height;
int padding = (4 - (width * sizeof(RGBTRIPLE)) % 4) % 4;
RGBTRIPLE (*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));
//read pixel data
for (int i = 0; i < height; i++)
{
fread(image[i], sizeof(RGBTRIPLE), width, fp);
fseek(fp, padding, SEEK_CUR); //skip over padding
}
//coonvert grey levels into 0 and 1
BinaryConvert(height, width, image);
//modify file header
fInfo.noBitsPerPixel = 1;
//write headers into output file
fseek(cp, 0, SEEK_SET);
fwrite(&fHeader, sizeof(BITMAP_HEADER), 1, cp);
fwrite(&fInfo, sizeof(INFO_HEADER), 1, cp);
//write pixel data into output file
for (int i = 0; i < height; i++)
{
fwrite(image[i], sizeof(RGBTRIPLE), width, cp);
for (int k = 0; k < padding; k++)
{
fputc(0x00, cp);
}
}
fclose(cp);
fclose(fp);
}
void BinaryConvert(DWORD height, DWORD width, RGBTRIPLE img[height][width])
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (img[i][j].rgbtBlue <= 127 && img[i][j].rgbtBlue >=0)
{
img[i][j].rgbtBlue = 0;
}
else if (img[i][j].rgbtBlue <= 255 && img[i][j].rgbtBlue >= 128)
img[i][j].rgbtBlue = 1;
}
}
}
Input file (lena.bmp). (257 KB)
Result from program (257 KB)
You need to use 255 instead of 1. That is the color for white
I'm trying to write a program to blur an image, but first of am trying to see if I can even reproduce the image, pixel by pixel, in another file. I've allocated a 2-dimensional char array to hold the value of each pixel in the image.
Note: The image is in grayscale, and it is of type .raw
However, whenever I attempt to read the pixels into my 2D array, my program crashes. I feel like it has something to do with me not looping through the dimensions of the image correctly, but I'm not sure.
Code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fin, *fout;
char path_in[64], path_out[64], **rev, px;
int width, height, read, i, j;
printf("Input file name: ");
scanf("%s", path_in);
printf("Output file name: ");
scanf("%s", path_out);
printf("Width of image (in pixels): ");
scanf("%d", &width);
printf("Height of image (in pixels): ");
scanf("%d", &height);
fin = fopen(path_in, "rb");
fout = fopen(path_out, "wb");
row = 0;
rev = (char **)malloc(height * sizeof(char));
for(i = 0; i < width; i++)
rev[i] = (char *)malloc(width * sizeof(char));
for(i = 0; i < height; i++)
{
for(j = 0; j < width; j++)
{
read = fread(&px, sizeof(char), 1, fin);
rev[i][j] = px;
}
}
fclose(fout);
fclose(fin);
return 0;
}
My program is pretty narrow, as it only accepts grayscale .raw image type.
Change these lines as this:
row = 0;
rev = malloc(height * sizeof *rev);
for(i = 0; i < width; i++)
rev[i] = malloc(width * sizeof **rev);
You were allocating memory for height chars, not for height pointers to chars, as you intended.
Also, don't cast the result of malloc if developing with C
This line: rev = (char **)malloc(height * sizeof(char));
should be rev = (char **)malloc(height * sizeof(char*));
I think is better to use contiguous memory to manage the image!
Using char ** in the way as in your code you don't have a block of memory that contains the whole image, but a lot of not contiguous vectors each one containing a line!
The following code reads the image in a contiguous block of memory using only one malloc:
char * rev;
/* HERE your code to insert width and height */
rev = malloc(height * width *sizeof(char));
if (rev==NULL) {
/* Ops! The buffer is not allocated!!! */
}
/* HERE you open the file and so on */
for(i = 0; i < height; i++)
{
for(j = 0; j < width; j++)
{
read = fread(&rev[i*width+j], sizeof(char), 1, fin);
if (read!=1) { /* 1 is the number of bytes fread reads if ok */
/* Ops, there's a problem! The fread didn't read! */
}
}
}
Using char * you might load all the image with one fread, thus avoiding the two for loops :)
fread(rev,witdh,height,fin);
In this way you may point each single pixel using:
rev[y*width+x];
im trying to copy pixel data from a bmp file to a text file in c (white will be 0, every other color will be 1), but for some reason the text file comes out trippled (three areas of 1) and in the wrong direction, i cant figure out why. anyway this is my scipt:
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#pragma pack(1)
typedef struct {
unsigned char type1; /* Magic identifier */
unsigned char type2;
unsigned int size; /* File size in bytes */
unsigned int reserved;
unsigned long offset; /* Offset to image data, bytes */
} Header;
#pragma pack(2)
typedef struct {
unsigned int size; /* Header size in bytes */
int width,height; /* Width and height of image */
unsigned short int planes; /* Number of colour planes */
unsigned short int bits; /* Bits per pixel */
unsigned int compression; /* Compression type */
unsigned int imagesize; /* Image size in bytes */
unsigned int xresolution,yresolution; /* Pixels per meter */
unsigned int ncolours; /* Number of colours */
unsigned int importantcolours; /* Important colours */
} Infoheader;
typedef struct
{ unsigned char Red, Green, Blue,Reserved;
} Pixel;
void main()
{
int n;
FILE *fin;
Header *fileheader;
Infoheader *information;
Pixel *ppixel,**pImage;
fin=fopen("TEST_web.bmp","rb");
if (fin==NULL)
{
printf("Error reading image\n");
exit(1);
}
int i,j;
fileheader=(Header *)malloc(sizeof(Header));
information=(Infoheader *)malloc(sizeof(Infoheader));
ppixel=(Pixel *)malloc(sizeof(Pixel));
fread(fileheader,sizeof(Header),1,fin);
if ((*fileheader).type1!='B'&&(*fileheader).type2!='M')
{
printf("Not a bmp file\n");
exit(1);
}
n=fread(information, sizeof(Infoheader),1,fin);
if(n!=1)
{
printf("Error reading image information\n");
exit(1);
}
pImage = (Pixel **)malloc(sizeof(Pixel *) * information->height);
for(i = 0; i < information->height; i++)
{ pImage[i] = (Pixel *)malloc(sizeof(Pixel) * information->width);
}
fseek(fin,fileheader->offset,SEEK_SET);
for(i = 0; i < information->width; i++)
{ for(j = 0; j < information->height; j++)
{ fread(&(*ppixel).Red, sizeof(unsigned char), 1, fin);
fread(&(*ppixel).Green, sizeof(unsigned char), 1, fin);
fread(&(*ppixel).Blue, sizeof(unsigned char), 1, fin);
pImage[i][j] = *ppixel;
}
}
char data[information->width][information->height];
for(i = 0; i <information->width; i++)
{ for(j= 0; j<information->height; j++)
{
if((pImage[i][j]).Red==255&&(pImage[i][j]).Green==255&& Image[i][j]).Blue==255)
data[i][j]='0';
else
data[i][j]='1';
}
}
FILE *fout;
fout=fopen("text.txt","wt");
for(i = 0; i < information->width; i++)
{ for(j = 0; j < information->width ; j++)
{ fputc(data[i][j],fout);
}
fputs("\n",fout);
}
free(fileheader);
free(information);
free(ppixel);
for(i = 0; i < information->height; i++)
free(pImage[i]);
fclose(fin);
}
Im working for now with this picture
Instead of this:
for(i = 0; i < information->width; i++)
{
for(j = 0; j < information->height; j++)
use something like this:
for(y = 0; y < information->height; y++)
{
for(x = 0; x < information->width; x++)
(and of course do the same when you are scanning the bitmap.)
I'm trying to store the pixel values of a BMP file in a 2D dynamically allocated array of structs but it keeps giving a segmentation fault. Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
typedef struct PIXEL{
unsigned char Red, Green, Blue;
}*pixel;
int main (int argc, char *argv[])
{
//variable declarations and open the file
FILE* fin = fopen(argv[1], "rb");
if (fin == NULL){
printf("Error opening file.\n");
exit(0);
}
unsigned char info[54];
int width, height, i, j;
fread(info, sizeof(unsigned char), 54, fin); //read the header
width = *(int*)&info[18];
height = *(int*)&info[22];
pixel **image = (pixel **) malloc(sizeof(pixel *) * width); //reserve enough space for RGB for each pixel
for (i = 0; i < width; i++){
image[i] = (pixel *) malloc(sizeof(pixel) * height);
}
for (i = 0; i < width; i++){
for (j = 0; j < height; j++){
image[i][j]->Blue = getc(fin); //put the blue value of the pixel
image[i][j]->Green = getc(fin); //green value
image[i][j]->Red = getc(fin); //red value
printf("Pixel %d: [%d, %d, %d]\n", (i+1)*(j+1), image[i][j]->Blue, image[i][j]->Green, image[i][j]->Blue);
}
}
fclose(fin);
return 0;
}
You did not check for valid width and height values from the header. If for any reason they are huge (for instance if the file read failed) this will crash.
Also, %d in printf expects an int. You should cast your unsigned chars to int or it may crash.
I am trying to understand images some more, and I'm having a great deal of trouble. From using matlab, I have experience in using imread('test.tif'), and getting a beautiful matrix of rows vs. columns, where you have the intensity of each pixel as an integer. So, a 720 x 250 image will give a 720 x 250 matrix, where each cell contains the intensity of the pixel, on a scale from 0-255 (depending on the data type). So, 0 was black, 255 was white.
It was so simple and made so much sense. Now I am attempting to use libtiff, and I am really struggling. I want to do the same thing--access those pixels, and I just can't get it.
I have the following code:
int main(int argc, char *argv[]){
TIFF* tif = TIFFOpen( argv[1], "r");
FILE *fp = fopen("test2.txt", "w+");
if (tif) {
int * buf;
tstrip_t strip;
uint32* bc;
uint32 stripsize;
TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
stripsize = bc[0];
buf = _TIFFmalloc(stripsize);
for(strip = 0; strip < TIFFNumberOfStrips(tif); strip++ ) {
if( bc[strip] > stripsize) {
buf = _TIFFrealloc(buf, bc[strip]);
stripsize = bc[strip];
}
TIFFReadRawStrip(tif, strip, buf, bc[strip]);
}
int i;
for (i=0; i<stripsize; i++) {
if ( i % 960 ==0 )
fprintf(fp, "\n");
fprintf(fp,"%d ", buf[i]);
}
_TIFFfree(buf);
TIFFClose(tif);
}
exit(0);
}
But I get completely meaningless results--just completely wacked out numbers. Nothing like the numbers I see when I load the image in matlab.
How can I simply access the pixel values, and look at them?
Thanks so much.
I think you should read Using The TIFF Library article. It contains enough information to get started with libtiff.
Here is some code to read image scanlines and print values of each sample.
main()
{
TIFF* tif = TIFFOpen("myfile.tif", "r");
if (tif) {
uint32 imagelength;
tsize_t scanline;
tdata_t buf;
uint32 row;
uint32 col;
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
scanline = TIFFScanlineSize(tif);
buf = _TIFFmalloc(scanline);
for (row = 0; row < imagelength; row++)
{
TIFFReadScanline(tif, buf, row);
for (col = 0; col < scanline; col++)
printf("%d ", buf[col]);
printf("\n");
}
_TIFFfree(buf);
TIFFClose(tif);
}
}
Regarding this article, I think it'll be better to use TIFFRGBAImage approach, because as it turned out TIFF file could be one of different formats: tiled, scanline-based and strip-oriented. Here's an example from the same article.
TIFF* tif = TIFFOpen(argv[1], "r");
if (tif) {
uint32 w, h;
size_t npixels;
uint32* raster;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;
raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != NULL) {
if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {
...process raster data...
}
_TIFFfree(raster);
}
TIFFClose(tif);
}
raster is a uint32 array (maximum value= 0xffffffff)
but you are trying to read a 16-bit array (maximum value 0xffff).
you will run into 32bit to 16bit conversion problems.
Reading the scanline method is the better way to do it.
This way you can convert the void* buf to uint16* and access the pixel values.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <inttypes.h>
#include "tiffio.h"
using namespace std;
void printArray(uint16 * array, uint16 width);
int main()
{
TIFF* tif = TIFFOpen("16bit_grayscale_image.tif", "r");
if (tif) {
uint32 imagelength,height;
tdata_t buf;
uint32 row;
uint32 config;
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
buf = _TIFFmalloc(TIFFScanlineSize(tif));
uint16 s, nsamples;
uint16* data;
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &nsamples);
for (s = 0; s < nsamples; s++)
{
for (row = 0; row < imagelength; row++)
{
TIFFReadScanline(tif, buf, row, s);
data=(uint16*)buf;
printArray(data,imagelength);
}
// printArray(data,imagelength,height);
}
_TIFFfree(buf);
TIFFClose(tif);
}
exit(0);
}
void printArray(uint16 * array, uint16 width)
{
uint32 i;
for (i=0;i<width;i++)
{
printf("%u ", array[i]);
}
printf("\n");
}