This is SurfJPEGDecoder.Internal.m in view mode; [Download] [Up]
/* ** Copyright (c) 1995 Netsurfer Inc. All Rights Reserved. ** ** Author: <bbum@friday.com> */ /* This object is included in the MiscKit by permission from the author ** and its use is governed by the MiscKit license, found in the file ** "LICENSE.rtf" in the MiscKit distribution. Please refer to that file ** for a list of all applicable permissions and restrictions. */ #import <appkit/appkit.h> #import "SurfJPEGSupport.h" #import "SurfJPEGDecoder.Internal.h" #import <jpeglib.h> #import <jerror.h> #import <jconfig.h> #import <mach/mach.h> #ifdef VERBOSE #undef VERBOSE #undef METHOD #undef METHODnl #endif #define VERBOSE if(_SDFlags.verboseMode) #define METHOD fprintf(stderr, "[%s %s%s] ", \ object_getClassName(self), \ (self == [self class]) ? "+" : "-", \ SELNAME(_cmd)) #define METHODnl fprintf(stderr, "[%s %s%s]\n", \ object_getClassName(self), \ (self == [self class]) ? "+" : "-", \ SELNAME(_cmd)) #define INPUT_BUF_SIZE vm_page_size typedef struct { struct jpeg_source_mgr pub; /* public fields */ NXStream *infile; /* source stream */ JOCTET *buffer; /* start of buffer */ boolean start_of_file; /* have we gotten any data yet? */ } my_source_mgr; typedef my_source_mgr * my_src_ptr; @implementation SurfJPEGDecoder (InternalAPI) /*" * This category implements the internals of the JPEG/JFIF decoder. It * basically provides an interface between the #{SurfDecoder} API and the * IJG libjpeg API. "*/ void _init_source(j_decompress_ptr cinfo) { my_src_ptr src = (my_src_ptr) cinfo->src; src->start_of_file = TRUE; } boolean _fill_input_buffer (j_decompress_ptr cinfo) { my_src_ptr src = (my_src_ptr) cinfo->src; size_t nbytes; nbytes = NXRead(src->infile, src->buffer, INPUT_BUF_SIZE); if (nbytes <= 0) { if (src->start_of_file) /* Treat empty input file as fatal error */ ERREXIT(cinfo, JERR_INPUT_EMPTY); WARNMS(cinfo, JWRN_JPEG_EOF); /* Insert a fake EOI marker */ src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2; } src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = nbytes; src->start_of_file = FALSE; return TRUE; } static void _skip_input_data (j_decompress_ptr cinfo, long num_bytes) { my_src_ptr src = (my_src_ptr) cinfo->src; /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { while (num_bytes > (long) src->pub.bytes_in_buffer) { num_bytes -= (long) src->pub.bytes_in_buffer; (void) _fill_input_buffer(cinfo); /* note we assume that fill_input_buffer will never return FALSE, * so suspension need not be handled. */ } src->pub.next_input_byte += (size_t) num_bytes; src->pub.bytes_in_buffer -= (size_t) num_bytes; } } void _term_source (j_decompress_ptr cinfo) { /* no work necessary here */ } void _nxstream_stdio_src (j_decompress_ptr cinfo, NXStream *infile) { my_src_ptr src; /* The source object and input buffer are made permanent so that a series * of JPEG images can be read from the same file by calling jpeg_stdio_src * only before the first one. (If we discarded the buffer at the end of * one image, we'd likely lose the start of the next one.) * This makes it unsafe to use this manager and a different source * manager serially with the same JPEG object. Caveat programmer. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); src = (my_src_ptr) cinfo->src; src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof(JOCTET)); } src = (my_src_ptr) cinfo->src; src->pub.init_source = _init_source; src->pub.fill_input_buffer = _fill_input_buffer; src->pub.skip_input_data = _skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = _term_source; src->infile = infile; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ } void _update_row_ptr_buf(unsigned char **rowPtrBuf, unsigned totalRows, unsigned rowsRead, unsigned readCount, unsigned bytesPerRow, unsigned char *data) { unsigned row; unsigned bufIndex; unsigned maxRow = (rowsRead + readCount); maxRow = (maxRow < totalRows) ? maxRow : totalRows; for(row=rowsRead, bufIndex = 0; row < maxRow; row++, bufIndex++) rowPtrBuf[bufIndex] = &(data[row * bytesPerRow]); } - _decodeImage { NXBitmapImageRep *imageRep; void *data; int bytesPerRow; VERBOSE { METHODnl; } totalRows = jpegDecompInfo.pub.output_height; imageRep = [[NXBitmapImageRep allocFromZone:[self zone]] initDataPlanes:NULL // instance will allocate pixelsWide: jpegDecompInfo.pub.output_width pixelsHigh: totalRows bitsPerSample:8 samplesPerPixel:jpegDecompInfo.pub.output_components hasAlpha:NO isPlanar:NO colorSpace:NX_RGBColorSpace bytesPerRow:0 // instance will figure it out bitsPerPixel:0]; if(!imageRep) { VERBOSE { METHOD; fprintf(stderr, "Failed to allocate imageRep.\n"); } return nil; } data = [imageRep data]; bytesPerRow = [imageRep bytesPerRow]; rowsRead = 0; while (jpegDecompInfo.pub.output_scanline < jpegDecompInfo.pub.output_height) { _update_row_ptr_buf(rowPtrBuf, totalRows, rowsRead, readCount, bytesPerRow, data); rowsRead += jpeg_read_scanlines(&jpegDecompInfo.pub, (JSAMPARRAY) rowPtrBuf, 1); } [returnImage useRepresentation:imageRep]; return returnImage; } void surfjpeg_error_exit (j_common_ptr cinfo) { surfjpeg_error_ptr theErr = (surfjpeg_error_ptr) cinfo->err; /* Always display the message. */ // (*cinfo->err->output_message) (cinfo); longjmp(theErr->setjmp_buffer, 1); // bounce to setjmp() point } void surfjpeg_error_msg (j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; surfjpeg_decompress_ptr decompInfo = (surfjpeg_decompress_ptr) cinfo; /* Create the message */ (*cinfo->err->format_message) (cinfo, buffer); [decompInfo->jpegDecoder setLastImageCorrupt: YES]; if(decompInfo->jpegDecoder) [decompInfo->jpegDecoder spewMessage:buffer withSeverity:SEV_Failure]; } - _decodeFromStream:(NXStream *) theStream { id theImage; // initialize decompressor jpegDecompInfo.pub.err = jpeg_std_error(&jpegErrMgr.pub); jpegDecompInfo.jpegDecoder = self; jpeg_create_decompress(&jpegDecompInfo.pub); // set source to theStream _nxstream_stdio_src(&jpegDecompInfo.pub, theStream); // set up jpeg error handlers jpegErrMgr.pub.output_message = surfjpeg_error_msg; jpegErrMgr.pub.error_exit = surfjpeg_error_exit; if(setjmp(jpegErrMgr.setjmp_buffer)) { [self setLastImageCorrupt: YES]; jpeg_destroy_decompress(&jpegDecompInfo.pub); return (rowsRead < (totalRows / 2)) ? nil : theImage; } // read header and start decompression jpeg_read_header(&jpegDecompInfo.pub, TRUE); jpeg_start_decompress(&jpegDecompInfo.pub); // dump verbosity VERBOSE { METHOD; fprintf(stderr, "(%d x %d); %d components\n", jpegDecompInfo.pub.image_width, jpegDecompInfo.pub.image_height, jpegDecompInfo.pub.num_components); } // decode image theImage = [self _decodeImage]; // finish decompression jpeg_finish_decompress(&jpegDecompInfo.pub); // destroy decompression context jpeg_destroy_decompress(&jpegDecompInfo.pub); // return theImage return theImage; // will either by returnImage or nil } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.