Reputation: 77
I am trying to extract jpeg files from a memory-card like file. The program will read 512 byte blocks at a time and if the block starts with JPEG-identifying bytes, my program should write to an output file those bytes. It should keep writing those bytes until it finds another JPEG-identifying byte sequence at which time it should stop writing to the .jpg file and write to a new one. Each file should be named 00x.jpg where x is the #.
My program compiles but doesn't produce all the jpegs. There should be 16 JPEGs but it only produces 7.
int main(void)
{
// open file for reading
FILE* file = fopen("card.raw", "r"); // Open the file for reading
// target file
FILE* image;
// buffer of bytes
uint8_t buffer[512];
// check for NULL file
if (file == NULL)
{
fclose(file);
printf("Could not open file");
return 1;
}
// Prefixes of a jpeg file
uint8_t jpeg1[4] = {0xff, 0xd8, 0xff, 0xe0};
uint8_t jpeg2[4] = {0xff, 0xd8, 0xff, 0xe1};
// keep track of jpegs opened
int pic = 0;
int match = 0;
// is file open?
int open = 0;
// stores first 4 bytes of block
uint8_t check[4];
int byteNum;
byteNum = fread(buffer, 512, 1, file);
// while there are bytes to be read in the file
while(fread(buffer,512, 1, file) > 0)
{
for (int x=0; x < 4; x++)
{
check[x] = buffer[x];
}
// compares first 4 bytes of buffer segment to jpeg prefixes to determine match
if((memcmp(check, jpeg1,4) == 0) || (memcmp(check, jpeg2, 4) == 0))
{
match = 1;
}
// if encounter a jpeg and file is open, close the file and set match to false
if (match == 1 && open == 1)
{
fclose(image);
open = 0;
match = 0;
}
// if match is true and file is closed, create jpeg output file, increment pic#, set file to open, set match to false, open target file
if (match == 1 && open == 0)
{
// stores name of jpegfile
char jpegName[8];
// stores the jpeg file name with the # jpeg
sprintf(jpegName ,"%03d.jpg" ,pic);
pic++;
open = 1; // signifies target jpeg file is open
match = 0; // sets match back to 0 (false) so it can detect the next match to signify closing the writing
image=fopen(jpegName, "w"); // write to target file image
}
// if file target is still open but no match, then keep writing since you're in the middle of a jpeg
if (match == 0 && open == 1)
{
fwrite(buffer, 512, 1, image);
}
}
fclose(file);
return 0;
}
Upvotes: 2
Views: 3826
Reputation: 66194
I may be missing something stark, but if all you're trying to do is read a file in 512-byte chunks, checking the first four octets of each chunk for two known preambles, and upon encountering either, open an image file and start dumping until the next chunk that matches closes the file and starts a new one, then about half the posted code isn't needed.
You can use the value of image
(null or not) to dictate whether a file is opened or not. Further, only write data if a file is opened (image != NULL)
, and close an existing file if opened before cycling to the next file.
Something like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
int main(void)
{
// Prefixes of a jpeg file
static const uint8_t jpeg1[4] = {0xff, 0xd8, 0xff, 0xe0};
static const uint8_t jpeg2[4] = {0xff, 0xd8, 0xff, 0xe1};
// open file for reading
FILE* file = fopen("card.raw", "r"); // Open the file for reading
if (file == NULL)
{
perror("card.raw");
return EXIT_FAILURE;
}
// target file
FILE* image = NULL;
// keep track of jpegs opened
int pic = 0;
// while there are bytes to be read in the file
uint8_t buffer[512];
size_t n_bytes = 0;
while( (n_bytes = fread(buffer,1, 512, file)) > sizeof(jpeg1))
{
// compares first 4 bytes of buffer segment to jpeg prefixes to determine match
if( memcmp(buffer, jpeg1, sizeof(jpeg1)) == 0 ||
memcmp(buffer, jpeg2, sizeof(jpeg2)) == 0)
{
// stores the jpeg file name with the # jpeg
char jpegName[64];
sprintf(jpegName ,"00%d.jpg" , pic++);
// match. close current file if present.
if (image)
fclose(image);
// open new image file (sets NULL on failure)
image = fopen(jpegName, "wb"); // write to target file image
if (image == NULL)
{
perror(jpegName);
break;
}
}
// write whatever we have for our current bytes
if (image)
fwrite(buffer, n_bytes, 1, image);
}
// the above loop can exit with a file open (in fact, it is guaranteed
// if we opened at least one file), so close it if one is active.
if (image)
fclose(image);
}
Or something similar. This also opens and closes files in binary-mode, and does not write extraneous junk ot the last frame if it was smaller than an even 512 bytes. Finally, it increments pic
on each file created, and has a (admittedly soft) amount of error checking.
Anyway, hope it helps. Best of luck.
Upvotes: 2