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
27 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata);
29 jpeg_memio_cleanup (j_decompress_ptr cinfo);
34 useImageDimensions=true;
44 if (fileName) delete fileName;
47 int WJpeg::init(char* tfileName,bool useImage, JpegReader *rdr)
50 if (fileName) delete fileName;
53 fileName = new char[strlen(tfileName)+1];
54 strcpy(fileName,tfileName);
57 useImageDimensions=useImage;
62 ULONG WJpeg::getJpegInfo(ULONG tag){
83 int WJpeg::getJpegInfo(ULONG tag, char * buffer) {
86 strncpy(buffer,fileName,INFO_BUFFER-1);
87 buffer[INFO_BUFFER-1]=0;
94 void WJpeg::setRotate(int amount) {
101 struct my_error_mgr {
102 struct jpeg_error_mgr pub; /* "public" fields */
103 FILE *infile; /* to be used in error handler */
105 jmp_buf setjmp_buffer; /* for return to caller */
108 typedef struct my_error_mgr * my_error_ptr;
111 * Here's the routine that will replace the standard error_exit method:
115 my_error_exit (j_common_ptr cinfo)
117 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
118 my_error_ptr myerr = (my_error_ptr) cinfo->err;
120 /* Always display the message. */
121 /* We could postpone this until after returning, if we chose. */
122 (*cinfo->err->output_message) (cinfo);
123 if (myerr->infile) fclose(myerr->infile);
124 /* Return control to the setjmp point */
125 longjmp(myerr->setjmp_buffer, 1);
130 bool WJpeg::hasError() {
136 if (drawJpeg() != 0) {
138 drawTextCentre(tr("Jpeg ERROR"), 240, 180, Colour::LIGHTTEXT);
142 /* handle picture rotation
150 void WJpeg::drawPixel(int x, int y,int w,int h,int xpos, int ypos,Colour c){
173 if (xb < 0 || yb < 0 ) {
174 Log::getInstance()->log("WJpeg:drawPixel",Log::ERR,"pixpos < 0 x=%d, y=%d",xb,yb);
177 Box::drawPixel((UINT)xb,(UINT)yb,c);
180 int WJpeg::drawJpeg() {
182 Log* logger = Log::getInstance();
183 unsigned char* buffer =NULL;
184 struct jpeg_decompress_struct cinfo;
185 struct my_error_mgr jerr;
187 cinfo.err = jpeg_std_error(&jerr.pub);
188 jerr.pub.error_exit = my_error_exit;
189 /* Establish the setjmp return context for my_error_exit to use. */
190 if (setjmp(jerr.setjmp_buffer)) {
191 /* If we get here, the JPEG code has signaled an error.
192 * We need to clean up the JPEG object, close the input file, and return.
194 if (reader) jpeg_memio_cleanup(&cinfo);
195 jpeg_destroy_decompress(&cinfo);
196 logger->log("BJpeg", Log::ERR, "JPEG error");
197 if (buffer) free(buffer);
202 jpeg_create_decompress(&cinfo);
203 if (fileName && ! reader) {
204 jsize=0; //TODO: compute size for local files
205 jerr.infile=fopen(fileName, "r");
206 if (jerr.infile == NULL)
208 logger->log("BJpeg", Log::ERR, "Can't open JPEG");
209 jpeg_destroy_decompress(&cinfo);
212 logger->log("BJpeg", Log::DEBUG, "File opened");
213 jpeg_stdio_src(&cinfo, jerr.infile);
216 jsize=reader->initRead(fileName);
218 logger->log("BJpeg", Log::ERR, "Can't init JPEG transfer");
219 jpeg_destroy_decompress(&cinfo);
222 jpeg_memio_src(&cinfo,(void *)reader);
225 logger->log("BJpeg", Log::ERR, "neither filename nor reader set");
226 jpeg_destroy_decompress(&cinfo);
229 jpeg_read_header(&cinfo, TRUE);
230 logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", cinfo.image_width, cinfo.image_height, rotate);
231 int picturew=cinfo.image_width;
232 int pictureh=cinfo.image_height;
236 pictureh=cinfo.image_width;
237 picturew=cinfo.image_height;
240 if (! useImageDimensions) {
241 //scale - we can have factors 1,2,4,8
242 int scalew=getWidth()*1000/picturew;
243 int scaleh=getHeight()*1000/pictureh;
245 if (scalew < scaleh) scale=scalew;
247 //we allow for 10% bigger...
248 if (scale >= 900) fac=1;
249 else if (scale >= 450 ) fac=2;
250 else if (scale >= 225 ) fac=4;
251 cinfo.scale_denom=fac;
252 logger->log("BJpeg", Log::DEBUG, "JPEG scaling (1/1000) pw=%i ph=%i w=%i h=%i r=%i f=%i",
255 scalew,scaleh,scale,fac);
259 //remember picture parameters
263 jpeg_start_decompress(&cinfo);
264 //recompute width based on rotation (consider scale)
265 picturew=cinfo.output_width;
266 pictureh=cinfo.output_height;
270 pictureh=cinfo.output_width;
271 picturew=cinfo.output_height;
274 //if our image is smaller - center it
275 if (! useImageDimensions) {
276 xpos=(getWidth()-picturew)/2;
278 ypos=(getHeight()-pictureh)/2;
281 //center point for rotation
282 int w=cinfo.output_width;
283 int h=cinfo.output_height;
284 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);
287 if (useImageDimensions) setDimensions(picturew, pictureh);
288 fillColour(backgroundColour);
290 //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
291 int linelen=cinfo.output_width*3;
294 buffer = (unsigned char*)malloc(config.output_height * linelen);
295 logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, width = %i height = %i", buffer, cinfo.output_height, linelen);
296 if (buffer == NULL) {
297 if (reader) jpeg_memio_cleanup(&cinfo);
298 jpeg_destroy_decompress(&cinfo);
299 if (jerr.infile) fclose(jerr.infile);
300 logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
305 //unsigned char* bufferPointers[area.h];
306 //for(UINT ps = 0; ps < area.h; ps++) bufferPointers[ps] = buffer + (ps * area.w * 3);
308 logger->log("BJpeg", Log::DEBUG, "header w=%d,h=%d",cinfo.output_width,cinfo.output_height);
310 unsigned char lbuf[linelen];
311 unsigned char * ptr=lbuf;
313 unsigned char * ptr=buffer;
319 while (cinfo.output_scanline < cinfo.output_height)
321 // logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
322 rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
327 for (unsigned char * lp=ptr;lp < (ptr+linelen);lp+=3,x++) {
331 drawPixel(x, rowsread-1,w,h,xpos,ypos, c);
337 logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
339 jpeg_finish_decompress(&cinfo);
340 if (reader) jpeg_memio_cleanup(&cinfo);
341 jpeg_destroy_decompress(&cinfo);
343 if (jerr.infile) fclose(jerr.infile);
345 logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done, x, y %u %u", area.w, area.h);
351 for (y = 0; y < numlines; y++)
353 p = bufferPointers[y];
355 for (x = 0; x < sfclen; x++)
359 // c = ( (0xFF000000 )
360 // | (p[xoff ] << 16)
361 // | (p[xoff + 1] << 8)
362 // | (p[xoff + 2] ) );
365 c.green = p[xoff + 1];
366 c.blue = p[xoff + 2];
368 drawPixel(x, y, w,h,xpos,ypos,c);
374 logger->log("BJpeg", Log::DEBUG, "deleted buffer");
378 ((SurfaceWin*)surface)->drawJpeg(fileName+1,offsetX,offsetY,&width,&height);//This should went into the abstract base classes?
379 //Windows has a problem with the leading / fixme
381 setDimensions(width, height);
388 ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
389 JpegReader *rd=(JpegReader *)cb;
390 return rd->readChunk(offset,size,buf);
393 //the memory buffer reader for the jpeg lib
394 //taken from jdatasrc.c
397 /* Expanded data source object for stdio input */
398 #include "jinclude.h"
400 #include "jerror.h"/* Expanded data source object for stdio input */
403 struct jpeg_source_mgr pub; /* public fields */
405 JOCTET * buffer; /* start of buffer */
406 boolean start_of_file; /* have we gotten any data yet? */
407 void * userdata; /* used for callback */
411 typedef my_source_mgr * my_src_ptr;
413 #define INPUT_BUF_SIZE (64*4096) /* choose an efficiently fread'able size */
417 * Initialize source --- called by jpeg_read_header
418 * before any data is actually read.
422 linit_source (j_decompress_ptr cinfo)
424 my_src_ptr src = (my_src_ptr) cinfo->src;
426 /* We reset the empty-input-file flag for each image,
427 * but we don't clear the input buffer.
428 * This is correct behavior for reading a series of images from one source.
430 src->start_of_file = TRUE;
436 * Fill the input buffer --- called whenever buffer is emptied.
438 * In typical applications, this should read fresh data into the buffer
439 * (ignoring the current state of next_input_byte & bytes_in_buffer),
440 * reset the pointer & count to the start of the buffer, and return TRUE
441 * indicating that the buffer has been reloaded. It is not necessary to
442 * fill the buffer entirely, only to obtain at least one more byte.
444 * There is no such thing as an EOF return. If the end of the file has been
445 * reached, the routine has a choice of ERREXIT() or inserting fake data into
446 * the buffer. In most cases, generating a warning message and inserting a
447 * fake EOI marker is the best course of action --- this will allow the
448 * decompressor to output however much of the image is there. However,
449 * the resulting error message is misleading if the real problem is an empty
450 * input file, so we handle that case specially.
452 * In applications that need to be able to suspend compression due to input
453 * not being available yet, a FALSE return indicates that no more data can be
454 * obtained right now, but more may be forthcoming later. In this situation,
455 * the decompressor will return to its caller (with an indication of the
456 * number of scanlines it has read, if any). The application should resume
457 * decompression after it has loaded more data into the input buffer. Note
458 * that there are substantial restrictions on the use of suspension --- see
461 * When suspending, the decompressor will back up to a convenient restart point
462 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
463 * indicate where the restart point will be if the current call returns FALSE.
464 * Data beyond this point must be rescanned after resumption, so move it to
465 * the front of the buffer rather than discarding it.
469 lfill_input_buffer (j_decompress_ptr cinfo)
471 my_src_ptr src = (my_src_ptr) cinfo->src;
473 if (src->buffer) free(src->buffer);
475 nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
478 WARNMS(cinfo, JWRN_JPEG_EOF);
479 src->buffer = (JOCTET *)malloc(2);
480 src->buffer[0] = (JOCTET) 0xFF;
481 src->buffer[1] = (JOCTET) JPEG_EOI;
487 src->pub.next_input_byte = src->buffer;
488 src->pub.bytes_in_buffer = nbytes;
489 src->start_of_file = FALSE;
496 * Skip data --- used to skip over a potentially large amount of
497 * uninteresting data (such as an APPn marker).
499 * Writers of suspendable-input applications must note that skip_input_data
500 * is not granted the right to give a suspension return. If the skip extends
501 * beyond the data currently in the buffer, the buffer can be marked empty so
502 * that the next read will cause a fill_input_buffer call that can suspend.
503 * Arranging for additional bytes to be discarded before reloading the input
504 * buffer is the application writer's problem.
508 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
510 my_src_ptr src = (my_src_ptr) cinfo->src;
512 /* Just a dumb implementation for now. Could use fseek() except
513 * it doesn't work on pipes. Not clear that being smart is worth
514 * any trouble anyway --- large skips are infrequent.
517 while (num_bytes > (long) src->pub.bytes_in_buffer) {
518 num_bytes -= (long) src->pub.bytes_in_buffer;
519 (void) lfill_input_buffer(cinfo);
520 /* note we assume that fill_input_buffer will never return FALSE,
521 * so suspension need not be handled.
524 src->pub.next_input_byte += (size_t) num_bytes;
525 src->pub.bytes_in_buffer -= (size_t) num_bytes;
531 * An additional method that can be provided by data source modules is the
532 * resync_to_restart method for error recovery in the presence of RST markers.
533 * For the moment, this source module just uses the default resync method
534 * provided by the JPEG library. That method assumes that no backtracking
540 * Terminate source --- called by jpeg_finish_decompress
541 * after all data has been read. Often a no-op.
543 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
544 * application must deal with any cleanup that should happen even
549 lterm_source (j_decompress_ptr cinfo)
551 /* no work necessary here */
556 * Prepare for input from a stdio stream.
557 * The caller must have already opened the stream, and is responsible
558 * for closing it after finishing decompression.
562 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
566 /* The source object and input buffer are made permanent so that a series
567 * of JPEG images can be read from the same file by calling jpeg_stdio_src
568 * only before the first one. (If we discarded the buffer at the end of
569 * one image, we'd likely lose the start of the next one.)
570 * This makes it unsafe to use this manager and a different source
571 * manager serially with the same JPEG object. Caveat programmer.
573 if (cinfo->src == NULL) { /* first time for this JPEG object? */
574 cinfo->src = (struct jpeg_source_mgr *)
575 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
576 SIZEOF(my_source_mgr));
577 src = (my_src_ptr) cinfo->src;
581 src = (my_src_ptr) cinfo->src;
582 src->pub.init_source = linit_source;
583 src->pub.fill_input_buffer = lfill_input_buffer;
584 src->pub.skip_input_data = lskip_input_data;
585 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
586 src->pub.term_source = lterm_source;
587 src->userdata=userdata;
588 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
589 src->pub.next_input_byte = NULL; /* until buffer loaded */
591 src->userdata=userdata;
597 /* cleanup to be called before cleanup of cinfo*/
599 jpeg_memio_cleanup (j_decompress_ptr cinfo) {
600 my_src_ptr src=(my_src_ptr)cinfo->src;
601 Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
602 if (src && src->buffer) {