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.
23 #include <sys/types.h>
41 //#define EXTENDED_JPEGLIB
43 //a struct to store user data for the jpeg decompressor
46 WJpeg::JpegControl * ctl;
54 //the scale factors supported by the jpeg lib
62 struct scale jpegFactors[]={
63 #ifndef EXTENDED_JPEGLIB
64 {1,1},{1,2},{1,4},{1,8}
66 {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
72 #define LocalReader WindowsResourceJpegReader
73 class WindowsResourceJpegReader: public JpegReader {
75 virtual ULONG initRead(const char *filename);
76 virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
77 virtual ULONG getSize();
78 virtual ~WindowsResourceJpegReader();
85 ULONG WindowsResourceJpegReader::initRead(const char *filename)
87 HRSRC res=FindResource(NULL,filename,RT_RCDATA);
88 hres=LoadResource(NULL,res);
89 buffer=LockResource(hres);
90 size=SizeofResource(NULL,res);
95 ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
97 if (offset>size) return 0;
98 ULONG toread=min(size-offset,len);
99 char* buffy=(char*)malloc(toread);
100 memcpy(buffy,((char*)buffer)+offset,toread);
105 WindowsResourceJpegReader::~WindowsResourceJpegReader(){
111 ULONG WindowsResourceJpegReader::getSize(){
116 #define LocalReader LocalJpegReader
117 class LocalJpegReader: public JpegReader {
119 virtual ULONG initRead(const char *filename);
120 virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
121 virtual ~LocalJpegReader();
122 virtual ULONG getSize();
129 LocalJpegReader::LocalJpegReader(){
134 ULONG LocalJpegReader::initRead(const char *filename)
136 if (file) fclose(file);
138 file=fopen(filename,"r");
141 if (fstat(fileno(file), &st) != 0) return 0;
145 Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
149 ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
154 ULLONG cpos=ftell(file);
155 if (offset != cpos) {
156 fseek(file,offset-cpos,SEEK_CUR);
158 if (offset != (ULONG)ftell(file)) {
159 Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
162 *buf=(char *)malloc(len);
164 Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
167 bread=fread(*buf,1,len,file);
174 LocalJpegReader::~LocalJpegReader(){
175 if (file) fclose(file);
178 ULONG LocalJpegReader::getSize(){
183 /*----------------------------------------------------------------
184 the jpeg lib routines
185 ----------------------------------------------------------------
191 struct my_error_mgr {
192 struct jpeg_error_mgr pub; /* "public" fields */
194 jmp_buf setjmp_buffer; /* for return to caller */
197 typedef struct my_error_mgr * my_error_ptr;
200 * Here's the routine that will replace the standard error_exit method:
204 my_error_exit (j_common_ptr cinfo)
206 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
207 my_error_ptr myerr = (my_error_ptr) cinfo->err;
209 /* Always display the message. */
210 /* We could postpone this until after returning, if we chose. */
211 (*cinfo->err->output_message) (cinfo);
212 /* Return control to the setjmp point */
213 longjmp(myerr->setjmp_buffer, 1);
216 ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
217 jpegUserData *user=(jpegUserData *)cb;
218 return user->reader->readChunk(offset,size,buf);
220 //the memory buffer reader for the jpeg lib
221 //taken from jdatasrc.c
223 #include "jinclude.h"
229 struct jpeg_source_mgr pub; /* public fields */
231 JOCTET * buffer; /* start of buffer */
232 boolean start_of_file; /* have we gotten any data yet? */
233 void * userdata; /* used for callback */
237 typedef my_source_mgr * my_src_ptr;
239 #define INPUT_BUF_SIZE (64*4096) /* choose an efficiently fread'able size */
243 * Initialize source --- called by jpeg_read_header
244 * before any data is actually read.
248 linit_source (j_decompress_ptr cinfo)
250 my_src_ptr src = (my_src_ptr) cinfo->src;
252 /* We reset the empty-input-file flag for each image,
253 * but we don't clear the input buffer.
254 * This is correct behavior for reading a series of images from one source.
256 src->start_of_file = TRUE;
262 * Fill the input buffer --- called whenever buffer is emptied.
264 * In typical applications, this should read fresh data into the buffer
265 * (ignoring the current state of next_input_byte & bytes_in_buffer),
266 * reset the pointer & count to the start of the buffer, and return TRUE
267 * indicating that the buffer has been reloaded. It is not necessary to
268 * fill the buffer entirely, only to obtain at least one more byte.
270 * There is no such thing as an EOF return. If the end of the file has been
271 * reached, the routine has a choice of ERREXIT() or inserting fake data into
272 * the buffer. In most cases, generating a warning message and inserting a
273 * fake EOI marker is the best course of action --- this will allow the
274 * decompressor to output however much of the image is there. However,
275 * the resulting error message is misleading if the real problem is an empty
276 * input file, so we handle that case specially.
278 * In applications that need to be able to suspend compression due to input
279 * not being available yet, a FALSE return indicates that no more data can be
280 * obtained right now, but more may be forthcoming later. In this situation,
281 * the decompressor will return to its caller (with an indication of the
282 * number of scanlines it has read, if any). The application should resume
283 * decompression after it has loaded more data into the input buffer. Note
284 * that there are substantial restrictions on the use of suspension --- see
287 * When suspending, the decompressor will back up to a convenient restart point
288 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
289 * indicate where the restart point will be if the current call returns FALSE.
290 * Data beyond this point must be rescanned after resumption, so move it to
291 * the front of the buffer rather than discarding it.
295 lfill_input_buffer (j_decompress_ptr cinfo)
297 my_src_ptr src = (my_src_ptr) cinfo->src;
299 if (src->buffer) free(src->buffer);
301 nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
304 WARNMS(cinfo, JWRN_JPEG_EOF);
305 src->buffer = (JOCTET *)malloc(2);
306 src->buffer[0] = (JOCTET) 0xFF;
307 src->buffer[1] = (JOCTET) JPEG_EOI;
313 src->pub.next_input_byte = src->buffer;
314 src->pub.bytes_in_buffer = nbytes;
315 src->start_of_file = FALSE;
322 * Skip data --- used to skip over a potentially large amount of
323 * uninteresting data (such as an APPn marker).
325 * Writers of suspendable-input applications must note that skip_input_data
326 * is not granted the right to give a suspension return. If the skip extends
327 * beyond the data currently in the buffer, the buffer can be marked empty so
328 * that the next read will cause a fill_input_buffer call that can suspend.
329 * Arranging for additional bytes to be discarded before reloading the input
330 * buffer is the application writer's problem.
334 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
336 my_src_ptr src = (my_src_ptr) cinfo->src;
338 /* Just a dumb implementation for now. Could use fseek() except
339 * it doesn't work on pipes. Not clear that being smart is worth
340 * any trouble anyway --- large skips are infrequent.
343 while (num_bytes > (long) src->pub.bytes_in_buffer) {
344 num_bytes -= (long) src->pub.bytes_in_buffer;
345 (void) lfill_input_buffer(cinfo);
346 /* note we assume that fill_input_buffer will never return FALSE,
347 * so suspension need not be handled.
350 src->pub.next_input_byte += (size_t) num_bytes;
351 src->pub.bytes_in_buffer -= (size_t) num_bytes;
357 * An additional method that can be provided by data source modules is the
358 * resync_to_restart method for error recovery in the presence of RST markers.
359 * For the moment, this source module just uses the default resync method
360 * provided by the JPEG library. That method assumes that no backtracking
366 * Terminate source --- called by jpeg_finish_decompress
367 * after all data has been read. Often a no-op.
369 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
370 * application must deal with any cleanup that should happen even
375 lterm_source (j_decompress_ptr cinfo)
377 /* no work necessary here */
382 * Prepare for input from a stdio stream.
383 * The caller must have already opened the stream, and is responsible
384 * for closing it after finishing decompression.
388 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
392 /* The source object and input buffer are made permanent so that a series
393 * of JPEG images can be read from the same file by calling jpeg_stdio_src
394 * only before the first one. (If we discarded the buffer at the end of
395 * one image, we'd likely lose the start of the next one.)
396 * This makes it unsafe to use this manager and a different source
397 * manager serially with the same JPEG object. Caveat programmer.
399 if (cinfo->src == NULL) { /* first time for this JPEG object? */
400 cinfo->src = (struct jpeg_source_mgr *)
401 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
402 SIZEOF(my_source_mgr));
403 src = (my_src_ptr) cinfo->src;
407 src = (my_src_ptr) cinfo->src;
408 src->pub.init_source = linit_source;
409 src->pub.fill_input_buffer = lfill_input_buffer;
410 src->pub.skip_input_data = lskip_input_data;
411 src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
412 src->pub.term_source = lterm_source;
413 src->userdata=userdata;
414 src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
415 src->pub.next_input_byte = NULL; /* until buffer loaded */
417 src->userdata=userdata;
423 /* cleanup to be called before cleanup of cinfo*/
425 jpeg_memio_cleanup (j_decompress_ptr cinfo) {
426 my_src_ptr src=(my_src_ptr)cinfo->src;
427 Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
428 if (src && src->buffer) {
435 //http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
437 #define GET2BYTES(cinfo, V, swap, offset) do { \
438 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
439 cinfo->src->bytes_in_buffer--; \
440 V = (*cinfo->src->next_input_byte++) << (swap?0:8); \
441 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
442 cinfo->src->bytes_in_buffer--; \
443 V += (*cinfo->src->next_input_byte++) << (swap?8:0); \
444 offset += 2; } while(0)
446 #define GET4BYTES(cinfo, V, swap, offset) do { \
447 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
448 cinfo->src->bytes_in_buffer--; \
449 V = (*cinfo->src->next_input_byte++) << (swap?0:24); \
450 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
451 cinfo->src->bytes_in_buffer--; \
452 V += (*cinfo->src->next_input_byte++) << (swap?8:16); \
453 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
454 cinfo->src->bytes_in_buffer--; \
455 V += (*cinfo->src->next_input_byte++) << (swap?16:8); \
456 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
457 cinfo->src->bytes_in_buffer--; \
458 V += (*cinfo->src->next_input_byte++) << (swap?24:0); \
459 offset += 4; } while(0)
462 get_exif_orient (j_decompress_ptr cinfo)
463 /* Get the Exif orientation info */
465 unsigned int tmp, offset, length, numtags;
471 my_src_ptr mysrc = (my_src_ptr) cinfo->src;
474 GET2BYTES(cinfo, length, 0, offset);
475 if (length<8) goto err;
477 GET4BYTES(cinfo, tmp, 0, offset);
478 if (tmp != 0x45786966) goto err;
479 GET2BYTES(cinfo, tmp, 0, offset);
480 if (tmp != 0x0000) goto err;
482 GET2BYTES(cinfo, tmp, 0, offset);
483 if (tmp == 0x4949) swap = 1;
484 else if (tmp == 0x4d4d) swap = 0;
486 GET2BYTES(cinfo, tmp, swap, offset);
487 if (tmp != 0x002A) goto err;
488 /* offset to first IFD */
489 GET4BYTES(cinfo, tmp, swap, offset);
491 (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
492 /* number of tags in IFD */
493 GET2BYTES(cinfo, numtags, swap, offset);
494 if (numtags == 0) goto err;
496 /* Search for Orientation Tag in IFD0 */
498 if (offset > length-12) goto err;
499 GET2BYTES(cinfo, tmp, swap, offset);
500 if (tmp == 0x0112) break; /* found Orientation Tag */
501 if (--numtags == 0) goto err;
503 (*mysrc->pub.skip_input_data)(cinfo, 10);
506 (*mysrc->pub.skip_input_data)(cinfo, 6);
507 GET2BYTES(cinfo, orient, swap, offset);
508 if( orient==0 || orient>8 ) orient = 1;
510 Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
511 ud=(jpegUserData *)(mysrc->userdata);
514 ud->ctl->exifRotation=WJpeg::ROT_180;
517 ud->ctl->exifRotation=WJpeg::ROT_90;
520 ud->ctl->exifRotation=WJpeg::ROT_270;
525 (*mysrc->pub.skip_input_data)(cinfo, length-offset);
530 /*----------------------------------------------------------------
532 ----------------------------------------------------------------
543 if (owningReader && reader) delete reader;
546 int WJpeg::init(char* tfileName)
548 if (owningReader && reader) delete reader;
549 errbuf[0]=0; //clean error state
550 LocalReader *myreader=new LocalReader();
553 ULONG psize=myreader->initRead(tfileName);
558 SNPRINTF(errbuf,200,"unable to open %s",tfileName);
567 bool WJpeg::hasError() {
568 return (errbuf[0] != 0);
576 Surface *sfc=getSurface(myRegion);
581 if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
584 SNPRINTF(errbuf,200,"jpeg reader not initialized");
587 drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);
588 if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, Colour::LIGHTTEXT);
589 if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, Colour::LIGHTTEXT);
594 the main drawing function
595 this will read the pciture via the reader
596 and draw directly into the surface
597 it will compute an appropriate scale and set the infos in the
598 JpegControl structure
601 bool WJpeg::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {
602 Log* logger = Log::getInstance();
603 if (! rdr || ! sfc) {
604 logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
607 logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
608 unsigned char* buffer =NULL;
609 struct jpeg_decompress_struct cinfo;
610 struct my_error_mgr jerr;
611 cinfo.err = jpeg_std_error(&jerr.pub);
612 jerr.pub.error_exit = my_error_exit;
613 /* Establish the setjmp return context for my_error_exit to use. */
614 if (setjmp(jerr.setjmp_buffer)) {
615 /* If we get here, the JPEG code has signaled an error.
616 * We need to clean up the JPEG object, close the input file, and return.
618 if (rdr) jpeg_memio_cleanup(&cinfo);
619 jpeg_destroy_decompress(&cinfo);
620 logger->log("BJpeg", Log::ERR, "JPEG error");
621 if (buffer) free(buffer);
624 jpegUserData userdata;
627 jpeg_create_decompress(&cinfo);
630 ctl->exifRotation=ROT_0;
633 //create the input for the jpeg lib
634 jpeg_memio_src(&cinfo,(void *)(&userdata));
635 //processor for EXIF data
636 jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
637 //read in header info
638 jpeg_read_header(&cinfo, TRUE);
639 ctl->picw=cinfo.image_width;
640 ctl->pich=cinfo.image_height;
641 ctl->compressedSize=rdr->getSize();
642 //now we have important info available in ctl (pictuerw,h, exif orientation,size)
643 //compute rotation due to the defined enum values we can simply add them
644 ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
645 logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
646 //now we have to compute the scale
647 //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
648 // list of available jpeg scale factors
649 //out: scalenum,scaledenom,scaleafter
651 UINT picturew=ctl->picw;
652 UINT pictureh=ctl->pich;
653 switch (ctl->finalRotation){
665 if (! ctl->enlarge) {
666 //scale - compute the factors to fit 100%
667 int scalew=1000*picturew/ctl->area.w;
668 int scaleh=1000*pictureh/ctl->area.h;
670 if (scalew > scaleh) scale=scalew;
672 //OK now find out which is the optimal setting
673 //rule: find settings being nearest to:
674 // mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
675 // mode=CROP - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
676 // mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
677 // scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
678 //the scalefactor computes as scalenum/(scaledenom*scaleafter)
681 logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
682 ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter);
683 for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
684 for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
685 int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
687 logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d",
688 curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
691 if (curf >= 1000 && curf < (minDiff +1000)) {
697 if (curf <= 1000 && curf > (1000-minDiff)) {
703 if (curf <= 10*(int)ctl->scaleAmount ) {
705 if (abs < 0) abs=-abs;
714 logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
715 scalenum=jpegFactors[j].num;
716 scaledenom=jpegFactors[j].denom;
721 ctl->scale=100*scalenum/(scaledenom*scaleafter);
723 logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
724 scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
726 cinfo.scale_denom=scaledenom;
727 cinfo.scale_num=scalenum;
731 //set drawing area according to picture
732 ctl->area.w=ctl->picw;
733 ctl->area.h=ctl->pich;
736 //now we know the scaling
737 //compute the scaled size and position
739 jpeg_start_decompress(&cinfo);
740 //picturew/h is now the output width from the decompressor and afterscaler
742 picturew=cinfo.output_width;
743 pictureh=cinfo.output_height;
744 if (scaleafter > 1) {
745 picturew=picturew/scaleafter;
746 pictureh=pictureh/scaleafter;
748 //if our image is smaller - center it
749 if (! ctl->enlarge) {
750 if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
752 xpos=(((int)ctl->area.w)-dim)/2;
754 ypos=(((int)ctl->area.h)-dim)/2;
757 xpos=(((int)ctl->area.w)-dim)/2;
759 ypos=(((int)ctl->area.h)-dim)/2;
766 //remember the jpeg dimensions for computing the buffer
767 UINT jpegwidth=cinfo.output_width;
768 UINT jpegheight=cinfo.output_height;
769 logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d",
770 picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
772 //fill the background
773 sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
775 //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
776 int linelen=jpegwidth*3;
779 buffer = (unsigned char*)malloc(jpegheight * linelen);
780 logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
781 if (buffer == NULL) {
782 if (rdr) jpeg_memio_cleanup(&cinfo);
783 jpeg_destroy_decompress(&cinfo);
784 logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
785 SNPRINTF(ctl->error,100,"no room for buffer");
791 //unsigned char lbuf[linelen];
792 unsigned char *lbuf=new unsigned char[linelen*scaleafter];
793 unsigned char * ptr=lbuf;
796 unsigned char * ptr=buffer;
802 sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
803 //so that performance, can be optimized
804 logger->log("BJpeg", Log::DEBUG, "start drawing ");
806 //factors to base 1024
808 if (scaleafter > 1) {
809 colincr=3*scaleafter-3;
810 fac=1024/(scaleafter*scaleafter);
812 logger->log("BJpeg", Log::DEBUG, "jpeg draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
813 while (cinfo.output_scanline < jpegheight)
815 // logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
816 rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
820 if (scaleafter > 1) {
821 if (rowsread % scaleafter != scaleafter-1) {
822 //this simple approach wold maybe forget scaleafter -1 lines at the end...
828 drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
835 logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
837 jpeg_finish_decompress(&cinfo);
838 jpeg_memio_cleanup(&cinfo);
839 jpeg_destroy_decompress(&cinfo);
841 logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
846 //Tell the surface, that we will draw a lot of pixel,
847 //so that performance, can be optimized
848 sfc->startFastDraw();
849 logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
850 unsigned char* p=buffer; //start of first row
851 UINT rowincr=linelen*scaleafter;
852 //for simplicity omit last line to avoid running out of buffer
853 for (y = 0; y < pictureh-1 ;y++)
855 drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
859 logger->log("BJpeg", Log::DEBUG, "end draw");
864 logger->log("BJpeg", Log::DEBUG, "deleted buffer");
869 Surface * WJpeg::getSurface(Region & r) {
870 r.x=getRootBoxOffsetX();
871 r.y=getRootBoxOffsetY();
874 return Boxx::getSurface();