]> git.vomp.tv Git - vompclient.git/blob - wjpeg.cc
Rewritten vomp discovery protocol
[vompclient.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         jpegUserData * ud=0;
468         boolean swap;
469         orient = 1;
470         offset = 0;
471         my_src_ptr mysrc = (my_src_ptr) cinfo->src;
472
473         /* marker length */
474         GET2BYTES(cinfo, length, 0, offset);
475         if (length<8) goto err;
476         /* Exif header */
477         GET4BYTES(cinfo, tmp, 0, offset);
478         if (tmp != 0x45786966) goto err;
479         GET2BYTES(cinfo, tmp, 0, offset);
480         if (tmp != 0x0000) goto err;
481         /* Byte-order */
482         GET2BYTES(cinfo, tmp, 0, offset);
483         if (tmp == 0x4949) swap = 1;
484         else if (tmp == 0x4d4d) swap = 0;
485         else goto err;
486         GET2BYTES(cinfo, tmp, swap, offset);
487         if (tmp != 0x002A) goto err;
488         /* offset to first IFD */
489         GET4BYTES(cinfo, tmp, swap, offset);
490         offset += tmp-8;
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;
495         
496         /* Search for Orientation Tag in IFD0 */
497         for (;;) {
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;
502                 offset += 10;
503                 (*mysrc->pub.skip_input_data)(cinfo, 10);
504         }
505         offset += 6;
506         (*mysrc->pub.skip_input_data)(cinfo, 6);
507         GET2BYTES(cinfo, orient, swap, offset);
508         if( orient==0 || orient>8 ) orient = 1;
509         
510         Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
511         ud=(jpegUserData *)(mysrc->userdata);
512         switch(orient) {
513           case 3:
514             ud->ctl->exifRotation=WJpeg::ROT_180;
515             break;
516           case 6:
517             ud->ctl->exifRotation=WJpeg::ROT_90;
518             break;
519           case 8:
520             ud->ctl->exifRotation=WJpeg::ROT_270;
521             break;
522         }
523
524 err:
525         (*mysrc->pub.skip_input_data)(cinfo, length-offset);
526         return TRUE;
527 }
528 }
529
530 /*----------------------------------------------------------------
531   the implementation
532   ----------------------------------------------------------------
533  */
534
535
536 WJpeg::WJpeg(){
537   reader=NULL;
538   owningReader=false;
539   errbuf[0]=0;
540 }
541
542 WJpeg::~WJpeg() {
543   if (owningReader && reader) delete reader;
544 }
545
546 int WJpeg::init(char* tfileName)
547 {
548   if (owningReader && reader) delete reader;
549   errbuf[0]=0; //clean error state
550   LocalReader *myreader=new LocalReader();
551   reader=myreader;
552   owningReader=true;
553   ULONG psize=myreader->initRead(tfileName);
554   if (psize == 0) {
555     delete reader;
556     reader=NULL;
557     owningReader=false;
558     SNPRINTF(errbuf,200,"unable to open %s",tfileName);
559     return 0;
560   }
561   return 1;
562 }
563
564
565
566
567 bool WJpeg::hasError() {
568   return (errbuf[0] != 0);
569 }
570 void WJpeg::draw()
571 {
572   bool ok=false;
573   JpegControl ctl;
574   if (reader) {
575     Region myRegion;
576     Surface *sfc=getSurface(myRegion);
577     myRegion.w=area.w;
578     myRegion.h=area.h;
579     ctl.area=myRegion;
580     ctl.enlarge=true;
581     if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
582   }
583   else {
584     SNPRINTF(errbuf,200,"jpeg reader not initialized");
585   }
586   if (! ok) {
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);
590   }
591 }
592
593 /**
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
599 **/  
600
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");
605     return false;
606   }
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.
617      */
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);
622     return false;
623   }
624   jpegUserData userdata;
625   int xpos=0;
626   int ypos=0;
627   jpeg_create_decompress(&cinfo);
628   userdata.reader=rdr;
629   userdata.ctl=ctl;
630   ctl->exifRotation=ROT_0;
631   ctl->error[0]=0;
632   ctl->exifDate[0]=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
650
651   UINT picturew=ctl->picw;
652   UINT pictureh=ctl->pich;
653   switch (ctl->finalRotation){
654     case ROT_90:
655     case ROT_270:
656       pictureh=ctl->picw;
657       picturew=ctl->pich;
658       break;
659     default:
660       break;
661   }
662   UINT scalenum=1;
663   UINT scaledenom=1;
664   UINT scaleafter=1;
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;
669     int scale=scaleh;
670     if (scalew > scaleh) scale=scalew;
671
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)
679     scaledenom=8;
680     int minDiff=1000;
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);
686         bool setThis=false;
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);
689         switch(ctl->mode) {
690           case CROP:
691             if (curf >= 1000 && curf < (minDiff +1000)) {
692               setThis=true;
693               minDiff=curf-1000;
694             }
695             break;
696           case LETTER:
697             if (curf <= 1000 && curf > (1000-minDiff)) {
698               setThis=true;
699               minDiff=1000-curf;
700             }
701             break;
702           case CROPPERCENT:
703             if (curf <= 10*(int)ctl->scaleAmount ) {
704               int abs=curf-1000;
705               if (abs < 0) abs=-abs;
706               if (abs < minDiff) {
707                    setThis=true;
708                    minDiff=abs;
709               }
710             }
711             break;
712         }
713         if (setThis) {
714           logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
715           scalenum=jpegFactors[j].num;
716           scaledenom=jpegFactors[j].denom;
717           scaleafter=sa;
718         }
719       }
720     }
721     ctl->scale=100*scalenum/(scaledenom*scaleafter);
722
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);
725
726     cinfo.scale_denom=scaledenom;
727     cinfo.scale_num=scalenum;
728     }
729   else
730   {
731     //set drawing area according to picture
732     ctl->area.w=ctl->picw;
733     ctl->area.h=ctl->pich;
734   }
735
736   //now we know the scaling
737   //compute the scaled size and position
738
739   jpeg_start_decompress(&cinfo);
740   //picturew/h is now the output width from the decompressor and afterscaler
741   //this is unrotated 
742   picturew=cinfo.output_width;
743   pictureh=cinfo.output_height;
744   if (scaleafter > 1) {
745     picturew=picturew/scaleafter;
746     pictureh=pictureh/scaleafter;
747   }
748   //if our image is smaller - center it
749   if (! ctl->enlarge) {
750     if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
751       int dim=pictureh;
752       xpos=(((int)ctl->area.w)-dim)/2;
753       dim=picturew;
754       ypos=(((int)ctl->area.h)-dim)/2;
755     } else {
756       int dim=picturew;
757       xpos=(((int)ctl->area.w)-dim)/2;
758       dim=pictureh;
759       ypos=(((int)ctl->area.h)-dim)/2;
760     }
761     if (xpos <0) xpos=0;
762     if (ypos <0) ypos=0;
763   }
764   xpos+=ctl->area.x;
765   ypos+=ctl->area.y;
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);
771
772   //fill the background
773   sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
774
775   //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
776   int linelen=jpegwidth*3;
777 #ifdef USE_BUFFER
778   // MAKE THE 2D ARRAY
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");
786     return false;
787   }
788 #endif
789
790 #ifndef USE_BUFFER
791   //unsigned char lbuf[linelen];
792   unsigned char *lbuf=new unsigned char[linelen*scaleafter];
793   unsigned char * ptr=lbuf;
794   UINT outy=0;
795 #else
796   unsigned char * ptr=buffer;
797 #endif
798
799   int rowsread = 0;
800
801   Colour c;
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 ");
805   UINT colincr=0;
806   //factors to base 1024
807   UINT fac=1024;
808   if (scaleafter > 1) {
809      colincr=3*scaleafter-3;
810      fac=1024/(scaleafter*scaleafter);
811      }
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)
814   {
815 //  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
816     rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
817 #ifdef USE_BUFFER
818     ptr+=linelen;
819 #else
820     if (scaleafter > 1) {
821       if (rowsread % scaleafter != scaleafter-1) {
822         //this simple approach wold maybe forget scaleafter -1 lines at the end...
823         ptr+=linelen;
824         continue;
825       }
826       ptr=lbuf;
827     }
828     drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
829     outy++;
830     
831 #endif
832   }
833   sfc->endFastDraw();
834
835   logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
836
837   jpeg_finish_decompress(&cinfo);
838   jpeg_memio_cleanup(&cinfo);
839   jpeg_destroy_decompress(&cinfo);
840
841   logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
842   rdr->drawingDone();
843
844 #ifdef USE_BUFFER
845   UINT y;
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++)
854   {
855     drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
856     p+=rowincr;
857   }
858   sfc->endFastDraw();
859   logger->log("BJpeg", Log::DEBUG, "end draw");
860   free(buffer);
861 #else
862   delete[] lbuf;
863 #endif
864   logger->log("BJpeg", Log::DEBUG, "deleted buffer");
865   return true;
866 }
867
868 //get my own surface
869 Surface * WJpeg::getSurface(Region & r) {
870   r.x=getRootBoxOffsetX();
871   r.y=getRootBoxOffsetY();
872   r.w=area.w;
873   r.h=area.h;
874   return Boxx::getSurface();
875 }
876
877