Blame converter/other/jpegdatasource.c

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
}