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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "wjpegcomplex.h"
23 #include <sys/types.h>
45 //#define EXTENDED_JPEGLIB
47 //a struct to store user data for the jpeg decompressor
50 WJpegComplex::JpegControl * ctl;
58 //the scale factors supported by the jpeg lib
66 struct scale jpegFactors[]={
67 #ifndef EXTENDED_JPEGLIB
68 {1,1},{1,2},{1,4},{1,8}
70 {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
76 #define LocalReader WindowsResourceJpegReader
77 class WindowsResourceJpegReader: public JpegReader {
79 virtual ULONG initRead(const char *filename);
80 virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
81 virtual ULONG getSize();
82 virtual ~WindowsResourceJpegReader();
89 ULONG WindowsResourceJpegReader::initRead(const char *filename)
91 HRSRC res=FindResource(NULL,filename,RT_RCDATA);
92 hres=LoadResource(NULL,res);
93 buffer=LockResource(hres);
94 size=SizeofResource(NULL,res);
99 ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
101 if (offset>size) return 0;
102 ULONG toread=min(size-offset,len);
103 char* buffy=(char*)malloc(toread);
104 memcpy(buffy,((char*)buffer)+offset,toread);
109 WindowsResourceJpegReader::~WindowsResourceJpegReader(){
115 ULONG WindowsResourceJpegReader::getSize(){
120 #define LocalReader LocalJpegReader
121 class LocalJpegReader: public JpegReader {
123 virtual ULONG initRead(const char *filename);
124 virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
125 virtual ~LocalJpegReader();
126 virtual ULONG getSize();
133 LocalJpegReader::LocalJpegReader(){
138 ULONG LocalJpegReader::initRead(const char *filename)
140 if (file) fclose(file);
142 file=fopen(filename,"r");
145 if (fstat(fileno(file), &st) != 0) return 0;
149 Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
153 ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
158 ULLONG cpos=ftell(file);
159 if (offset != cpos) {
160 fseek(file,offset-cpos,SEEK_CUR);
162 if (offset != (ULONG)ftell(file)) {
163 Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
166 *buf=(char *)malloc(len);
168 Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
171 bread=fread(*buf,1,len,file);
178 LocalJpegReader::~LocalJpegReader(){
179 if (file) fclose(file);
182 ULONG LocalJpegReader::getSize(){
188 /*----------------------------------------------------------------
189 the jpeg lib routines
190 ----------------------------------------------------------------
196 struct my_error_mgr {
197 struct jpeg_error_mgr pub; /* "public" fields */
199 jmp_buf setjmp_buffer; /* for return to caller */
202 typedef struct my_error_mgr * my_error_ptr;
205 * Here's the routine that will replace the standard error_exit method:
209 my_error_exit (j_common_ptr cinfo)
211 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
212 my_error_ptr myerr = (my_error_ptr) cinfo->err;
214 /* Always display the message. */
215 /* We could postpone this until after returning, if we chose. */
216 (*cinfo->err->output_message) (cinfo);
217 /* Return control to the setjmp point */
218 longjmp(myerr->setjmp_buffer, 1);
221 ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
222 jpegUserData *user=(jpegUserData *)cb;
223 return user->reader->readChunk(offset,size,buf);
225 //the memory buffer reader for the jpeg lib
226 //taken from jdatasrc.c
228 #include "jinclude.h"
234 struct jpeg_source_mgr pub; /* public fields */
236 JOCTET * buffer; /* start of buffer */
237 boolean start_of_file; /* have we gotten any data yet? */
238 void * userdata; /* used for callback */
242 typedef my_source_mgr * my_src_ptr;
244 #define INPUT_BUF_SIZE (64*4096) /* choose an efficiently fread'able size */
248 * Initialize source --- called by jpeg_read_header
249 * before any data is actually read.
253 linit_source (j_decompress_ptr cinfo)
255 my_src_ptr src = (my_src_ptr) cinfo->src;
257 /* We reset the empty-input-file flag for each image,
258 * but we don't clear the input buffer.
259 * This is correct behavior for reading a series of images from one source.
261 src->start_of_file = TRUE;
267 * Fill the input buffer --- called whenever buffer is emptied.
269 * In typical applications, this should read fresh data into the buffer
270 * (ignoring the current state of next_input_byte & bytes_in_buffer),
271 * reset the pointer & count to the start of the buffer, and return TRUE
272 * indicating that the buffer has been reloaded. It is not necessary to
273 * fill the buffer entirely, only to obtain at least one more byte.
275 * There is no such thing as an EOF return. If the end of the file has been
276 * reached, the routine has a choice of ERREXIT() or inserting fake data into
277 * the buffer. In most cases, generating a warning message and inserting a
278 * fake EOI marker is the best course of action --- this will allow the
279 * decompressor to output however much of the image is there. However,
280 * the resulting error message is misleading if the real problem is an empty
281 * input file, so we handle that case specially.
283 * In applications that need to be able to suspend compression due to input
284 * not being available yet, a FALSE return indicates that no more data can be
285 * obtained right now, but more may be forthcoming later. In this situation,
286 * the decompressor will return to its caller (with an indication of the
287 * number of scanlines it has read, if any). The application should resume
288 * decompression after it has loaded more data into the input buffer. Note
289 * that there are substantial restrictions on the use of suspension --- see
292 * When suspending, the decompressor will back up to a convenient restart point
293 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
294 * indicate where the restart point will be if the current call returns FALSE.
295 * Data beyond this point must be rescanned after resumption, so move it to
296 * the front of the buffer rather than discarding it.
300 lfill_input_buffer (j_decompress_ptr cinfo)
302 my_src_ptr src = (my_src_ptr) cinfo->src;
304 if (src->buffer) free(src->buffer);
306 nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
309 WARNMS(cinfo, JWRN_JPEG_EOF);
310 src->buffer = (JOCTET *)malloc(2);
311 src->buffer[0] = (JOCTET) 0xFF;
312 src->buffer[1] = (JOCTET) JPEG_EOI;
318 src->pub.next_input_byte = src->buffer;
319 src->pub.bytes_in_buffer = nbytes;
320 src->start_of_file = FALSE;
327 * Skip data --- used to skip over a potentially large amount of
328 * uninteresting data (such as an APPn marker).
330 * Writers of suspendable-input applications must note that skip_input_data
331 * is not granted the right to give a suspension return. If the skip extends
332 * beyond the data currently in the buffer, the buffer can be marked empty so
333 * that the next read will cause a fill_input_buffer call that can suspend.
334 * Arranging for additional bytes to be discarded before reloading the input
335 * buffer is the application writer's problem.
339 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
341 my_src_ptr src = (my_src_ptr) cinfo->src;
343 /* Just a dumb implementation for now. Could use fseek() except
344 * it doesn't work on pipes. Not clear that being smart is worth
345 * any trouble anyway --- large skips are infrequent.
348 while (num_bytes > (long) src->pub.bytes_in_buffer) {
349 num_bytes -= (long) src->pub.bytes_in_buffer;
350 (void) lfill_input_buffer(cinfo);
351 /* note we assume that fill_input_buffer will never return FALSE,
352 * so suspension need not be handled.
355 src->pub.next_input_byte += (size_t) num_bytes;
356 src->pub.bytes_in_buffer -= (size_t) num_bytes;
362 * An additional method that can be provided by data source modules is the
363 * resync_to_restart method for error recovery in the presence of RST markers.
364 * For the moment, this source module just uses the default resync method
365 * provided by the JPEG library. That method assumes that no backtracking
371 * Terminate source --- called by jpeg_finish_decompress
372 * after all data has been read. Often a no-op.
374 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
375 * application must deal with any cleanup that should happen even
380 lterm_source (j_decompress_ptr cinfo)
382 /* no work necessary here */
387 * Prepare for input from a stdio stream.
388 * The caller must have already opened the stream, and is responsible
389 * for closing it after finishing decompression.
393 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
397 /* The source object and input buffer are made permanent so that a series
398 * of JPEG images can be read from the same file by calling jpeg_stdio_src
399 * only before the first one. (If we discarded the buffer at the end of
400 * one image, we'd likely lose the start of the next one.)
401 * This makes it unsafe to use this manager and a different source
402 * manager serially with the same JPEG object. Caveat programmer.
404 if (cinfo->src == NULL) { /* first time for this JPEG object? */
405 cinfo->src = (struct jpeg_source_mgr *)
406 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
407 SIZEOF(my_source_mgr));
408 src = (my_src_ptr) cinfo->src;
412 src = (my_src_ptr) cinfo->src;
413 src->pub.init_source = linit_source;
414 src->pub.fill_input_buffer = lfill_input_buffer;
415 src->pub.skip_input_data = lskip_input_data;
416 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
417 src->pub.term_source = lterm_source;
418 src->userdata=userdata;
419 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
420 src->pub.next_input_byte = NULL; /* until buffer loaded */
422 src->userdata=userdata;
428 /* cleanup to be called before cleanup of cinfo*/
430 jpeg_memio_cleanup (j_decompress_ptr cinfo) {
431 my_src_ptr src=(my_src_ptr)cinfo->src;
432 Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
433 if (src && src->buffer) {
440 //http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
442 #define GET2BYTES(cinfo, V, swap, offset) do { \
443 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
444 cinfo->src->bytes_in_buffer--; \
445 V = (*cinfo->src->next_input_byte++) << (swap?0:8); \
446 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
447 cinfo->src->bytes_in_buffer--; \
448 V += (*cinfo->src->next_input_byte++) << (swap?8:0); \
449 offset += 2; } while(0)
451 #define GET4BYTES(cinfo, V, swap, offset) do { \
452 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
453 cinfo->src->bytes_in_buffer--; \
454 V = (*cinfo->src->next_input_byte++) << (swap?0:24); \
455 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
456 cinfo->src->bytes_in_buffer--; \
457 V += (*cinfo->src->next_input_byte++) << (swap?8:16); \
458 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
459 cinfo->src->bytes_in_buffer--; \
460 V += (*cinfo->src->next_input_byte++) << (swap?16:8); \
461 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
462 cinfo->src->bytes_in_buffer--; \
463 V += (*cinfo->src->next_input_byte++) << (swap?24:0); \
464 offset += 4; } while(0)
467 get_exif_orient (j_decompress_ptr cinfo)
468 /* Get the Exif orientation info */
470 unsigned int tmp, offset, length, numtags;
476 my_src_ptr mysrc = (my_src_ptr) cinfo->src;
479 GET2BYTES(cinfo, length, 0, offset);
480 if (length<8) goto err;
482 GET4BYTES(cinfo, tmp, 0, offset);
483 if (tmp != 0x45786966) goto err;
484 GET2BYTES(cinfo, tmp, 0, offset);
485 if (tmp != 0x0000) goto err;
487 GET2BYTES(cinfo, tmp, 0, offset);
488 if (tmp == 0x4949) swap = 1;
489 else if (tmp == 0x4d4d) swap = 0;
491 GET2BYTES(cinfo, tmp, swap, offset);
492 if (tmp != 0x002A) goto err;
493 /* offset to first IFD */
494 GET4BYTES(cinfo, tmp, swap, offset);
496 (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
497 /* number of tags in IFD */
498 GET2BYTES(cinfo, numtags, swap, offset);
499 if (numtags == 0) goto err;
501 /* Search for Orientation Tag in IFD0 */
503 if (offset > length-12) goto err;
504 GET2BYTES(cinfo, tmp, swap, offset);
505 if (tmp == 0x0112) break; /* found Orientation Tag */
506 if (--numtags == 0) goto err;
508 (*mysrc->pub.skip_input_data)(cinfo, 10);
511 (*mysrc->pub.skip_input_data)(cinfo, 6);
512 GET2BYTES(cinfo, orient, swap, offset);
513 if( orient==0 || orient>8 ) orient = 1;
515 Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
516 ud=(jpegUserData *)(mysrc->userdata);
519 ud->ctl->exifRotation=WJpegComplex::ROT_180;
522 ud->ctl->exifRotation=WJpegComplex::ROT_90;
525 ud->ctl->exifRotation=WJpegComplex::ROT_270;
530 (*mysrc->pub.skip_input_data)(cinfo, length-offset);
535 /*----------------------------------------------------------------
537 ----------------------------------------------------------------
541 WJpegComplex::WJpegComplex(){
547 WJpegComplex::~WJpegComplex() {
548 if (owningReader && reader) delete reader;
551 int WJpegComplex::init(const char* tfileName)
553 if (owningReader && reader) delete reader;
554 errbuf[0]=0; //clean error state
555 LocalReader *myreader=new LocalReader();
558 ULONG psize=myreader->initRead(tfileName);
563 SNPRINTF(errbuf,200,"unable to open %s",tfileName);
572 bool WJpegComplex::hasError() {
573 return (errbuf[0] != 0);
575 void WJpegComplex::draw()
581 Surface *sfc=getSurface(myRegion);
586 if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
589 SNPRINTF(errbuf,200,"jpeg reader not initialized");
592 drawTextCentre(tr("Jpeg ERROR"), 240, 170, DrawStyle::LIGHTTEXT);
593 if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, DrawStyle::LIGHTTEXT);
594 if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, DrawStyle::LIGHTTEXT);
601 the main drawing function
602 this will read the pciture via the reader
603 and draw directly into the surface
604 it will compute an appropriate scale and set the infos in the
605 JpegControl structure
610 bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, DrawStyle & backgroundColour) {
611 Log* logger = Log::getInstance();
612 if (! rdr || ! sfc) {
613 logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
616 logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
617 unsigned char* buffer =NULL;
618 struct jpeg_decompress_struct cinfo;
619 struct my_error_mgr jerr;
620 cinfo.err = jpeg_std_error(&jerr.pub);
621 jerr.pub.error_exit = my_error_exit;
622 /* Establish the setjmp return context for my_error_exit to use. */
623 if (setjmp(jerr.setjmp_buffer)) {
624 /* If we get here, the JPEG code has signaled an error.
625 * We need to clean up the JPEG object, close the input file, and return.
627 if (rdr) jpeg_memio_cleanup(&cinfo);
628 jpeg_destroy_decompress(&cinfo);
629 logger->log("BJpeg", Log::ERR, "JPEG error");
630 if (buffer) free(buffer);
633 jpegUserData userdata;
636 jpeg_create_decompress(&cinfo);
639 ctl->exifRotation=ROT_0;
642 //create the input for the jpeg lib
643 jpeg_memio_src(&cinfo,(void *)(&userdata));
644 //processor for EXIF data
645 jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
646 //read in header info
647 jpeg_read_header(&cinfo, TRUE);
648 ctl->picw=cinfo.image_width;
649 ctl->pich=cinfo.image_height;
650 ctl->compressedSize=rdr->getSize();
651 //now we have important info available in ctl (pictuerw,h, exif orientation,size)
652 //compute rotation due to the defined enum values we can simply add them
653 ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
654 logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
655 //now we have to compute the scale
656 //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
657 // list of available jpeg scale factors
658 //out: scalenum,scaledenom,scaleafter
660 UINT picturew=ctl->picw;
661 UINT pictureh=ctl->pich;
662 switch (ctl->finalRotation){
674 if (! ctl->enlarge) {
675 //scale - compute the factors to fit 100%
676 int scalew=1000*picturew/ctl->area.w;
677 int scaleh=1000*pictureh/ctl->area.h;
679 if (scalew > scaleh) scale=scalew;
681 //OK now find out which is the optimal setting
682 //rule: find settings being nearest to:
683 // mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
684 // mode=CROP - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
685 // mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
686 // scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
687 //the scalefactor computes as scalenum/(scaledenom*scaleafter)
690 logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
691 ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter);
692 for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
693 for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
694 int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
696 logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d",
697 curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
700 if (curf >= 1000 && curf < (minDiff +1000)) {
706 if (curf <= 1000 && curf > (1000-minDiff)) {
712 if (curf <= 10*(int)ctl->scaleAmount ) {
714 if (abs < 0) abs=-abs;
723 logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
724 scalenum=jpegFactors[j].num;
725 scaledenom=jpegFactors[j].denom;
730 ctl->scale=100*scalenum/(scaledenom*scaleafter);
732 logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
733 scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
735 cinfo.scale_denom=scaledenom;
736 cinfo.scale_num=scalenum;
740 //set drawing area according to picture
741 ctl->area.w=ctl->picw;
742 ctl->area.h=ctl->pich;
745 //now we know the scaling
746 //compute the scaled size and position
748 jpeg_start_decompress(&cinfo);
749 //picturew/h is now the output width from the decompressor and afterscaler
751 picturew=cinfo.output_width;
752 pictureh=cinfo.output_height;
753 if (scaleafter > 1) {
754 picturew=picturew/scaleafter;
755 pictureh=pictureh/scaleafter;
757 //if our image is smaller - center it
758 if (! ctl->enlarge) {
759 if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
761 xpos=(((int)ctl->area.w)-dim)/2;
763 ypos=(((int)ctl->area.h)-dim)/2;
766 xpos=(((int)ctl->area.w)-dim)/2;
768 ypos=(((int)ctl->area.h)-dim)/2;
775 //remember the jpeg dimensions for computing the buffer
776 UINT jpegwidth=cinfo.output_width;
777 UINT jpegheight=cinfo.output_height;
778 logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d",
779 picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
781 //fill the background
782 sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour);
784 //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
785 int linelen=jpegwidth*3;
788 buffer = (unsigned char*)malloc(jpegheight * linelen);
789 logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
790 if (buffer == NULL) {
791 if (rdr) jpeg_memio_cleanup(&cinfo);
792 jpeg_destroy_decompress(&cinfo);
793 logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
794 SNPRINTF(ctl->error,100,"no room for buffer");
800 //unsigned char lbuf[linelen];
801 unsigned char *lbuf=new unsigned char[linelen*scaleafter];
802 unsigned char * ptr=lbuf;
805 unsigned char * ptr=buffer;
811 sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
812 //so that performance, can be optimized
813 logger->log("BJpeg", Log::DEBUG, "start drawing ");
815 //factors to base 1024
817 if (scaleafter > 1) {
818 colincr=3*scaleafter-3;
819 fac=1024/(scaleafter*scaleafter);
821 logger->log("BJpeg", Log::DEBUG, "jpeg draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
822 while (cinfo.output_scanline < jpegheight)
824 // logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
825 rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
829 if (scaleafter > 1) {
830 if (rowsread % scaleafter != scaleafter-1) {
831 //this simple approach wold maybe forget scaleafter -1 lines at the end...
837 drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
844 logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
846 jpeg_finish_decompress(&cinfo);
847 jpeg_memio_cleanup(&cinfo);
848 jpeg_destroy_decompress(&cinfo);
850 logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
855 //Tell the surface, that we will draw a lot of pixel,
856 //so that performance, can be optimized
857 sfc->startFastDraw();
858 logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
859 unsigned char* p=buffer; //start of first row
860 UINT rowincr=linelen*scaleafter;
861 //for simplicity omit last line to avoid running out of buffer
862 for (y = 0; y < pictureh-1 ;y++)
864 drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
868 logger->log("BJpeg", Log::DEBUG, "end draw");
873 logger->log("BJpeg", Log::DEBUG, "deleted buffer");
879 bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, DrawStyle & backgroundColour) {
885 Surface * WJpegComplex::getSurface(Region & r) {
886 r.x=getRootBoxOffsetX();
887 r.y=getRootBoxOffsetY();
890 return Boxx::getSurface();