]> git.vomp.tv Git - vompclient.git/blob - wjpeg.cc
Vogel Media Player 2008-11-28
[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 #include <unistd.h>
26
27
28 #include "i18n.h"
29 #include "log.h"
30 #include "surface.h"
31 extern "C"
32 {
33   #include <jpeglib.h>
34 }
35
36
37 //#define USE_BUFFER
38 //#define EXTENDED_JPEGLIB
39
40 //a struct to store user data for the jpeg decompressor
41 class jpegUserData{
42   public:
43     WJpeg::JpegControl * ctl;
44     JpegReader *reader;
45     jpegUserData() {
46       ctl=NULL;
47       reader=NULL;
48       }
49   };
50
51 //the scale factors supported by the jpeg lib
52
53 struct scale{
54   UINT num;
55   UINT denom;
56 };
57
58
59 struct scale jpegFactors[]={
60 #ifndef EXTENDED_JPEGLIB
61   {1,1},{1,2},{1,4},{1,8}
62 #else
63   {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
64 #endif
65 };
66   
67
68 #ifdef WIN32
69 #define LocalReader WindowsResourceJpegReader
70 class WindowsResourceJpegReader: public JpegReader {
71   public:
72   virtual ULONG initRead(const char *filename);
73   virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
74   virtual ULONG getSize();
75   virtual ~WindowsResourceJpegReader();
76 protected:
77   HGLOBAL hres;
78   LPVOID buffer;
79   DWORD size;
80 };
81
82 ULONG WindowsResourceJpegReader::initRead(const char *filename)
83 {
84     HRSRC res=FindResource(NULL,filename,RT_RCDATA);
85     hres=LoadResource(NULL,res);
86     buffer=LockResource(hres);
87     size=SizeofResource(NULL,res);
88     //CloseHandle(hres);
89     return size;
90 }
91
92  ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
93 {
94     if (offset>size) return 0;
95     ULONG toread=min(size-offset,len);
96     char* buffy=(char*)malloc(toread);
97     memcpy(buffy,((char*)buffer)+offset,toread);
98     *buf=buffy;
99     return toread;
100 }
101
102  WindowsResourceJpegReader::~WindowsResourceJpegReader(){
103     buffer=NULL;
104     size=0;
105     FreeResource(hres);
106
107  ULONG WindowsResourceJpegReader::getSize(){
108    return (ULONG)size;
109 }
110 #else
111 #define LocalReader LocalJpegReader
112 class LocalJpegReader: public JpegReader {
113   public:
114   virtual ULONG initRead(const char *filename);
115   virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
116   virtual ~LocalJpegReader();
117   virtual ULONG getSize();
118   LocalJpegReader();
119 protected:
120   FILE *file;
121   ULONG size;
122 };
123
124 LocalJpegReader::LocalJpegReader(){
125   file=NULL;
126   size=0;
127 }
128
129 ULONG LocalJpegReader::initRead(const char *filename)
130 {
131     if (file) fclose(file);
132     size=0;
133     file=fopen(filename,"r");
134     if (file) {
135       struct stat st;
136       if (fstat(fileno(file), &st) != 0) return 0;
137       size= st.st_size;
138       return size;
139     }
140     Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
141     return 0;
142 }
143
144 ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
145 {
146    *buf=NULL;
147    ULONG bread=0;
148    if (file) {
149      ULLONG cpos=ftell(file);
150      if (offset != cpos) {
151       fseek(file,offset-cpos,SEEK_CUR);
152      }
153      if (offset != (ULONG)ftell(file)) {
154        Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
155      }
156      else {
157        *buf=(char *)malloc(len);
158        if ( ! (*buf)) {
159          Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
160        }
161        else {
162          bread=fread(*buf,1,len,file);
163        }
164      }
165    }
166    return bread;
167 }
168
169 LocalJpegReader::~LocalJpegReader(){
170   if (file) fclose(file);
171   file=NULL;
172 }
173 ULONG LocalJpegReader::getSize(){
174   return size;
175 }
176 #endif
177
178 /*----------------------------------------------------------------
179   the jpeg lib routines
180   ----------------------------------------------------------------
181  */
182
183 extern "C" {
184
185
186 struct my_error_mgr {
187   struct jpeg_error_mgr pub;    /* "public" fields */
188
189   jmp_buf setjmp_buffer;        /* for return to caller */
190 };
191
192 typedef struct my_error_mgr * my_error_ptr;
193
194 /*
195  * Here's the routine that will replace the standard error_exit method:
196  */
197
198 METHODDEF(void)
199 my_error_exit (j_common_ptr cinfo)
200 {
201   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
202   my_error_ptr myerr = (my_error_ptr) cinfo->err;
203
204   /* Always display the message. */
205   /* We could postpone this until after returning, if we chose. */
206   (*cinfo->err->output_message) (cinfo);
207   /* Return control to the setjmp point */
208   longjmp(myerr->setjmp_buffer, 1);
209 }
210
211 ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
212   jpegUserData *user=(jpegUserData *)cb;
213   return user->reader->readChunk(offset,size,buf);
214 }
215 //the memory buffer reader for the jpeg lib
216 //taken from jdatasrc.c
217
218 #include "jinclude.h"
219 #include "jpeglib.h"
220 #include "jerror.h"
221
222
223 typedef struct {
224   struct jpeg_source_mgr pub;   /* public fields */
225
226   JOCTET * buffer;              /* start of buffer */
227   boolean start_of_file;        /* have we gotten any data yet? */
228   void * userdata;              /* used for callback */
229   ULONG offset;
230 } my_source_mgr;
231
232 typedef my_source_mgr * my_src_ptr;
233
234 #define INPUT_BUF_SIZE  (64*4096)       /* choose an efficiently fread'able size */
235
236
237 /*
238  * Initialize source --- called by jpeg_read_header
239  * before any data is actually read.
240  */
241
242 METHODDEF(void)
243 linit_source (j_decompress_ptr cinfo)
244 {
245   my_src_ptr src = (my_src_ptr) cinfo->src;
246
247   /* We reset the empty-input-file flag for each image,
248    * but we don't clear the input buffer.
249    * This is correct behavior for reading a series of images from one source.
250    */
251   src->start_of_file = TRUE;
252   src->offset=0;
253 }
254
255
256 /*
257  * Fill the input buffer --- called whenever buffer is emptied.
258  *
259  * In typical applications, this should read fresh data into the buffer
260  * (ignoring the current state of next_input_byte & bytes_in_buffer),
261  * reset the pointer & count to the start of the buffer, and return TRUE
262  * indicating that the buffer has been reloaded.  It is not necessary to
263  * fill the buffer entirely, only to obtain at least one more byte.
264  *
265  * There is no such thing as an EOF return.  If the end of the file has been
266  * reached, the routine has a choice of ERREXIT() or inserting fake data into
267  * the buffer.  In most cases, generating a warning message and inserting a
268  * fake EOI marker is the best course of action --- this will allow the
269  * decompressor to output however much of the image is there.  However,
270  * the resulting error message is misleading if the real problem is an empty
271  * input file, so we handle that case specially.
272  *
273  * In applications that need to be able to suspend compression due to input
274  * not being available yet, a FALSE return indicates that no more data can be
275  * obtained right now, but more may be forthcoming later.  In this situation,
276  * the decompressor will return to its caller (with an indication of the
277  * number of scanlines it has read, if any).  The application should resume
278  * decompression after it has loaded more data into the input buffer.  Note
279  * that there are substantial restrictions on the use of suspension --- see
280  * the documentation.
281  *
282  * When suspending, the decompressor will back up to a convenient restart point
283  * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
284  * indicate where the restart point will be if the current call returns FALSE.
285  * Data beyond this point must be rescanned after resumption, so move it to
286  * the front of the buffer rather than discarding it.
287  */
288
289 METHODDEF(boolean)
290 lfill_input_buffer (j_decompress_ptr cinfo)
291 {
292   my_src_ptr src = (my_src_ptr) cinfo->src;
293   size_t nbytes;
294   if (src->buffer) free(src->buffer);
295   src->buffer=NULL;
296   nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
297
298   if (nbytes <= 0) {
299     WARNMS(cinfo, JWRN_JPEG_EOF);
300     src->buffer =  (JOCTET *)malloc(2);
301     src->buffer[0] = (JOCTET) 0xFF;
302     src->buffer[1] = (JOCTET) JPEG_EOI;
303     nbytes = 2;
304
305   }
306   src->offset+=nbytes;
307
308   src->pub.next_input_byte = src->buffer;
309   src->pub.bytes_in_buffer = nbytes;
310   src->start_of_file = FALSE;
311
312   return TRUE;
313 }
314
315
316 /*
317  * Skip data --- used to skip over a potentially large amount of
318  * uninteresting data (such as an APPn marker).
319  *
320  * Writers of suspendable-input applications must note that skip_input_data
321  * is not granted the right to give a suspension return.  If the skip extends
322  * beyond the data currently in the buffer, the buffer can be marked empty so
323  * that the next read will cause a fill_input_buffer call that can suspend.
324  * Arranging for additional bytes to be discarded before reloading the input
325  * buffer is the application writer's problem.
326  */
327
328 METHODDEF(void)
329 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
330 {
331   my_src_ptr src = (my_src_ptr) cinfo->src;
332
333   /* Just a dumb implementation for now.  Could use fseek() except
334    * it doesn't work on pipes.  Not clear that being smart is worth
335    * any trouble anyway --- large skips are infrequent.
336    */
337   if (num_bytes > 0) {
338     while (num_bytes > (long) src->pub.bytes_in_buffer) {
339       num_bytes -= (long) src->pub.bytes_in_buffer;
340       (void) lfill_input_buffer(cinfo);
341       /* note we assume that fill_input_buffer will never return FALSE,
342        * so suspension need not be handled.
343        */
344     }
345     src->pub.next_input_byte += (size_t) num_bytes;
346     src->pub.bytes_in_buffer -= (size_t) num_bytes;
347   }
348 }
349
350
351 /*
352  * An additional method that can be provided by data source modules is the
353  * resync_to_restart method for error recovery in the presence of RST markers.
354  * For the moment, this source module just uses the default resync method
355  * provided by the JPEG library.  That method assumes that no backtracking
356  * is possible.
357  */
358
359
360 /*
361  * Terminate source --- called by jpeg_finish_decompress
362  * after all data has been read.  Often a no-op.
363  *
364  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
365  * application must deal with any cleanup that should happen even
366  * for error exit.
367  */
368
369 METHODDEF(void)
370 lterm_source (j_decompress_ptr cinfo)
371 {
372   /* no work necessary here */
373 }
374
375
376 /*
377  * Prepare for input from a stdio stream.
378  * The caller must have already opened the stream, and is responsible
379  * for closing it after finishing decompression.
380  */
381
382 extern "C" void
383 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
384 {
385   my_src_ptr src;
386
387   /* The source object and input buffer are made permanent so that a series
388    * of JPEG images can be read from the same file by calling jpeg_stdio_src
389    * only before the first one.  (If we discarded the buffer at the end of
390    * one image, we'd likely lose the start of the next one.)
391    * This makes it unsafe to use this manager and a different source
392    * manager serially with the same JPEG object.  Caveat programmer.
393    */
394   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
395     cinfo->src = (struct jpeg_source_mgr *)
396       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
397                                   SIZEOF(my_source_mgr));
398     src = (my_src_ptr) cinfo->src;
399     src->buffer = NULL;
400   }
401
402   src = (my_src_ptr) cinfo->src;
403   src->pub.init_source = linit_source;
404   src->pub.fill_input_buffer = lfill_input_buffer;
405   src->pub.skip_input_data = lskip_input_data;
406   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
407   src->pub.term_source = lterm_source;
408   src->userdata=userdata;
409   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
410   src->pub.next_input_byte = NULL; /* until buffer loaded */
411   src->offset=0;
412   src->userdata=userdata;
413   if (src->buffer) {
414      free(src->buffer);
415      src->buffer=NULL;
416      }
417 }
418 /* cleanup to be called before cleanup of cinfo*/
419 extern "C" void
420 jpeg_memio_cleanup (j_decompress_ptr cinfo) {
421   my_src_ptr src=(my_src_ptr)cinfo->src;
422   Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
423   if (src && src->buffer) {
424     free(src->buffer);
425     src->buffer=NULL;
426     }
427 }
428
429 //taken from mvpmc
430 //http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
431
432 #define GET2BYTES(cinfo, V, swap, offset) do { \
433                 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
434                 cinfo->src->bytes_in_buffer--; \
435                 V = (*cinfo->src->next_input_byte++) << (swap?0:8); \
436                 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
437                 cinfo->src->bytes_in_buffer--; \
438                 V += (*cinfo->src->next_input_byte++) << (swap?8:0); \
439                 offset += 2; } while(0) 
440
441 #define GET4BYTES(cinfo, V, swap, offset) do { \
442                 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
443                 cinfo->src->bytes_in_buffer--; \
444                 V = (*cinfo->src->next_input_byte++) << (swap?0:24); \
445                 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
446                 cinfo->src->bytes_in_buffer--; \
447                 V += (*cinfo->src->next_input_byte++) << (swap?8:16); \
448                 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
449                 cinfo->src->bytes_in_buffer--; \
450                 V += (*cinfo->src->next_input_byte++) << (swap?16:8); \
451                 if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
452                 cinfo->src->bytes_in_buffer--; \
453                 V += (*cinfo->src->next_input_byte++) << (swap?24:0); \
454                 offset += 4; } while(0)
455
456 static boolean
457 get_exif_orient (j_decompress_ptr cinfo)
458 /* Get the Exif orientation info */
459 {
460         unsigned int tmp, offset, length, numtags;
461         int orient=-1;
462         boolean swap;
463         orient = 1;
464         offset = 0;
465         my_src_ptr mysrc = (my_src_ptr) cinfo->src;
466
467         /* marker length */
468         GET2BYTES(cinfo, length, 0, offset);
469         if (length<8) goto err;
470         /* Exif header */
471         GET4BYTES(cinfo, tmp, 0, offset);
472         if (tmp != 0x45786966) goto err;
473         GET2BYTES(cinfo, tmp, 0, offset);
474         if (tmp != 0x0000) goto err;
475         /* Byte-order */
476         GET2BYTES(cinfo, tmp, 0, offset);
477         if (tmp == 0x4949) swap = 1;
478         else if (tmp == 0x4d4d) swap = 0;
479         else goto err;
480         GET2BYTES(cinfo, tmp, swap, offset);
481         if (tmp != 0x002A) goto err;
482         /* offset to first IFD */
483         GET4BYTES(cinfo, tmp, swap, offset);
484         offset += tmp-8;
485         (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
486         /* number of tags in IFD */
487         GET2BYTES(cinfo, numtags, swap, offset);
488         if (numtags == 0) goto err;
489         
490         /* Search for Orientation Tag in IFD0 */
491         for (;;) {
492                 if (offset > length-12) goto err;
493                 GET2BYTES(cinfo, tmp, swap, offset);
494                 if (tmp == 0x0112) break; /* found Orientation Tag */
495                 if (--numtags == 0) goto err;
496                 offset += 10;
497                 (*mysrc->pub.skip_input_data)(cinfo, 10);
498         }
499         offset += 6;
500         (*mysrc->pub.skip_input_data)(cinfo, 6);
501         GET2BYTES(cinfo, orient, swap, offset);
502         if( orient==0 || orient>8 ) orient = 1;
503         
504         Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
505         jpegUserData * ud=(jpegUserData *)(mysrc->userdata);
506         switch(orient) {
507           case 3:
508             ud->ctl->exifRotation=WJpeg::ROT_180;
509             break;
510           case 6:
511             ud->ctl->exifRotation=WJpeg::ROT_90;
512             break;
513           case 8:
514             ud->ctl->exifRotation=WJpeg::ROT_270;
515             break;
516         }
517
518 err:
519         (*mysrc->pub.skip_input_data)(cinfo, length-offset);
520         return TRUE;
521 }
522 }
523
524 /*----------------------------------------------------------------
525   the implementation
526   ----------------------------------------------------------------
527  */
528
529
530 WJpeg::WJpeg(){
531   reader=NULL;
532   owningReader=false;
533   errbuf[0]=0;
534 }
535
536 WJpeg::~WJpeg() {
537   if (owningReader && reader) delete reader;
538 }
539
540 int WJpeg::init(char* tfileName)
541 {
542   if (owningReader && reader) delete reader;
543   errbuf[0]=0; //clean error state
544   LocalReader *myreader=new LocalReader();
545   reader=myreader;
546   owningReader=true;
547   ULONG psize=myreader->initRead(tfileName);
548   if (psize == 0) {
549     delete reader;
550     reader=NULL;
551     owningReader=false;
552     snprintf(errbuf,200,"unable to open %s",tfileName);
553     return 0;
554   }
555   return 1;
556 }
557
558
559
560
561 bool WJpeg::hasError() {
562   return (errbuf[0] != 0);
563 }
564 void WJpeg::draw()
565 {
566   bool ok=false;
567   JpegControl ctl;
568   if (reader) {
569     Region myRegion;
570     Surface *sfc=getSurface(myRegion);
571     myRegion.w=area.w;
572     myRegion.h=area.h;
573     ctl.area=myRegion;
574     ctl.enlarge=true;
575     if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
576   }
577   else {
578     snprintf(errbuf,200,"jpeg reader not initialized");
579   }
580   if (! ok) {
581     drawTextCentre(tr("Jpeg ERROR"), 240, 170, Colour::LIGHTTEXT);
582     if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, Colour::LIGHTTEXT);
583     if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, Colour::LIGHTTEXT);
584   }
585 }
586
587 /**
588   the main drawing function
589   this will read the pciture via the reader
590   and draw directly into the surface
591   it will compute an appropriate scale and set the infos in the
592   JpegControl structure
593 **/  
594
595 bool WJpeg::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, Colour & backgroundColour) {
596   Log* logger = Log::getInstance();
597   if (! rdr || ! sfc) {
598     logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
599     return false;
600   }
601   logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
602   unsigned char* buffer =NULL;
603   struct jpeg_decompress_struct cinfo;
604   struct my_error_mgr jerr;
605   cinfo.err = jpeg_std_error(&jerr.pub);
606   jerr.pub.error_exit = my_error_exit;
607   /* Establish the setjmp return context for my_error_exit to use. */
608   if (setjmp(jerr.setjmp_buffer)) {
609     /* If we get here, the JPEG code has signaled an error.
610      * We need to clean up the JPEG object, close the input file, and return.
611      */
612     if (rdr) jpeg_memio_cleanup(&cinfo);
613     jpeg_destroy_decompress(&cinfo);
614     logger->log("BJpeg", Log::ERR, "JPEG error");
615     if (buffer) free(buffer);
616     return false;
617   }
618   jpegUserData userdata;
619   int xpos=0;
620   int ypos=0;
621   jpeg_create_decompress(&cinfo);
622   userdata.reader=rdr;
623   userdata.ctl=ctl;
624   ctl->exifRotation=ROT_0;
625   ctl->error[0]=0;
626   ctl->exifDate[0]=0;
627   //create the input for the jpeg lib
628   jpeg_memio_src(&cinfo,(void *)(&userdata));
629   //processor for EXIF data
630   jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
631   //read in header info
632   jpeg_read_header(&cinfo, TRUE);
633   ctl->picw=cinfo.image_width;
634   ctl->pich=cinfo.image_height;
635   ctl->compressedSize=rdr->getSize();
636   //now we have important info available in ctl (pictuerw,h, exif orientation,size)
637   //compute rotation due to the defined enum values we can simply add them
638   ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
639   logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
640   //now we have to compute the scale
641   //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
642   //       list of available jpeg scale factors
643   //out:   scalenum,scaledenom,scaleafter
644
645   UINT picturew=ctl->picw;
646   UINT pictureh=ctl->pich;
647   switch (ctl->finalRotation){
648     case ROT_90:
649     case ROT_270:
650       pictureh=ctl->picw;
651       picturew=ctl->pich;
652       break;
653     default:
654       break;
655   }
656   UINT scalenum=1;
657   UINT scaledenom=1;
658   UINT scaleafter=1;
659   if (! ctl->enlarge) {
660     //scale - compute the factors to fit 100%
661     int scalew=1000*picturew/ctl->area.w;
662     int scaleh=1000*pictureh/ctl->area.h;
663     int scale=scaleh;
664     if (scalew > scaleh) scale=scalew;
665
666     //OK now find out which is the optimal setting
667     //rule: find settings being nearest to:
668     //   mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
669     //   mode=CROP   - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
670     //   mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
671     //                      scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
672     //the scalefactor computes as scalenum/(scaledenom*scaleafter)
673     scaledenom=8;
674     int minDiff=1000;
675     logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
676        ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter); 
677     for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
678       for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
679         int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
680         bool setThis=false;
681         logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d", 
682             curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
683         switch(ctl->mode) {
684           case CROP:
685             if (curf >= 1000 && curf < (minDiff +1000)) {
686               setThis=true;
687               minDiff=curf-1000;
688             }
689             break;
690           case LETTER:
691             if (curf <= 1000 && curf > (1000-minDiff)) {
692               setThis=true;
693               minDiff=1000-curf;
694             }
695             break;
696           case CROPPERCENT:
697             if (curf <= 10*(int)ctl->scaleAmount ) {
698               int abs=curf-1000;
699               if (abs < 0) abs=-abs;
700               if (abs < minDiff) {
701                    setThis=true;
702                    minDiff=abs;
703               }
704             }
705             break;
706         }
707         if (setThis) {
708           logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
709           scalenum=jpegFactors[j].num;
710           scaledenom=jpegFactors[j].denom;
711           scaleafter=sa;
712         }
713       }
714     }
715     ctl->scale=100*scalenum/(scaledenom*scaleafter);
716
717     logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
718         scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
719
720     cinfo.scale_denom=scaledenom;
721     cinfo.scale_num=scalenum;
722     }
723   else
724   {
725     //set drawing area according to picture
726     ctl->area.w=ctl->picw;
727     ctl->area.h=ctl->pich;
728   }
729
730   //now we know the scaling
731   //compute the scaled size and position
732
733   jpeg_start_decompress(&cinfo);
734   //picturew/h is now the output width from the decompressor and afterscaler
735   //this is unrotated 
736   picturew=cinfo.output_width;
737   pictureh=cinfo.output_height;
738   if (scaleafter > 1) {
739     picturew=picturew/scaleafter;
740     pictureh=pictureh/scaleafter;
741   }
742   //if our image is smaller - center it
743   if (! ctl->enlarge) {
744     if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
745       int dim=pictureh;
746       xpos=(((int)ctl->area.w)-dim)/2;
747       dim=picturew;
748       ypos=(((int)ctl->area.h)-dim)/2;
749     } else {
750       int dim=picturew;
751       xpos=(((int)ctl->area.w)-dim)/2;
752       dim=pictureh;
753       ypos=(((int)ctl->area.h)-dim)/2;
754     }
755     if (xpos <0) xpos=0;
756     if (ypos <0) ypos=0;
757   }
758   xpos+=ctl->area.x;
759   ypos+=ctl->area.y;
760   //remember the jpeg dimensions for computing the buffer
761   UINT jpegwidth=cinfo.output_width;
762   UINT jpegheight=cinfo.output_height;
763   logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d", 
764       picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
765
766   //fill the background
767   sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour.rgba());
768
769   //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
770   int linelen=jpegwidth*3;
771 #ifdef USE_BUFFER
772   // MAKE THE 2D ARRAY
773   buffer = (unsigned char*)malloc(jpegheight * linelen);
774   logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
775   if (buffer == NULL) {
776     if (rdr) jpeg_memio_cleanup(&cinfo);
777     jpeg_destroy_decompress(&cinfo);
778     logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
779     snprintf(ctl->error,100,"no room for buffer");
780     return false;
781   }
782 #endif
783
784 #ifndef USE_BUFFER
785   //unsigned char lbuf[linelen];
786   unsigned char *lbuf=new unsigned char[linelen*scaleafter];
787   unsigned char * ptr=lbuf;
788   UINT outy=0;
789 #else
790   unsigned char * ptr=buffer;
791 #endif
792
793   int rowsread = 0;
794
795   Colour c;
796   sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
797   //so that performance, can be optimized
798   logger->log("BJpeg", Log::DEBUG, "start drawing ");
799   UINT colincr=0;
800   //factors to base 1024
801   UINT fac=1024;
802   if (scaleafter > 1) {
803      colincr=3*scaleafter-3;
804      fac=1024/(scaleafter*scaleafter);
805      }
806   logger->log("BJpeg", Log::DEBUG, "jpeg  draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
807   while (cinfo.output_scanline < jpegheight)
808   {
809 //  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
810     rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
811 #ifdef USE_BUFFER
812     ptr+=linelen;
813 #else
814     if (scaleafter > 1) {
815       if (rowsread % scaleafter != scaleafter-1) {
816         //this simple approach wold maybe forget scaleafter -1 lines at the end...
817         ptr+=linelen;
818         continue;
819       }
820       ptr=lbuf;
821     }
822     drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
823     outy++;
824     
825 #endif
826   }
827   sfc->endFastDraw();
828
829   logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
830
831   jpeg_finish_decompress(&cinfo);
832   jpeg_memio_cleanup(&cinfo);
833   jpeg_destroy_decompress(&cinfo);
834
835   logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
836   rdr->drawingDone();
837
838 #ifdef USE_BUFFER
839   UINT y;
840   //Tell the surface, that we will draw a lot of pixel,
841   //so that performance, can be optimized
842   sfc->startFastDraw();
843   logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
844   unsigned char* p=buffer; //start of first row
845   UINT rowincr=linelen*scaleafter;
846   //for simplicity omit last line to avoid running out of buffer
847   for (y = 0; y < pictureh-1 ;y++)
848   {
849     drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
850     p+=rowincr;
851   }
852   sfc->endFastDraw();
853   logger->log("BJpeg", Log::DEBUG, "end draw");
854   free(buffer);
855 #else
856   delete[] lbuf;
857 #endif
858   logger->log("BJpeg", Log::DEBUG, "deleted buffer");
859   return true;
860 }
861
862 //get my own surface
863 Surface * WJpeg::getSurface(Region & r) {
864   r.x=getRootBoxOffsetX();
865   r.y=getRootBoxOffsetY();
866   r.w=area.w;
867   r.h=area.h;
868   return Boxx::getSurface();
869 }
870
871