Storing pixel values of a BMP file - c

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.

Related

Memory Allocation of 3D Array and Use of fread in C results

// A part of Code
int dim1=height;
int dim2=width;
int dim3=3;
int k;
unsigned char *** image = (unsigned char ***)malloc(dim1*dim2*3);
for (i = 0; i< dim1; i++) {
image[i] = (unsigned char **)malloc(dim2*sizeof(unsigned char *));
for (j = 0; j < dim2; j++) {
image[i][j] = (unsigned char *)malloc(dim3*sizeof(unsigned char ));
}
}
// B part of Code
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
fread(&image[i][j][0],sizeof(unsigned char),1,fp);
fread(&image[i][j][1],sizeof(unsigned char),1,fp);
fread(&image[i][j][2],sizeof(unsigned char),1,fp);
}
}
As you can see from above I am trying to declare a 3d array that will contain the pixel information of a bmp image. The fp pointer is to a binary file that the data is contained there.
My question is how is it possible when I try to fread using dynamic memory allocation to get wrong results in image table (meaning a blank image is printed even though the rest of my code that i dont include here is correct).
On the other hand when i remove the A part of the Code and replace it with "unsigned char image[height][width][3]" it works.
So what am i doing wrong in the memory allocation or in the use of fread? Because obviously the problem is there.
In order to make it easier lets assume that the size is 252x252x3.
typedef struct
{
unsigned char R;
unsigned char G;
unsigned char B;
}RGB;
void *allocateReadImage(size_t width, size_t height, FILE *fi)
{
RGB (*picture)[width] = malloc(sizeof(*picture) * height);
if(picture && fi)
{
if(fread(picture, sizeof(*picture), height, fi) != height)
{
free(picture);
picture = NULL;
}
}
return picture;
}
usage:
RGB *mypicture = allocateReadImage(1600, 1200, inputfile);
if(!mypicture) { /*some error handling*/ }

Reproducing an Image using C

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];

Trying to copy data from bmp file to a text file

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.)

Read BMP file and rotate

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.

How can I simply load a greyscale tiff in libtiff and get an array of pixel intensities?

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

Resources