|
Packit |
78deda |
/*****************************************************************************
|
|
Packit |
78deda |
jpegdatasource.c
|
|
Packit |
78deda |
******************************************************************************
|
|
Packit |
78deda |
This is the data source manager that Jpegtopnm supplies to the JPEG
|
|
Packit |
78deda |
library. The Jpeg library uses this object to get JPEG input.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
This data source manager is the same as the Jpeg library's built in
|
|
Packit |
78deda |
"stdio" one, except that it looks ahead and one can query it to see
|
|
Packit |
78deda |
if there is any data in the stream that the Jpeg library hasn't seen
|
|
Packit |
78deda |
yet. Thus, you can use it in a program that reads multiple JPEG
|
|
Packit |
78deda |
images and know when to stop. You can also nicely handle completely
|
|
Packit |
78deda |
empty input files more gracefully than just crying input error.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
This data source manager does 4K fread() reads and passes 4K buffers
|
|
Packit |
78deda |
to the Jpeg library. It reads one 4K block ahead, so there is up to
|
|
Packit |
78deda |
8K of image buffered at any time.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
By Bryan Henderson, San Jose CA 2002.10.13
|
|
Packit |
78deda |
*****************************************************************************/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <ctype.h>
|
|
Packit |
78deda |
#include <stdlib.h>
|
|
Packit |
78deda |
#include <stdio.h>
|
|
Packit |
78deda |
#include <errno.h>
|
|
Packit |
78deda |
/* Note: jpeglib.h prerequires stdlib.h and ctype.h. It should include them
|
|
Packit |
78deda |
itself, but doesn't.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
#include <jpeglib.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "pnm.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "jpegdatasource.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define BUFFER_SIZE 4096
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct sourceManager {
|
|
Packit |
78deda |
/* The following structure _must_ be the first thing in this structure,
|
|
Packit |
78deda |
because the methods below assume the address of the struct
|
|
Packit |
78deda |
jpeg_source_mgr is the same as the address of the struct sourceManager.
|
|
Packit |
78deda |
The former address is the only information the Jpeg library gives
|
|
Packit |
78deda |
these methods to tell them on what source manager object they are
|
|
Packit |
78deda |
supposed to operate.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
struct jpeg_source_mgr jpegSourceMgr;
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
bool prematureEof;
|
|
Packit |
78deda |
/* We have been asked for data and were unable to comply because
|
|
Packit |
78deda |
the file had no more to give (so we supplied EOI markers
|
|
Packit |
78deda |
instead).
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
JOCTET * currentBuffer;
|
|
Packit |
78deda |
JOCTET * nextBuffer;
|
|
Packit |
78deda |
unsigned int bytesInNextBuffer;
|
|
Packit |
78deda |
JOCTET buffer1[BUFFER_SIZE];
|
|
Packit |
78deda |
JOCTET buffer2[BUFFER_SIZE];
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
dsInitSource(j_decompress_ptr const cinfoP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
This is the init_source method for the data source manager the Jpeg
|
|
Packit |
78deda |
library uses.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
/* The object was created ready to go and remains ready from one image
|
|
Packit |
78deda |
to the next. No per-image initialization is necessary.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static const JOCTET jfifEoiMarker[] = {0xff, JPEG_EOI};
|
|
Packit |
78deda |
/* An EOI (end of image) marker */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static boolean
|
|
Packit |
78deda |
dsFillInputBuffer(j_decompress_ptr const cinfoP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
This is the fill_input_buffer method for the data source manager the Jpeg
|
|
Packit |
78deda |
library uses.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
struct sourceManager * const srcP = (struct sourceManager *) cinfoP->src;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (srcP->bytesInNextBuffer == 0) {
|
|
Packit |
78deda |
/* The decompressor expects more bytes, but there aren't any, so
|
|
Packit |
78deda |
the file is corrupted -- probably truncated. We want the
|
|
Packit |
78deda |
decompressor to decompress whatever it's read so far, so we
|
|
Packit |
78deda |
synthesize an EOI marker here, but we also set error state
|
|
Packit |
78deda |
in the source manager. The decompressor will recognize the
|
|
Packit |
78deda |
truncation and pad out the image with gray.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
srcP->prematureEof = TRUE;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
srcP->jpegSourceMgr.next_input_byte = jfifEoiMarker;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.bytes_in_buffer = sizeof(jfifEoiMarker);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
/* Rotate the buffers */
|
|
Packit |
78deda |
srcP->jpegSourceMgr.next_input_byte = srcP->nextBuffer;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.bytes_in_buffer = srcP->bytesInNextBuffer;
|
|
Packit |
78deda |
{
|
|
Packit |
78deda |
JOCTET * tmp;
|
|
Packit |
78deda |
tmp = srcP->nextBuffer;
|
|
Packit |
78deda |
srcP->nextBuffer = srcP->currentBuffer;
|
|
Packit |
78deda |
srcP->currentBuffer = tmp;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Fill the new "next" buffer */
|
|
Packit |
78deda |
srcP->bytesInNextBuffer =
|
|
Packit |
78deda |
fread(srcP->nextBuffer, 1, BUFFER_SIZE, srcP->ifP);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return TRUE;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
dsSkipInputData(j_decompress_ptr const cinfoP, long const num_bytes) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
This is the skip_input_data method for the data source manager the Jpeg
|
|
Packit |
78deda |
library uses.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
struct jpeg_source_mgr * const jpegSourceMgrP = cinfoP->src;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
long i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i < num_bytes; ++i) {
|
|
Packit |
78deda |
if (jpegSourceMgrP->bytes_in_buffer == 0)
|
|
Packit |
78deda |
dsFillInputBuffer(cinfoP);
|
|
Packit |
78deda |
++jpegSourceMgrP->next_input_byte;
|
|
Packit |
78deda |
--jpegSourceMgrP->bytes_in_buffer;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
dsTermSource(j_decompress_ptr const cinfoP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
This is the term_source method for the data source manager the Jpeg
|
|
Packit |
78deda |
library uses.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
/* We couldn't care less that the Jpeg library is done reading an
|
|
Packit |
78deda |
image. The source manager object remains active and ready for the
|
|
Packit |
78deda |
Jpeg library to read the next image.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bool
|
|
Packit |
78deda |
dsDataLeft(struct sourceManager * const srcP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return((srcP->jpegSourceMgr.bytes_in_buffer > 0 ||
|
|
Packit |
78deda |
srcP->bytesInNextBuffer > 0));
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bool
|
|
Packit |
78deda |
dsPrematureEof(struct sourceManager * const srcP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return srcP->prematureEof;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct sourceManager *
|
|
Packit |
78deda |
dsCreateSource(const char * const fileName) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct sourceManager * srcP;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCVAR(srcP);
|
|
Packit |
78deda |
if (srcP == NULL)
|
|
Packit |
78deda |
pm_error("Unable to get memory for the Jpeg library source manager.");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
srcP->ifP = pm_openr(fileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
srcP->jpegSourceMgr.init_source = dsInitSource;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.fill_input_buffer = dsFillInputBuffer;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.skip_input_data = dsSkipInputData;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.resync_to_restart = jpeg_resync_to_restart;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.term_source = dsTermSource;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
srcP->prematureEof = FALSE;
|
|
Packit |
78deda |
srcP->currentBuffer = srcP->buffer1;
|
|
Packit |
78deda |
srcP->nextBuffer = srcP->buffer2;
|
|
Packit |
78deda |
srcP->jpegSourceMgr.bytes_in_buffer =
|
|
Packit |
78deda |
fread(srcP->currentBuffer, 1, BUFFER_SIZE, srcP->ifP);
|
|
Packit |
78deda |
srcP->jpegSourceMgr.next_input_byte = srcP->currentBuffer;
|
|
Packit |
78deda |
srcP->bytesInNextBuffer =
|
|
Packit |
78deda |
fread(srcP->nextBuffer, 1, BUFFER_SIZE, srcP->ifP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return srcP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
void
|
|
Packit |
78deda |
dsDestroySource(struct sourceManager * const srcP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_close(srcP->ifP);
|
|
Packit |
78deda |
free(srcP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct jpeg_source_mgr *
|
|
Packit |
78deda |
dsJpegSourceMgr(struct sourceManager * const srcP) {
|
|
Packit |
78deda |
return &srcP->jpegSourceMgr;
|
|
Packit |
78deda |
}
|