2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata);
31 jpeg_memio_cleanup (j_decompress_ptr cinfo);
36 useImageDimensions=true;
46 if (fileName) delete fileName;
49 int WJpeg::init(char* tfileName,bool useImage, JpegReader *rdr)
52 if (fileName) delete fileName;
55 fileName = new char[strlen(tfileName)+1];
56 strcpy(fileName,tfileName);
59 useImageDimensions=useImage;
64 ULONG WJpeg::getJpegInfo(ULONG tag){
85 int WJpeg::getJpegInfo(ULONG tag, char * buffer) {
88 strncpy(buffer,fileName,INFO_BUFFER-1);
89 buffer[INFO_BUFFER-1]=0;
96 void WJpeg::setRotate(int amount) {
103 struct my_error_mgr {
104 struct jpeg_error_mgr pub; /* "public" fields */
105 FILE *infile; /* to be used in error handler */
107 jmp_buf setjmp_buffer; /* for return to caller */
110 typedef struct my_error_mgr * my_error_ptr;
113 * Here's the routine that will replace the standard error_exit method:
117 my_error_exit (j_common_ptr cinfo)
119 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
120 my_error_ptr myerr = (my_error_ptr) cinfo->err;
122 /* Always display the message. */
123 /* We could postpone this until after returning, if we chose. */
124 (*cinfo->err->output_message) (cinfo);
125 if (myerr->infile) fclose(myerr->infile);
126 /* Return control to the setjmp point */
127 longjmp(myerr->setjmp_buffer, 1);
132 bool WJpeg::hasError() {
138 if (drawJpeg() != 0) {
140 drawTextCentre(tr("Jpeg ERROR"), 240, 180, Colour::LIGHTTEXT);
144 /* handle picture rotation
152 void WJpeg::drawPixel(int x, int y,int w,int h,int xpos, int ypos,Colour c){
175 if (xb < 0 || yb < 0 ) {
176 Log::getInstance()->log("WJpeg:drawPixel",Log::ERR,"pixpos < 0 x=%d, y=%d",xb,yb);
179 Boxx::drawPixel((UINT)xb,(UINT)yb,c);
182 int WJpeg::drawJpeg() {
184 Log* logger = Log::getInstance();
185 unsigned char* buffer =NULL;
186 struct jpeg_decompress_struct cinfo;
187 struct my_error_mgr jerr;
189 cinfo.err = jpeg_std_error(&jerr.pub);
190 jerr.pub.error_exit = my_error_exit;
191 /* Establish the setjmp return context for my_error_exit to use. */
192 if (setjmp(jerr.setjmp_buffer)) {
193 /* If we get here, the JPEG code has signaled an error.
194 * We need to clean up the JPEG object, close the input file, and return.
196 if (reader) jpeg_memio_cleanup(&cinfo);
197 jpeg_destroy_decompress(&cinfo);
198 logger->log("BJpeg", Log::ERR, "JPEG error");
199 if (buffer) free(buffer);
204 jpeg_create_decompress(&cinfo);
205 if (fileName && ! reader) {
206 jsize=0; //TODO: compute size for local files
207 jerr.infile=fopen(fileName, "r");
208 if (jerr.infile == NULL)
210 logger->log("BJpeg", Log::ERR, "Can't open JPEG");
211 jpeg_destroy_decompress(&cinfo);
214 logger->log("BJpeg", Log::DEBUG, "File opened");
215 jpeg_stdio_src(&cinfo, jerr.infile);
218 jsize=reader->initRead(fileName);
220 logger->log("BJpeg", Log::ERR, "Can't init JPEG transfer");
221 jpeg_destroy_decompress(&cinfo);
224 jpeg_memio_src(&cinfo,(void *)reader);
227 logger->log("BJpeg", Log::ERR, "neither filename nor reader set");
228 jpeg_destroy_decompress(&cinfo);
231 jpeg_read_header(&cinfo, TRUE);
232 logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", cinfo.image_width, cinfo.image_height, rotate);
233 int picturew=cinfo.image_width;
234 int pictureh=cinfo.image_height;
238 pictureh=cinfo.image_width;
239 picturew=cinfo.image_height;
242 if (! useImageDimensions) {
243 //scale - we can have factors 1,2,4,8
244 int scalew=getWidth()*1000/picturew;
245 int scaleh=getHeight()*1000/pictureh;
247 if (scalew < scaleh) scale=scalew;
249 //we allow for 10% bigger...
250 if (scale >= 900) fac=1;
251 else if (scale >= 450 ) fac=2;
252 else if (scale >= 225 ) fac=4;
253 cinfo.scale_denom=fac;
254 logger->log("BJpeg", Log::DEBUG, "JPEG scaling (1/1000) pw=%i ph=%i w=%i h=%i r=%i f=%i",
257 scalew,scaleh,scale,fac);
261 //remember picture parameters
265 jpeg_start_decompress(&cinfo);
266 //recompute width based on rotation (consider scale)
267 picturew=cinfo.output_width;
268 pictureh=cinfo.output_height;
272 pictureh=cinfo.output_width;
273 picturew=cinfo.output_height;
276 //if our image is smaller - center it
277 if (! useImageDimensions) {
278 xpos=(getWidth()-picturew)/2;
280 ypos=(getHeight()-pictureh)/2;
283 //center point for rotation
284 int w=cinfo.output_width;
285 int h=cinfo.output_height;
286 logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, iw=%i, ih=%i", picturew, pictureh,xpos,ypos,w,h);
290 // Temp disabled for boxx. what does this do anyway .. - cjt
292 if (useImageDimensions) setDimensions(picturew, pictureh);
293 fillColour(backgroundColour);
297 //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
298 int linelen=cinfo.output_width*3;
301 buffer = (unsigned char*)malloc(config.output_height * linelen);
302 logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, width = %i height = %i", buffer, cinfo.output_height, linelen);
303 if (buffer == NULL) {
304 if (reader) jpeg_memio_cleanup(&cinfo);
305 jpeg_destroy_decompress(&cinfo);
306 if (jerr.infile) fclose(jerr.infile);
307 logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
312 //unsigned char* bufferPointers[area.h];
313 //for(UINT ps = 0; ps < area.h; ps++) bufferPointers[ps] = buffer + (ps * area.w * 3);
315 logger->log("BJpeg", Log::DEBUG, "header w=%d,h=%d",cinfo.output_width,cinfo.output_height);
317 unsigned char lbuf[linelen];
318 unsigned char * ptr=lbuf;
320 unsigned char * ptr=buffer;
326 while (cinfo.output_scanline < cinfo.output_height)
328 // logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
329 rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
334 for (unsigned char * lp=ptr;lp < (ptr+linelen);lp+=3,x++) {
338 drawPixel(x, rowsread-1,w,h,xpos,ypos, c);
344 logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
346 jpeg_finish_decompress(&cinfo);
347 if (reader) jpeg_memio_cleanup(&cinfo);
348 jpeg_destroy_decompress(&cinfo);
350 if (jerr.infile) fclose(jerr.infile);
352 logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done, x, y %u %u", area.w, area.h);
358 for (y = 0; y < numlines; y++)
360 p = bufferPointers[y];
362 for (x = 0; x < sfclen; x++)
366 // c = ( (0xFF000000 )
367 // | (p[xoff ] << 16)
368 // | (p[xoff + 1] << 8)
369 // | (p[xoff + 2] ) );
372 c.green = p[xoff + 1];
373 c.blue = p[xoff + 2];
375 drawPixel(x, y, w,h,xpos,ypos,c);
381 logger->log("BJpeg", Log::DEBUG, "deleted buffer");
385 ((SurfaceWin*)surface)->drawJpeg(fileName+1,offsetX,offsetY,&width,&height);//This should went into the abstract base classes?
386 //Windows has a problem with the leading / fixme
388 setDimensions(width, height);
395 ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
396 JpegReader *rd=(JpegReader *)cb;
397 return rd->readChunk(offset,size,buf);
400 //the memory buffer reader for the jpeg lib
401 //taken from jdatasrc.c
404 /* Expanded data source object for stdio input */
405 #include "jinclude.h"
407 #include "jerror.h"/* Expanded data source object for stdio input */
410 struct jpeg_source_mgr pub; /* public fields */
412 JOCTET * buffer; /* start of buffer */
413 boolean start_of_file; /* have we gotten any data yet? */
414 void * userdata; /* used for callback */
418 typedef my_source_mgr * my_src_ptr;
420 #define INPUT_BUF_SIZE (64*4096) /* choose an efficiently fread'able size */
424 * Initialize source --- called by jpeg_read_header
425 * before any data is actually read.
429 linit_source (j_decompress_ptr cinfo)
431 my_src_ptr src = (my_src_ptr) cinfo->src;
433 /* We reset the empty-input-file flag for each image,
434 * but we don't clear the input buffer.
435 * This is correct behavior for reading a series of images from one source.
437 src->start_of_file = TRUE;
443 * Fill the input buffer --- called whenever buffer is emptied.
445 * In typical applications, this should read fresh data into the buffer
446 * (ignoring the current state of next_input_byte & bytes_in_buffer),
447 * reset the pointer & count to the start of the buffer, and return TRUE
448 * indicating that the buffer has been reloaded. It is not necessary to
449 * fill the buffer entirely, only to obtain at least one more byte.
451 * There is no such thing as an EOF return. If the end of the file has been
452 * reached, the routine has a choice of ERREXIT() or inserting fake data into
453 * the buffer. In most cases, generating a warning message and inserting a
454 * fake EOI marker is the best course of action --- this will allow the
455 * decompressor to output however much of the image is there. However,
456 * the resulting error message is misleading if the real problem is an empty
457 * input file, so we handle that case specially.
459 * In applications that need to be able to suspend compression due to input
460 * not being available yet, a FALSE return indicates that no more data can be
461 * obtained right now, but more may be forthcoming later. In this situation,
462 * the decompressor will return to its caller (with an indication of the
463 * number of scanlines it has read, if any). The application should resume
464 * decompression after it has loaded more data into the input buffer. Note
465 * that there are substantial restrictions on the use of suspension --- see
468 * When suspending, the decompressor will back up to a convenient restart point
469 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
470 * indicate where the restart point will be if the current call returns FALSE.
471 * Data beyond this point must be rescanned after resumption, so move it to
472 * the front of the buffer rather than discarding it.
476 lfill_input_buffer (j_decompress_ptr cinfo)
478 my_src_ptr src = (my_src_ptr) cinfo->src;
480 if (src->buffer) free(src->buffer);
482 nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
485 WARNMS(cinfo, JWRN_JPEG_EOF);
486 src->buffer = (JOCTET *)malloc(2);
487 src->buffer[0] = (JOCTET) 0xFF;
488 src->buffer[1] = (JOCTET) JPEG_EOI;
494 src->pub.next_input_byte = src->buffer;
495 src->pub.bytes_in_buffer = nbytes;
496 src->start_of_file = FALSE;
503 * Skip data --- used to skip over a potentially large amount of
504 * uninteresting data (such as an APPn marker).
506 * Writers of suspendable-input applications must note that skip_input_data
507 * is not granted the right to give a suspension return. If the skip extends
508 * beyond the data currently in the buffer, the buffer can be marked empty so
509 * that the next read will cause a fill_input_buffer call that can suspend.
510 * Arranging for additional bytes to be discarded before reloading the input
511 * buffer is the application writer's problem.
515 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
517 my_src_ptr src = (my_src_ptr) cinfo->src;
519 /* Just a dumb implementation for now. Could use fseek() except
520 * it doesn't work on pipes. Not clear that being smart is worth
521 * any trouble anyway --- large skips are infrequent.
524 while (num_bytes > (long) src->pub.bytes_in_buffer) {
525 num_bytes -= (long) src->pub.bytes_in_buffer;
526 (void) lfill_input_buffer(cinfo);
527 /* note we assume that fill_input_buffer will never return FALSE,
528 * so suspension need not be handled.
531 src->pub.next_input_byte += (size_t) num_bytes;
532 src->pub.bytes_in_buffer -= (size_t) num_bytes;
538 * An additional method that can be provided by data source modules is the
539 * resync_to_restart method for error recovery in the presence of RST markers.
540 * For the moment, this source module just uses the default resync method
541 * provided by the JPEG library. That method assumes that no backtracking
547 * Terminate source --- called by jpeg_finish_decompress
548 * after all data has been read. Often a no-op.
550 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
551 * application must deal with any cleanup that should happen even
556 lterm_source (j_decompress_ptr cinfo)
558 /* no work necessary here */
563 * Prepare for input from a stdio stream.
564 * The caller must have already opened the stream, and is responsible
565 * for closing it after finishing decompression.
569 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
573 /* The source object and input buffer are made permanent so that a series
574 * of JPEG images can be read from the same file by calling jpeg_stdio_src
575 * only before the first one. (If we discarded the buffer at the end of
576 * one image, we'd likely lose the start of the next one.)
577 * This makes it unsafe to use this manager and a different source
578 * manager serially with the same JPEG object. Caveat programmer.
580 if (cinfo->src == NULL) { /* first time for this JPEG object? */
581 cinfo->src = (struct jpeg_source_mgr *)
582 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
583 SIZEOF(my_source_mgr));
584 src = (my_src_ptr) cinfo->src;
588 src = (my_src_ptr) cinfo->src;
589 src->pub.init_source = linit_source;
590 src->pub.fill_input_buffer = lfill_input_buffer;
591 src->pub.skip_input_data = lskip_input_data;
592 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
593 src->pub.term_source = lterm_source;
594 src->userdata=userdata;
595 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
596 src->pub.next_input_byte = NULL; /* until buffer loaded */
598 src->userdata=userdata;
604 /* cleanup to be called before cleanup of cinfo*/
606 jpeg_memio_cleanup (j_decompress_ptr cinfo) {
607 my_src_ptr src=(my_src_ptr)cinfo->src;
608 Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
609 if (src && src->buffer) {