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;
470 my_src_ptr mysrc = (my_src_ptr) cinfo->src;
473 GET2BYTES(cinfo, length, 0, offset);
474 if (length<8) goto err;
476 GET4BYTES(cinfo, tmp, 0, offset);
477 if (tmp != 0x45786966) goto err;
478 GET2BYTES(cinfo, tmp, 0, offset);
479 if (tmp != 0x0000) goto err;
481 GET2BYTES(cinfo, tmp, 0, offset);
482 if (tmp == 0x4949) swap = 1;
483 else if (tmp == 0x4d4d) swap = 0;
485 GET2BYTES(cinfo, tmp, swap, offset);
486 if (tmp != 0x002A) goto err;
487 /* offset to first IFD */
488 GET4BYTES(cinfo, tmp, swap, offset);
490 (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
491 /* number of tags in IFD */
492 GET2BYTES(cinfo, numtags, swap, offset);
493 if (numtags == 0) goto err;
495 /* Search for Orientation Tag in IFD0 */
497 if (offset > length-12) goto err;
498 GET2BYTES(cinfo, tmp, swap, offset);
499 if (tmp == 0x0112) break; /* found Orientation Tag */
500 if (--numtags == 0) goto err;
502 (*mysrc->pub.skip_input_data)(cinfo, 10);
505 (*mysrc->pub.skip_input_data)(cinfo, 6);
506 GET2BYTES(cinfo, orient, swap, offset);
507 if( orient==0 || orient>8 ) orient = 1;
509 Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
510 jpegUserData * ud=(jpegUserData *)(mysrc->userdata);
513 ud->ctl->exifRotation=WJpeg::ROT_180;
516 ud->ctl->exifRotation=WJpeg::ROT_90;
519 ud->ctl->exifRotation=WJpeg::ROT_270;
524 (*mysrc->pub.skip_input_data)(cinfo, length-offset);
529 /*----------------------------------------------------------------
531 ----------------------------------------------------------------
542 if (owningReader && reader) delete reader;
545 int WJpeg::init(char* tfileName)
547 if (owningReader && reader) delete reader;
548 errbuf[0]=0; //clean error state
549 LocalReader *myreader=new LocalReader();
552 ULONG psize=myreader->initRead(tfileName);
557 SNPRINTF(errbuf,200,"unable to open %s",tfileName);
566 bool WJpeg::hasError() {
567 return (errbuf[0] != 0);
575 Surface *sfc=getSurface(myRegion);
580 if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
583 SNPRINTF(errbuf,200,"jpeg reader not initialized");
586 drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);
587 if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, Colour::LIGHTTEXT);
588 if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, Colour::LIGHTTEXT);
593 the main drawing function
594 this will read the pciture via the reader
595 and draw directly into the surface
596 it will compute an appropriate scale and set the infos in the
597 JpegControl structure
600 bool WJpeg::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {
601 Log* logger = Log::getInstance();
602 if (! rdr || ! sfc) {
603 logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
606 logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
607 unsigned char* buffer =NULL;
608 struct jpeg_decompress_struct cinfo;
609 struct my_error_mgr jerr;
610 cinfo.err = jpeg_std_error(&jerr.pub);
611 jerr.pub.error_exit = my_error_exit;
612 /* Establish the setjmp return context for my_error_exit to use. */
613 if (setjmp(jerr.setjmp_buffer)) {
614 /* If we get here, the JPEG code has signaled an error.
615 * We need to clean up the JPEG object, close the input file, and return.
617 if (rdr) jpeg_memio_cleanup(&cinfo);
618 jpeg_destroy_decompress(&cinfo);
619 logger->log("BJpeg", Log::ERR, "JPEG error");
620 if (buffer) free(buffer);
623 jpegUserData userdata;
626 jpeg_create_decompress(&cinfo);
629 ctl->exifRotation=ROT_0;
632 //create the input for the jpeg lib
633 jpeg_memio_src(&cinfo,(void *)(&userdata));
634 //processor for EXIF data
635 jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
636 //read in header info
637 jpeg_read_header(&cinfo, TRUE);
638 ctl->picw=cinfo.image_width;
639 ctl->pich=cinfo.image_height;
640 ctl->compressedSize=rdr->getSize();
641 //now we have important info available in ctl (pictuerw,h, exif orientation,size)
642 //compute rotation due to the defined enum values we can simply add them
643 ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
644 logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
645 //now we have to compute the scale
646 //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
647 // list of available jpeg scale factors
648 //out: scalenum,scaledenom,scaleafter
650 UINT picturew=ctl->picw;
651 UINT pictureh=ctl->pich;
652 switch (ctl->finalRotation){
664 if (! ctl->enlarge) {
665 //scale - compute the factors to fit 100%
666 int scalew=1000*picturew/ctl->area.w;
667 int scaleh=1000*pictureh/ctl->area.h;
669 if (scalew > scaleh) scale=scalew;
671 //OK now find out which is the optimal setting
672 //rule: find settings being nearest to:
673 // mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
674 // mode=CROP - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
675 // mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
676 // scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
677 //the scalefactor computes as scalenum/(scaledenom*scaleafter)
680 logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
681 ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter);
682 for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
683 for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
684 int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
686 logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d",
687 curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
690 if (curf >= 1000 && curf < (minDiff +1000)) {
696 if (curf <= 1000 && curf > (1000-minDiff)) {
702 if (curf <= 10*(int)ctl->scaleAmount ) {
704 if (abs < 0) abs=-abs;
713 logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
714 scalenum=jpegFactors[j].num;
715 scaledenom=jpegFactors[j].denom;
720 ctl->scale=100*scalenum/(scaledenom*scaleafter);
722 logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
723 scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
725 cinfo.scale_denom=scaledenom;
726 cinfo.scale_num=scalenum;
730 //set drawing area according to picture
731 ctl->area.w=ctl->picw;
732 ctl->area.h=ctl->pich;
735 //now we know the scaling
736 //compute the scaled size and position
738 jpeg_start_decompress(&cinfo);
739 //picturew/h is now the output width from the decompressor and afterscaler
741 picturew=cinfo.output_width;
742 pictureh=cinfo.output_height;
743 if (scaleafter > 1) {
744 picturew=picturew/scaleafter;
745 pictureh=pictureh/scaleafter;
747 //if our image is smaller - center it
748 if (! ctl->enlarge) {
749 if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
751 xpos=(((int)ctl->area.w)-dim)/2;
753 ypos=(((int)ctl->area.h)-dim)/2;
756 xpos=(((int)ctl->area.w)-dim)/2;
758 ypos=(((int)ctl->area.h)-dim)/2;
765 //remember the jpeg dimensions for computing the buffer
766 UINT jpegwidth=cinfo.output_width;
767 UINT jpegheight=cinfo.output_height;
768 logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d",
769 picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
771 //fill the background
772 sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
774 //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
775 int linelen=jpegwidth*3;
778 buffer = (unsigned char*)malloc(jpegheight * linelen);
779 logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
780 if (buffer == NULL) {
781 if (rdr) jpeg_memio_cleanup(&cinfo);
782 jpeg_destroy_decompress(&cinfo);
783 logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
784 SNPRINTF(ctl->error,100,"no room for buffer");
790 //unsigned char lbuf[linelen];
791 unsigned char *lbuf=new unsigned char[linelen*scaleafter];
792 unsigned char * ptr=lbuf;
795 unsigned char * ptr=buffer;
801 sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
802 //so that performance, can be optimized
803 logger->log("BJpeg", Log::DEBUG, "start drawing ");
805 //factors to base 1024
807 if (scaleafter > 1) {
808 colincr=3*scaleafter-3;
809 fac=1024/(scaleafter*scaleafter);
811 logger->log("BJpeg", Log::DEBUG, "jpeg draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
812 while (cinfo.output_scanline < jpegheight)
814 // logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
815 rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
819 if (scaleafter > 1) {
820 if (rowsread % scaleafter != scaleafter-1) {
821 //this simple approach wold maybe forget scaleafter -1 lines at the end...
827 drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
834 logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
836 jpeg_finish_decompress(&cinfo);
837 jpeg_memio_cleanup(&cinfo);
838 jpeg_destroy_decompress(&cinfo);
840 logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
845 //Tell the surface, that we will draw a lot of pixel,
846 //so that performance, can be optimized
847 sfc->startFastDraw();
848 logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
849 unsigned char* p=buffer; //start of first row
850 UINT rowincr=linelen*scaleafter;
851 //for simplicity omit last line to avoid running out of buffer
852 for (y = 0; y < pictureh-1 ;y++)
854 drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
858 logger->log("BJpeg", Log::DEBUG, "end draw");
863 logger->log("BJpeg", Log::DEBUG, "deleted buffer");
868 Surface * WJpeg::getSurface(Region & r) {
869 r.x=getRootBoxOffsetX();
870 r.y=getRootBoxOffsetY();
873 return Boxx::getSurface();