I'm trying to read in a bitmap image from one file and write it to another just to check that the contents were transferred. However when I run my code, the image doesn't get created into the output file. Instead, whenever I click on the new file it tells me that the file couldn't be opened. Here is what my header file looks like:
//////////////////////////////////////////////////////////////////////
// RGB.h header file for bitmap BMP definitions
// adapted from <WinGDI.h>
///To get DIB header struct. winGDI.h is huge overkill for the needs here
#ifndef RGBH //don't doubly include this stuff, set a flag when first including
#define RGBH
/* structures for defining DIBs //from WinGDI.h */
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned long int LONG;
typedef unsigned char BYTE;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef PBITMAPFILEHEADER pbfh;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; /* used to get to color table */
DWORD biWidth;
DWORD biHeight;
WORD biPlanes;
WORD biBitCount;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
typedef BITMAPINFOHEADER pbih;
typedef struct tagRGBTRIPLE { //from WinGDI.h
BYTE b; //rgbtBlue;
BYTE g; //rgbtGreen;
BYTE r; //rgbtRed;
} pix, *ppix;
#define BYTES_PER_PIX sizeof(pix)
const pix RED = {0,0,255};
const pix GREEN = {0,255,0};
const pix BLUE = {255,0,0};
#endif
////////////////////// End of RGB.h header file ////////////////////////////////
And here is the code I have written:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "RGB.h" //header file for Bitmap
BITMAPFILEHEADER *hp; //var pointer to the header file for bitmap
BITMAPINFOHEADER *p; //var pointer to the info file for bitmap
#define SIZE 100
int main(void)
{
FILE *bp, *op; //var for two file streams
char pix[SIZE]; //var for char name of input file
char out[SIZE]; //var for char name of output file
int n; //var to hold different values through out the program
unsigned char *bitmapImage; //var to store image data
printf("Enter bitmap filename: "); //prompts user to enter filename
scanf("%s", pix); //collects filename from user
//open filename in read binary mode
if((bp = fopen(pix, "rb")) == NULL) if ((bp = fopen(pix, "rb")) == NULL)
{
printf("Can't open file %s", bp); //prints if file path wasn't valid
getchar();
exit (1);
}
//malloc memory for file header
hp = (tagBITMAPFILEHEADER*)malloc(sizeof(tagBITMAPFILEHEADER));
//reads the bitmap file header
n = fread(pix, 1,SIZE, bp);
//read bitmap info header
fread(bp, sizeof(tagBITMAPINFOHEADER), 1, bp);
//allocate enough memory for the bitmap image data
p = (tagBITMAPINFOHEADER*) (pix+14);
bitmapImage = (unsigned char*) malloc(p->biSize);
//verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(bp);
puts("Memory allocation not allowed");
return NULL;
}
puts("Input File Statistics: \n");
printf("File size: %ld bytes", p->biSize); //prints out total file size
printf("\nWidth x Height = %ld x %ld", p->biWidth, p->biHeight); //prints out dimensions of image
printf("\nBits/pixel = %u\n", p->biBitCount);
printf("\nEnter an output filename for bitmap: "); //prompts user for output file name
scanf("%s", out); //collects pathway from user
//open output file
if((op = fopen(out, "wb")) == NULL)
{
puts("Invalid file");
fclose(op);
exit (2);
}
fclose(op);
return 0;
}
Any advice would be greatly appreciated! Thanks! O. Helm
Sometimes the solution is too easy to see.
Are you using the same "counter" in both for loops? I think that will not work.
Also, in your fread and fwrite, you are probably reading to and writing from the same place. You need to update the pointer of where you are reading to.
The comment for your first fread says "reads the bitmap file header". I am not sure it is doing that correctly.
Check your second fread. It might have a fatal problem. Are you sure you want to read into bp? Perhaps it will help you if you use more meaningful names for your variables.
Do you need to write BITMAPFILEHEADER and BITMAPINFOHEADER out? Check to ensure you are doing that correctly.
Since this is a class assignment, obviously it is best to not give precise help. I hope this helps enough to make progress. If there is anything more than I hope you can find them by looking closely.
Related
I have multiple tiff images stored inside a zip file and would like to read their pixel values in c. I am very new to c so please forgive the dodgy code. I have got to the point where I have a char * with the contents of the tiff file but can't seem to work out how to now process that with libtiff (or something similar). libtiff seems to require that I pass TIFFOpen a filename to open. I could write the tiff to a temporary file but it feels like there must be a more efficient way.
So far I have:
#include <stdlib.h>
#include <stdio.h>
#include <zip.h>
#include <string.h>
int main()
{
//Open the ZIP archive
int err = 0;
struct zip *z = zip_open("test.zip", 0, &err);
// Determine how many files are inside and iterate through them
int num_files = zip_get_num_entries(z, 0);
printf("%u\n", num_files);
int i;
for (i=0; i < num_files; i++)
{
const char * filename;
filename = zip_get_name(z, i, 0);
// If the file name ends in .tif
if (strlen(filename) > 4 && !strcmp(filename + strlen(filename) - 4, ".tif"))
{
printf("%s\n", filename);
// Get information about file
struct zip_stat st;
zip_stat_init(&st);
zip_stat(z, name, 0, &st);
printf("%lld\n", st.size);
// Allocate memory for decompressed contents
char *contents;
contents = (char *)malloc(st.size);
// Read the file
struct zip_file *f = zip_fopen(z, filename, 0);
zip_fread(f, contents, st.size);
zip_fclose(f);
// Do something with the contents
// Free memory
free(contents);
}
}
//And close the archive
zip_close(z);
}
EDIT: My question is similar to this one but the accepted answer there relates to c++ and I'm not sure how to translate it to straight c.
I submitted this problem set, but I'm unable to get a full mark grade because the exit code "is expected to be 0 and not a 1". However, if you take a look at the code (the recover.c file), the exit code is 0. What is wrong? The program accomplishes everything it was made for, which is to read through bits in a corrupted file and find the bits that make up a JPG file and write them in a separate file. The only problem I'm having is this aforementioned exit code issue. Please help!
recover.c file
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h>
#include "bmp.h"
int main (void){
FILE* card_ptr = fopen("card.raw","r");
if (card_ptr == NULL){
fprintf(stderr,"File Not Found!");
return 1;
}
BYTE buffer[512];
bool found_jpg = false;
FILE* new_jpg_ptr;
int file_counter = 0;
while(fread(buffer,1,512,card_ptr)!=0x00){
if(buffer[0]== 0xff && buffer[1]== 0xd8 && buffer[2]==0xff && (buffer[3] & 0xf0)== 0xe0){
if(!found_jpg){
char filename[8];
sprintf(filename, "%03i.jpg", file_counter++);
found_jpg = true;
new_jpg_ptr = fopen(filename,"w");
if(new_jpg_ptr == NULL){
return 2;
}
fwrite(buffer,1,512,new_jpg_ptr);
}
else {
fclose(new_jpg_ptr);
char filename[8];
sprintf(filename, "%03i.jpg", file_counter++);
found_jpg = true;
new_jpg_ptr = fopen(filename,"w");
if(new_jpg_ptr == NULL){
return 3;
}
fwrite(buffer,1,512, new_jpg_ptr);
}
}
else {
if(found_jpg){
fwrite(buffer,1,512, new_jpg_ptr);
}
}
}
fclose(new_jpg_ptr);
fclose(card_ptr);
return 0;
}
bmp.h file
/**
* BMP-related data types based on Microsoft's own.
*/
#include <stdint.h>
/**
* Common Data Types
*
* The data types in this section are essentially aliases for C/C++
* primitive data types.
*
* Adapted from https://msdn.microsoft.com/en-us/library/cc230309.aspx.
* See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
*/
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
/**
* BITMAPFILEHEADER
*
* The BITMAPFILEHEADER structure contains information about the type, size,
* and layout of a file that contains a DIB [device-independent bitmap].
*
* Adapted from 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;
/**
* BITMAPINFOHEADER
*
* The BITMAPINFOHEADER structure contains information about the
* dimensions and color format of a DIB [device-independent bitmap].
*
* Adapted from 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;
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
I experienced the same problem. My program worked as expected with no obvious reasons for a return code of 1. As you have, I had also included a header file with some definitions in it. Placing those definitions in the core file solved my problem. Perhaps if you move the needed definitions from your bmp.h file into recover.c, check50 will be able to compile.
My solution if you're interested.
// Recover any forgotten JPEGS from a given forensic image
# include <stdio.h>
# include <stdbool.h>
# include <stdint.h>
typedef uint8_t BYTE;
typedef struct
{
BYTE byte_1;
BYTE byte_2;
BYTE byte_3;
BYTE byte_4_min;
BYTE byte_4_max;
} __attribute__((__packed__))
SIG;
// declare helper function prototypes
int check_args(int argc, char *argv[]);
bool signature_is_present(BYTE potential_sig[4], SIG jpeg_sig);
SIG set_jpeg_signature(void);
// main program
int main (int argc, char *argv[])
{
// check input for validity
int check_args_value = check_args(argc, argv);
if (check_args_value != 0)
{
return check_args_value;
}
// call function to set default jpeg signature
SIG jpeg_sig = set_jpeg_signature();
// open buffers and declare other necessary variables for later use
BYTE FAT_block[512];
BYTE first_byte[1];
int signature_offset = -4;
int counter = 0;
// open forensic image
FILE * inptr = fopen(argv[1], "r");
FILE * outptr = NULL;
// loop through file searching for first '255'
while (fread(first_byte, sizeof(BYTE), 1, inptr) == 1)
{
// check if byte is 255, the first byte of a jpeg signature
if (*first_byte == jpeg_sig.byte_1)
{
// check for signature
BYTE possible_sig[4];
// back pointer up one byte to compensate for already discovered 255
fseek(inptr, -1, SEEK_CUR);
// read four bytes from file that could potentially be a signature.
fread(possible_sig, sizeof(possible_sig), 1, inptr);
if (signature_is_present(possible_sig, jpeg_sig))
{
// close previously open write file, if any.
if (outptr != NULL)
{
fclose(outptr);
//Increment counter for image signatures found.
counter++;
}
// setup name for image file
char file_name[8] = {};
snprintf(file_name, 8, "%.3i.jpg\n", counter);
// move pointer back 4 bytes after checking what they contain
fseek(inptr, signature_offset, SEEK_CUR);
//read FAT block from forensic image into buffer
fread(FAT_block, sizeof(FAT_block), 1, inptr);
// open new output file based on current signature
outptr = fopen(file_name, "w");
// write FAT block buffer to file
fwrite(FAT_block, sizeof(FAT_block), 1, outptr);
}
else // byte is 255 but not part of a signature
{
if (outptr != NULL)
{
// move pointer back 4 bytes after checking what they contain
fseek(inptr, signature_offset, SEEK_CUR);
//read FAT block from forensic image into buffer
fread(FAT_block, sizeof(FAT_block), 1, inptr);
// write FAT block buffer to file
fwrite(FAT_block, sizeof(FAT_block), 1, outptr);
}
}
}
else // if byte is not 255
{
if (outptr != NULL)
{
//back up one byte
fseek(inptr, -1, SEEK_CUR);
//read FAT block from forensic image into buffer
fread(FAT_block, sizeof(FAT_block), 1, inptr);
// write FAT block buffer to file
fwrite(FAT_block, sizeof(FAT_block), 1, outptr);
}
}
}
// close files
fclose(inptr);
if (outptr != NULL)
{
fclose(outptr);
}
return 0;
}
// helper functions
int check_args(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Invalid Input.\nForensic image file must be provided.\n");
return 1;
}
FILE *inptr = fopen(argv[1], "r");
if (inptr == NULL)
{
fprintf(stderr, "File does not exist.\n");
return 2;
}
fclose(inptr);
return 0;
}
bool signature_is_present(BYTE potential_sig[4], SIG jpeg_sig)
{
if( potential_sig[0] == jpeg_sig.byte_1 &&
potential_sig[1] == jpeg_sig.byte_2 &&
potential_sig[2] == jpeg_sig.byte_3 &&
potential_sig[3] >= jpeg_sig.byte_4_min &&
potential_sig[3] <= jpeg_sig.byte_4_max )
{
return true;
}
return false;
}
SIG set_jpeg_signature(void)
{
SIG jpeg_sig;
jpeg_sig.byte_1 = 255;
jpeg_sig.byte_2 = 216;
jpeg_sig.byte_3 = 255;
jpeg_sig.byte_4_min = 224;
jpeg_sig.byte_4_max = 239;
return jpeg_sig;
}
I'm working on an small tool that reads data from an wav file. This tool first extracts the header followed by separating the audio data into left and right channel. Audio files are just files with a sampling frequency of 44100Hz, 16Bit PCM and dual-channel.
After manipulating the data I want to write back the data to an output file and append 100 zeros on each channel. Here the problem occurs: first just half of the desired samples are append on each channel. Secondly the first half of the appended 'zeros' are random data.
See my code below
#include <stdlib.h>
#include <stdio.h>
#define BUFFSIZE 1024
#define NUM_ZEROS 100
#include <stdio.h>
#include <stdlib.h>
typedef struct header_file
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
char subchunk2_id[4];
int subchunk2_size;
} header;
typedef struct header_file* header_p;
int main(int argc, char** argv){
if( argc != 3 ){
printf("Wrong number of input arguments. Aborting.\n");
return -1;
}
char *inputFile = argv[1];
char *outputFile = argv[2];
FILE * infile = fopen(inputFile, "r+");
FILE * outfile = fopen(outputFile, "w+");
int count = 0; // For counting number of frames in wave file.
short int buff16[2*BUFFSIZE]; // short int used for 16 bit as input data format is 16 bit PCM audio
short int buffLeft[BUFFSIZE], buffRight[BUFFSIZE];
header_p meta = (header_p)malloc(sizeof(header)); // header_p points to a header struct that contains the wave file metadata fields
int nb, cnt; // variable storing number of bytes returned
printf("Buffers initialized.\n");
if (infile)
{
fread(meta, 1, sizeof(header), infile);
meta->subchunk2_size = meta->subchunk2_size + 2 * NUM_ZEROS;
fwrite(meta,1, sizeof(*meta), outfile);
while (!feof(infile))
{
nb = fread(buff16,1,BUFFSIZE,infile); // Reading data in chunks of BUFSIZE
count++; // Incrementing Number of frames
for(cnt = 0; cnt < nb/2; cnt++){
buffLeft[cnt] = buff16[2*cnt];
buffRight[cnt] = buff16[2*cnt+1];
}
/*
* TODO: INSERT SIGNAL PROCESSING PART
*/
for(cnt = 0; cnt < nb/2; cnt++){
buff16[2*cnt] = buffLeft[cnt];
buff16[2*cnt+1] = buffRight[cnt];
}
fwrite(buff16,1,nb,outfile);
}
for(cnt = 0; cnt < 2*NUM_ZEROS; cnt++){
buff16[cnt] = 0;
}
fwrite(buff16,1, 2*NUM_ZEROS,outfile);
printf("Number of frames in the input wave file are %d.\n", count);
}
fclose(infile);
fclose(outfile);
return 0;
}
Does somebody have an idea what I did wrong?
Are you sure that only a part of the added zeros is garbage?
You mess up the data size for fread and fwrite
Your buffers are short int:
short int buff16[2*BUFFSIZE]; // BUFFSIZE*2*sizeof(short) bytes
You read only 1/4 of that size:
nb = fread(buff16,1,BUFFSIZE,infile); // BUFFSIZE bytes
This reads BUFSIZE bytes as you only specify a size of 1 per element.
Instead of BUFFSIZE*2 shorts you only read BUFFSIZE bytes.
The return value is number of read elements, i.e. bytes again.
In your buffer that amount of data is only sufficient for nb/2 elements but you access buff16[0] .. buff16[nb-1] where second half of it was not read from the file.
Luckily you also do not write the second half back into the new file as the
same error with length is also present there.
And finally the same problem is present when you append the zero values to the file.
tl;dr
Change your size parameter for fread and fwrite to sizeof(short int).
You have
#define NUM_ZEROS 100
and
fwrite(buff16,1, 2*NUM_ZEROS,outfile);
Aim:
I want to write back the data to an output file and append 100 zeros
on each channel.
I think it should be 100 SAMPLES at each channel.
As you have 16bit PCM each sample is 2 bytes.
So one channel needs 200 bytes (zeros) to be written. Stereo means 400 bytes.
Your fwrite saves just 2*NUM_ZEROS so 200 bytes - this is answer to part about missing samples.
Additionally you declare
short int buff16[2*BUFFSIZE];
while reading just half of it and using half of half (nb/2) for processing. Than write full buffer (actually half of declared) with upper half full of random garbage from memory.
Well basically I wrote this program for my computer course (shoutout CS50) that recovers images from a .raw file. I have managed to have the program recover 48 of the 50 files in that file.
The issue im having right now with the program is that the program cannot recover both the first and the second file located on .raw. It either reads and writes the very first file (this girl in a snowy background) or the second file on the .raw (guy behind books).
For some reason if I change fopen from write to append I can switch between the photo of the girl and the guy, but I cant seem to be able to open both.
https://github.com/CoreData/cs50/blob/master/pset4/jpg/card.raw
This is the link to card.raw, unfortunately its not the same one that Im using but even using this one you get two different images for image1.jpg depending on whether you have fopen with an "a" or "w".
Any ideas???
if you guys want any additional info just let me know
#include <stdio.h>
#include <stdlib.h>
#include "bmp2.h"
int main(void)
{
/*OPEN CARD FILE*/
char* infile = "card.raw";;
FILE* card = fopen(infile, "r");
if (card == NULL)
{
printf("Could not open %s.\n", "card.raw");
return 2;
}
int f = 0, c = 0, l = 0, x = 128, imageno = 1;
// c signals that a jpg is being written
// l size control, 0 means 0 jpgs
FILE* images;
char* title = (char*)malloc(15);
/*repeat until end of card*/
do
{
//read one block into buffer
INTROJPG *buffer = (INTROJPG*)malloc(sizeof(INTROJPG)*x);
for (int i = 0; i < 128; i++)
{
fread(&buffer[i], sizeof(INTROJPG), 1, card);
}
if (buffer[0].first == 0xff && buffer[0].second == 0xd8 && buffer[0].third == 0xff)
{
sprintf(title, "image%d.jpg", imageno); //change jpg title
if (f == 1) //close previous jpg
{
fclose(images);
imageno++;
}
images = fopen(title, "w");
f = 1; //very first jpg has been opened
c = 1; //jpg open
l++; //jpg count + 1
}
//jpg already open?
if (c == 1)
{
for (int i = 0; i < 128; i++)
{
fwrite(&buffer[i], sizeof(INTROJPG), 1, images);
}
}
free(buffer);
}
while (l < 50);
free(title);
return 5;
//close any remaining files
}
and this is my bmp2.h file
#include <stdint.h>
/**
* Common Data Types
*
* The data types in this section are essentially aliases for C/C++
* primitive data types.
*
* Adapted from http://msdn.microsoft.com/en-us/library/cc230309.aspx.
* See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
*/
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
/**
* BITMAPFILEHEADER
*
* The BITMAPFILEHEADER structure contains information about the type, size,
* and layout of a file that contains a DIB [device-independent bitmap].
*
* Adapted from http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx.
*/
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;
/**
* BITMAPINFOHEADER
*
* The BITMAPINFOHEADER structure contains information about the
* dimensions and color format of a DIB [device-independent bitmap].
*
* Adapted from http://msdn.microsoft.com/en-us/library/dd183376(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;
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
typedef struct
{
BYTE first;
BYTE second;
BYTE third;
BYTE fourth;
} __attribute__((__packed__))
INTROJPG;
typedef struct
{
BYTE image;
}
BYTEIMAGE;
First things first, I'll try to improve a few things in your code. I've also done this pset and it is nice to help others.
INTROJPG *buffer = (INTROJPG*)malloc(sizeof(INTROJPG)*x);
At this part, you know that the size of both INTROJPG and x are constant, so there is no need to constantly allocate and free memory at every iteration, that takes much more time than simply creating a normal array. Also, why is the buffer a pointer to INTROJPG? If it is only to test for a header at each iteration, I don't think it is worth it, you could simply access the first 4 bytes of a normal BYTE array.
I'd create a static array of 512 BYTEs (the struct on the library), because this is the size you are constantly allocating and freeing and also you are using BYTEs, not INTROJPGs.
Second, at this section and another similar one:
for (int i = 0; i < 128; i++)
{
fread(&buffer[i], sizeof(INTROJPG), 1, card);
}
There is absolutely no need for this loop or, again, even using INTROJPG. You are always reading and writing 512 bytes, you could use:
fread(buffer, 4, 128, card);
// or even better
fread(buffer, 512, 1, card);
Now about your problem, I've tested your code (without any modifications) multiple times and found nothing wrong with image1.jpg and image2.jpg. Yes, I changed "w" mode to "a" and vice-versa.
However, your code is faulty in regard to the last image, your last image is image49.jpg, when it should be image50.jpg, and your image49.jpg does not even open, and that's because the loop is finished before the rest of image49.jpg is stored, i.e., you are storing only the first 512 bytes of image49.jpg.
To fix that, I've changed the condition of the do-while loop to keep going until the end of the card file, IIRC the problem guarantees the last block being part of the last image or something like that, if not, it's up to you to fix this little problem!
#include <stdio.h>
#include <stdlib.h>
#include "bmp2.h"
int main(void)
{
/*OPEN CARD FILE*/
char* infile = "card.raw";;
FILE* card = fopen(infile, "r");
if (card == NULL)
{
printf("Could not open %s.\n", "card.raw");
return 2;
}
int f = 0, c = 0, imageno = 1;
// c signals that a jpg is being written
// l size control, 0 means 0 jpgs
FILE* images;
char title[25];
BYTE buffer[512];
/*repeat until end of card*/
do
{
fread(buffer, 512, 1, card);
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff)
{
sprintf(title, "image%d.jpg", imageno); //change jpg title
if (f == 1) //close previous jpg
{
fclose(images);
imageno++;
}
images = fopen(title, "w");
f = 1; //very first jpg has been opened
c = 1; //jpg open
}
//jpg already open?
if (c == 1) fwrite(buffer, 512, 1, images);
}
while (!feof(card));
return 5;
//close any remaining files
}
One last thing, why are you returning 5 at the end of the program? Just curious.
I am currently facing issues when trying to apply the run-length algorithm to a .bmp picture. When I am doing the encoding, all is working well, but at decoding there is a problem and I cannot figure it out, namely I cannot read the number of repetitive pixels and thus my output is a blank image. When I use the debugger, the number of repetitive pixels is not readed correctly from the binary file (the result of applying RLE on the bitmap file). Here is my code
#include<stdlib.h>
#include <stdint.h>
//structure defiens bitmap header
struct BITMAPFILEHEADER{
uint8_t type[2];//type of file (bit map)
uint32_t size;//size of file
uint16_t reserved1;//
uint16_t reserved2;//
uint32_t offsetbits;//off set bits
} __attribute__ ((packed));
struct BITMAPINFOHEADER{
uint32_t size;//bitmap size
// uint16_t w2;
uint32_t width;//width of bitmap
//uint16_t h2;
uint32_t height;//hight of bitmap
uint16_t planes;
uint16_t bitcount;
uint32_t compression;// compression ratio (zero for no compression)
uint32_t sizeimage;//size of image
long xpelspermeter;
long ypelspermeter;
uint32_t colorsused;
uint32_t colorsimportant;
} __attribute__ ((packed));
//const char* INPUT_FILE = "/home/bogdan/bee.bmp";
const char* INPUT_FILE = "/home/bogdan/Linux.bmp";
const char* ENCODED_FILE = "/home/bogdan/encoded.bin";
const char* DECODED_FILE = "/home/bogdan/decoded.bmp";
typedef struct SINGLE_PIXEL{
uint8_t green;//Green level 0-255
uint8_t red; //Red level 0-255
} PIXEL;
int comparePixels(PIXEL, PIXEL);
void encode();
void decode(char*);
int main()
{
encode();
decode(ENCODED_FILE);
return 0;
}
void encode() {
uint32_t i=0;//to count pixels read
uint32_t pixno=0;//number of pixels to read
struct BITMAPFILEHEADER source_head;//to store file header
struct BITMAPINFOHEADER source_info;//to store bitmap info header
PIXEL pixel;// the current pixel
FILE *in;// bitmap imput pointer file
FILE *out;//output file pointer
if(!(in=fopen(INPUT_FILE,"rb")))//open in binary read mode
{
printf("\ncan not open file");//error at opening file
exit(-1);
}
out=fopen(ENCODED_FILE,"wb");//opne in binary write mode
//read the headers to source file
fread(&source_head,sizeof(struct BITMAPFILEHEADER),1,in);
fread(&source_info,sizeof(struct BITMAPINFOHEADER),1,in);
//write the headers to the output file
fwrite(&source_head,sizeof(struct BITMAPFILEHEADER),1,out);
fwrite(&source_info,sizeof(struct BITMAPINFOHEADER),1,out);
//cumpute the number of pixels to read
pixno=source_info.width*source_info.height;
// init list of pixels
PIXEL pixArr[pixno];
printf("total pixels: %d", pixno);
//printf("w:%f h:%u pn:%lu", (source_head.size/1024.0/1024), source_info.height, pixno);
uint32_t sum = 0;
//read, modify and write pixels
for(i=0;i<pixno;++i)
{
//read pixel form source file
fread(&pixel,sizeof(PIXEL),1,in);
pixArr[i] = pixel;
}
for (i = 0; i < pixno; i++) {
// printf ("i = %d\tred = %d green = %d blue = %d\n",i, pixArr[i].red, pixArr[i].green, pixArr[i].blue);
int runlength = 1;
while ((i + 1) < pixno) {
if (comparePixels(pixArr[i], pixArr[i+1]) == 0){
// printf ("i = %d\t red = %d green = %d blue = %d\n",i, pixArr[i].red, pixArr[i].green, pixArr[i].blue);
runlength++;
i++;
} else {
break;
}
}
//fprintf(out, "%d", runlength);
fwrite(&runlength, sizeof(runlength), 1, out);
fwrite(&pixel,sizeof(PIXEL),1,out);
sum += runlength;
runlength = 0;
}
//write the modification to the output file
//close all fiels
fclose(in);
fclose(out);
printf("sum = %d",sum);
}
void decode(char * filePath) {
uint32_t i=0;//to count pixels read
uint32_t j=0;
uint32_t totalPixels=0;//number of pixels to read
uint32_t pixelRepetition = 1;
struct BITMAPFILEHEADER source_head;//to store file header
struct BITMAPINFOHEADER source_info;//to store bitmap info header
PIXEL pixel;// the current pixel
FILE *in;// bitmap encoded pointer file
FILE *out;//decoded bitmap file pointer
if (!(in = fopen(filePath, "rb"))) {
printf("\ncan not open file");
exit(-1);
}
out = fopen(DECODED_FILE, "wb");
//read the headers to source file
fread(&source_head,sizeof(struct BITMAPFILEHEADER),1,in);
fread(&source_info,sizeof(struct BITMAPINFOHEADER),1,in);
//write the headers to the output file
fwrite(&source_head,sizeof(struct BITMAPFILEHEADER),1,out);
fwrite(&source_info,sizeof(struct BITMAPINFOHEADER),1,out);
totalPixels=source_info.width*source_info.height;
while(i < totalPixels) {
fread(&pixelRepetition, sizeof(pixelRepetition), 1, out);
fread(&pixel,sizeof(PIXEL),1,in);
for (j = 0; j < pixelRepetition; j++) {
fwrite(&pixel,sizeof(PIXEL),1,out);
}
i += pixelRepetition;
}
fclose(in);
fclose(out);
}
int comparePixels(PIXEL px1, PIXEL px2) {
if (px1.red == px2.red && px1.green == px2.green && px1.blue == px2.blue) {
return 0;
} else {
return -1;
}
}
My implementation is working as follow: I read the header of a bmp file and put it directly to another file. After that I compare pixels to see if they have the same RGB values. If this is true (according to comparePixels function) I put the number of consecutive identical pixels and one pixel (the one which is repeated) into the file. This is the encode phase. At decoding, I am reading the header of the image and then I am trying to read the number of repetitions (1 default, means no repetitive pixels) and the pixel which is repeated. I will really appreciate any type of help. Thank you.
You are repeatedly writing out only the very last pixel you read in:
fwrite(&runlength, sizeof(runlength), 1, out);
fwrite(&pixel,sizeof(PIXEL),1,out);
You need to write out your current pixel instead:
fwrite(pixArr[i], sizeof(PIXEL),1,out);