]> git.vomp.tv Git - vompclient-marten.git/blob - wjpeg.cc
*** empty log message ***
[vompclient-marten.git] / wjpeg.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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.
19 */
20 #include "boxx.h"
21 #include "wjpeg.h"
22 #include <setjmp.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #ifndef WIN32
26 #include <unistd.h>
27 #else
28
29 #endif
30
31 #include "i18n.h"
32 #include "log.h"
33 #include "surface.h"
34 extern "C"
35 {
36   #include <jpeglib.h>
37 }
38
39
40 //#define USE_BUFFER
41 //#define EXTENDED_JPEGLIB
42
43 //a struct to store user data for the jpeg decompressor
44 class jpegUserData{
45   public:
46     WJpeg::JpegControl * ctl;
47     JpegReader *reader;
48     jpegUserData() {
49       ctl=NULL;
50       reader=NULL;
51       }
52   };
53
54 //the scale factors supported by the jpeg lib
55
56 struct scale{
57   UINT num;
58   UINT denom;
59 };
60
61
62 struct scale jpegFactors[]={
63 #ifndef EXTENDED_JPEGLIB
64   {1,1},{1,2},{1,4},{1,8}
65 #else
66   {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
67 #endif
68 };
69   
70
71 #ifdef WIN32
72 #define LocalReader WindowsResourceJpegReader
73 class WindowsResourceJpegReader: public JpegReader {
74   public:
75   virtual ULONG initRead(const char *filename);
76   virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
77   virtual ULONG getSize();
78   virtual ~WindowsResourceJpegReader();
79 protected:
80   HGLOBAL hres;
81   LPVOID buffer;
82   DWORD size;
83 };
84
85 ULONG WindowsResourceJpegReader::initRead(const char *filename)
86 {
87     HRSRC res=FindResource(NULL,filename,RT_RCDATA);
88     hres=LoadResource(NULL,res);
89     buffer=LockResource(hres);
90     size=SizeofResource(NULL,res);
91     //CloseHandle(hres);
92     return size;
93 }
94
95  ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
96 {
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);
101     *buf=buffy;
102     return toread;
103 }
104
105  WindowsResourceJpegReader::~WindowsResourceJpegReader(){
106     buffer=NULL;
107     size=0;
108     FreeResource(hres);
109  }
110
111  ULONG WindowsResourceJpegReader::getSize(){
112    return (ULONG)size;
113 }
114 #else
115
116 #define LocalReader LocalJpegReader
117 class LocalJpegReader: public JpegReader {
118   public:
119   virtual ULONG initRead(const char *filename);
120   virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
121   virtual ~LocalJpegReader();
122   virtual ULONG getSize();
123   LocalJpegReader();
124 protected:
125   FILE *file;
126   ULONG size;
127 };
128
129 LocalJpegReader::LocalJpegReader(){
130   file=NULL;
131   size=0;
132 }
133
134 ULONG LocalJpegReader::initRead(const char *filename)
135 {
136     if (file) fclose(file);
137     size=0;
138     file=fopen(filename,"r");
139     if (file) {
140       struct stat st;
141       if (fstat(fileno(file), &st) != 0) return 0;
142       size= st.st_size;
143       return size;
144     }
145     Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
146     return 0;
147 }
148
149 ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
150 {
151    *buf=NULL;
152    ULONG bread=0;
153    if (file) {
154      ULLONG cpos=ftell(file);
155      if (offset != cpos) {
156       fseek(file,offset-cpos,SEEK_CUR);
157      }
158      if (offset != (ULONG)ftell(file)) {
159        Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
160      }
161      else {
162        *buf=(char *)malloc(len);
163        if ( ! (*buf)) {
164          Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
165        }
166        else {
167          bread=fread(*buf,1,len,file);
168        }
169      }
170    }
171    return bread;
172 }
173
174 LocalJpegReader::~LocalJpegReader(){
175   if (file) fclose(file);
176   file=NULL;
177 }
178 ULONG LocalJpegReader::getSize(){
179   return size;
180 }
181 #endif
182
183 /*----------------------------------------------------------------
184   the jpeg lib routines
185   ----------------------------------------------------------------
186  */
187
188 extern "C" {
189
190
191 struct my_error_mgr {
192   struct jpeg_error_mgr pub;    /* "public" fields */
193
194   jmp_buf setjmp_buffer;        /* for return to caller */
195 };
196
197 typedef struct my_error_mgr * my_error_ptr;
198
199 /*
200  * Here's the routine that will replace the standard error_exit method:
201  */
202
203 METHODDEF(void)
204 my_error_exit (j_common_ptr cinfo)
205 {
206   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
207   my_error_ptr myerr = (my_error_ptr) cinfo->err;
208
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);
214 }
215
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);
219 }
220 //the memory buffer reader for the jpeg lib
221 //taken from jdatasrc.c
222
223 #include "jinclude.h"
224 #include "jpeglib.h"
225 #include "jerror.h"
226
227
228 typedef struct {
229   struct jpeg_source_mgr pub;   /* public fields */
230
231   JOCTET * buffer;              /* start of buffer */
232   boolean start_of_file;        /* have we gotten any data yet? */
233   void * userdata;              /* used for callback */
234   ULONG offset;
235 } my_source_mgr;
236
237 typedef my_source_mgr * my_src_ptr;
238
239 #define INPUT_BUF_SIZE  (64*4096)       /* choose an efficiently fread'able size */
240
241
242 /*
243  * Initialize source --- called by jpeg_read_header
244  * before any data is actually read.
245  */
246
247 METHODDEF(void)
248 linit_source (j_decompress_ptr cinfo)
249 {
250   my_src_ptr src = (my_src_ptr) cinfo->src;
251
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.
255    */
256   src->start_of_file = TRUE;
257   src->offset=0;
258 }
259
260
261 /*
262  * Fill the input buffer --- called whenever buffer is emptied.
263  *
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.
269  *
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.
277  *
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
285  * the documentation.
286  *
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.
292  */
293
294 METHODDEF(boolean)
295 lfill_input_buffer (j_decompress_ptr cinfo)
296 {
297   my_src_ptr src = (my_src_ptr) cinfo->src;
298   size_t nbytes;
299   if (src->buffer) free(src->buffer);
300   src->buffer=NULL;
301   nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
302
303   if (nbytes <= 0) {
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;
308     nbytes = 2;
309
310   }
311   src->offset+=nbytes;
312
313   src->pub.next_input_byte = src->buffer;
314   src->pub.bytes_in_buffer = nbytes;
315   src->start_of_file = FALSE;
316
317   return TRUE;
318 }
319
320
321 /*
322  * Skip data --- used to skip over a potentially large amount of
323  * uninteresting data (such as an APPn marker).
324  *
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.
331  */
332
333 METHODDEF(void)
334 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
335 {
336   my_src_ptr src = (my_src_ptr) cinfo->src;
337
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.
341    */
342   if (num_bytes > 0) {
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.
348        */
349     }
350     src->pub.next_input_byte += (size_t) num_bytes;
351     src->pub.bytes_in_buffer -= (size_t) num_bytes;
352   }
353 }
354
355
356 /*
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
361  * is possible.
362  */
363
364
365 /*
366  * Terminate source --- called by jpeg_finish_decompress
367  * after all data has been read.  Often a no-op.
368  *
369  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
370  * application must deal with any cleanup that should happen even
371  * for error exit.
372  */
373
374 METHODDEF(void)
375 lterm_source (j_decompress_ptr cinfo)
376 {
377   /* no work necessary here */
378 }
379
380
381 /*
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.
385  */
386
387 extern "C" void
388 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
389 {
390   my_src_ptr src;
391
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.
398    */
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;
404     src->buffer = NULL;
405   }
406
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 */
416   src->offset=0;
417   src->userdata=userdata;
418   if (src->buffer) {
419      free(src->buffer);
420      src->buffer=NULL;
421      }
422 }
423 /* cleanup to be called before cleanup of cinfo*/
424 extern "C" void
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) {
429     free(src->buffer);
430     src->buffer=NULL;
431     }
432 }
433
434 //taken from mvpmc
435 //http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
436
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) 
445
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)
460
461 static boolean
462 get_exif_orient (j_decompress_ptr cinfo)
463 /* Get the Exif orientation info */
464 {
465         unsigned int tmp, offset, length, numtags;
466         int orient=-1;
467         boolean swap;
468         orient = 1;
469         offset = 0;
470         my_src_ptr mysrc = (my_src_ptr) cinfo->src;
471
472         /* marker length */
473         GET2BYTES(cinfo, length, 0, offset);
474         if (length<8) goto err;
475         /* Exif header */
476         GET4BYTES(cinfo, tmp, 0, offset);
477         if (tmp != 0x45786966) goto err;
478         GET2BYTES(cinfo, tmp, 0, offset);
479         if (tmp != 0x0000) goto err;
480         /* Byte-order */
481         GET2BYTES(cinfo, tmp, 0, offset);
482         if (tmp == 0x4949) swap = 1;
483         else if (tmp == 0x4d4d) swap = 0;
484         else goto err;
485         GET2BYTES(cinfo, tmp, swap, offset);
486         if (tmp != 0x002A) goto err;
487         /* offset to first IFD */
488         GET4BYTES(cinfo, tmp, swap, offset);
489         offset += tmp-8;
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;
494         
495         /* Search for Orientation Tag in IFD0 */
496         for (;;) {
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;
501                 offset += 10;
502                 (*mysrc->pub.skip_input_data)(cinfo, 10);
503         }
504         offset += 6;
505         (*mysrc->pub.skip_input_data)(cinfo, 6);
506         GET2BYTES(cinfo, orient, swap, offset);
507         if( orient==0 || orient>8 ) orient = 1;
508         
509         Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
510         jpegUserData * ud=(jpegUserData *)(mysrc->userdata);
511         switch(orient) {
512           case 3:
513             ud->ctl->exifRotation=WJpeg::ROT_180;
514             break;
515           case 6:
516             ud->ctl->exifRotation=WJpeg::ROT_90;
517             break;
518           case 8:
519             ud->ctl->exifRotation=WJpeg::ROT_270;
520             break;
521         }
522
523 err:
524         (*mysrc->pub.skip_input_data)(cinfo, length-offset);
525         return TRUE;
526 }
527 }
528
529 /*----------------------------------------------------------------
530   the implementation
531   ----------------------------------------------------------------
532  */
533
534
535 WJpeg::WJpeg(){
536   reader=NULL;
537   owningReader=false;
538   errbuf[0]=0;
539 }
540
541 WJpeg::~WJpeg() {
542   if (owningReader && reader) delete reader;
543 }
544
545 int WJpeg::init(char* tfileName)
546 {
547   if (owningReader && reader) delete reader;
548   errbuf[0]=0; //clean error state
549   LocalReader *myreader=new LocalReader();
550   reader=myreader;
551   owningReader=true;
552   ULONG psize=myreader->initRead(tfileName);
553   if (psize == 0) {
554     delete reader;
555     reader=NULL;
556     owningReader=false;
557     SNPRINTF(errbuf,200,"unable to open %s",tfileName);
558     return 0;
559   }
560   return 1;
561 }
562
563
564
565
566 bool WJpeg::hasError() {
567   return (errbuf[0] != 0);
568 }
569 void WJpeg::draw()
570 {
571   bool ok=false;
572   JpegControl ctl;
573   if (reader) {
574     Region myRegion;
575     Surface *sfc=getSurface(myRegion);
576     myRegion.w=area.w;
577     myRegion.h=area.h;
578     ctl.area=myRegion;
579     ctl.enlarge=true;
580     if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
581   }
582   else {
583     SNPRINTF(errbuf,200,"jpeg reader not initialized");
584   }
585   if (! ok) {
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);
589   }
590 }
591
592 /**
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
598 **/  
599
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");
604     return false;
605   }
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.
616      */
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);
621     return false;
622   }
623   jpegUserData userdata;
624   int xpos=0;
625   int ypos=0;
626   jpeg_create_decompress(&cinfo);
627   userdata.reader=rdr;
628   userdata.ctl=ctl;
629   ctl->exifRotation=ROT_0;
630   ctl->error[0]=0;
631   ctl->exifDate[0]=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
649
650   UINT picturew=ctl->picw;
651   UINT pictureh=ctl->pich;
652   switch (ctl->finalRotation){
653     case ROT_90:
654     case ROT_270:
655       pictureh=ctl->picw;
656       picturew=ctl->pich;
657       break;
658     default:
659       break;
660   }
661   UINT scalenum=1;
662   UINT scaledenom=1;
663   UINT scaleafter=1;
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;
668     int scale=scaleh;
669     if (scalew > scaleh) scale=scalew;
670
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)
678     scaledenom=8;
679     int minDiff=1000;
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);
685         bool setThis=false;
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);
688         switch(ctl->mode) {
689           case CROP:
690             if (curf >= 1000 && curf < (minDiff +1000)) {
691               setThis=true;
692               minDiff=curf-1000;
693             }
694             break;
695           case LETTER:
696             if (curf <= 1000 && curf > (1000-minDiff)) {
697               setThis=true;
698               minDiff=1000-curf;
699             }
700             break;
701           case CROPPERCENT:
702             if (curf <= 10*(int)ctl->scaleAmount ) {
703               int abs=curf-1000;
704               if (abs < 0) abs=-abs;
705               if (abs < minDiff) {
706                    setThis=true;
707                    minDiff=abs;
708               }
709             }
710             break;
711         }
712         if (setThis) {
713           logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
714           scalenum=jpegFactors[j].num;
715           scaledenom=jpegFactors[j].denom;
716           scaleafter=sa;
717         }
718       }
719     }
720     ctl->scale=100*scalenum/(scaledenom*scaleafter);
721
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);
724
725     cinfo.scale_denom=scaledenom;
726     cinfo.scale_num=scalenum;
727     }
728   else
729   {
730     //set drawing area according to picture
731     ctl->area.w=ctl->picw;
732     ctl->area.h=ctl->pich;
733   }
734
735   //now we know the scaling
736   //compute the scaled size and position
737
738   jpeg_start_decompress(&cinfo);
739   //picturew/h is now the output width from the decompressor and afterscaler
740   //this is unrotated 
741   picturew=cinfo.output_width;
742   pictureh=cinfo.output_height;
743   if (scaleafter > 1) {
744     picturew=picturew/scaleafter;
745     pictureh=pictureh/scaleafter;
746   }
747   //if our image is smaller - center it
748   if (! ctl->enlarge) {
749     if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
750       int dim=pictureh;
751       xpos=(((int)ctl->area.w)-dim)/2;
752       dim=picturew;
753       ypos=(((int)ctl->area.h)-dim)/2;
754     } else {
755       int dim=picturew;
756       xpos=(((int)ctl->area.w)-dim)/2;
757       dim=pictureh;
758       ypos=(((int)ctl->area.h)-dim)/2;
759     }
760     if (xpos <0) xpos=0;
761     if (ypos <0) ypos=0;
762   }
763   xpos+=ctl->area.x;
764   ypos+=ctl->area.y;
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);
770
771   //fill the background
772   sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
773
774   //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
775   int linelen=jpegwidth*3;
776 #ifdef USE_BUFFER
777   // MAKE THE 2D ARRAY
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");
785     return false;
786   }
787 #endif
788
789 #ifndef USE_BUFFER
790   //unsigned char lbuf[linelen];
791   unsigned char *lbuf=new unsigned char[linelen*scaleafter];
792   unsigned char * ptr=lbuf;
793   UINT outy=0;
794 #else
795   unsigned char * ptr=buffer;
796 #endif
797
798   int rowsread = 0;
799
800   Colour c;
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 ");
804   UINT colincr=0;
805   //factors to base 1024
806   UINT fac=1024;
807   if (scaleafter > 1) {
808      colincr=3*scaleafter-3;
809      fac=1024/(scaleafter*scaleafter);
810      }
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)
813   {
814 //  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
815     rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
816 #ifdef USE_BUFFER
817     ptr+=linelen;
818 #else
819     if (scaleafter > 1) {
820       if (rowsread % scaleafter != scaleafter-1) {
821         //this simple approach wold maybe forget scaleafter -1 lines at the end...
822         ptr+=linelen;
823         continue;
824       }
825       ptr=lbuf;
826     }
827     drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
828     outy++;
829     
830 #endif
831   }
832   sfc->endFastDraw();
833
834   logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
835
836   jpeg_finish_decompress(&cinfo);
837   jpeg_memio_cleanup(&cinfo);
838   jpeg_destroy_decompress(&cinfo);
839
840   logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
841   rdr->drawingDone();
842
843 #ifdef USE_BUFFER
844   UINT y;
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++)
853   {
854     drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
855     p+=rowincr;
856   }
857   sfc->endFastDraw();
858   logger->log("BJpeg", Log::DEBUG, "end draw");
859   free(buffer);
860 #else
861   delete[] lbuf;
862 #endif
863   logger->log("BJpeg", Log::DEBUG, "deleted buffer");
864   return true;
865 }
866
867 //get my own surface
868 Surface * WJpeg::getSurface(Region & r) {
869   r.x=getRootBoxOffsetX();
870   r.y=getRootBoxOffsetY();
871   r.w=area.w;
872   r.h=area.h;
873   return Boxx::getSurface();
874 }
875
876