]> git.vomp.tv Git - vompclient.git/blob - wjpeg.cc
German updates
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 #include "boxx.h"
21 #include "wjpeg.h"
22 #include <setjmp.h>
23
24 #include "i18n.h"
25 #include "log.h"
26 #include "surface.h"
27
28
29 extern "C" void
30 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata);
31 extern "C" void
32 jpeg_memio_cleanup (j_decompress_ptr cinfo);
33
34
35 #ifdef WIN32
36 ULONG WindowsResourceJpegReader::initRead(const char *filename)
37 {
38     HRSRC res=FindResource(NULL,filename,RT_RCDATA);
39     hres=LoadResource(NULL,res);
40     buffer=LockResource(hres);
41     size=SizeofResource(NULL,res);
42     //CloseHandle(hres);
43     return size;
44 }
45
46  ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
47 {
48     if (offset>size) return 0;
49     ULONG toread=min(size-offset,len);
50     char* buffy=(char*)malloc(toread);
51     memcpy(buffy,((char*)buffer)+offset,toread);
52     *buf=buffy;
53     return toread;
54 }
55
56  WindowsResourceJpegReader::~WindowsResourceJpegReader(){
57     buffer=NULL;
58     size=0;
59     FreeResource(hres);
60
61 }
62 #endif
63
64 WJpeg::WJpeg(){
65   fileName=NULL;
66 #ifndef WIN32
67   reader=NULL;
68 #else
69   reader=&winread;
70 #endif
71   useImageDimensions=true;
72   jheight=0;
73   jwidth=0;
74   jsize=0;
75   jerror=true;
76   rotate=0;
77   jscale=1;
78 }
79
80 WJpeg::~WJpeg() {
81   if (fileName) delete fileName;
82 }
83
84 int WJpeg::init(char* tfileName,bool useImage, JpegReader *rdr)
85 {
86   rotate=0;
87   if (fileName) delete fileName;
88   fileName=NULL;
89   if (tfileName) {
90     fileName = new char[strlen(tfileName)+1];
91     strcpy(fileName,tfileName);
92   }
93   if (rdr!=NULL) {
94   reader=rdr;
95   } else {
96 #ifdef WIN32
97       reader=&winread;
98 #else
99       reader=NULL;
100 #endif
101   }
102   useImageDimensions=useImage;
103   return 1;
104 }
105
106
107 ULONG WJpeg::getJpegInfo(ULONG tag){
108   switch(tag) {
109   case JPEG_HEIGHT:
110      return jheight;
111      break;
112   case JPEG_WIDTH:
113      return jwidth;
114      break;
115   case JPEG_SIZE:
116      return jsize;
117      break;
118   case JPEG_ROTATE:
119      return rotate;
120      break;
121   case JPEG_SCALE:
122      return jscale;
123      break;
124   }
125   return 0;
126 }
127
128 int WJpeg::getJpegInfo(ULONG tag, char * buffer) {
129   switch (tag) {
130   case JPEG_FILENAME:
131     strncpy(buffer,fileName,INFO_BUFFER-1);
132     buffer[INFO_BUFFER-1]=0;
133     return 0;
134     break;
135   }
136   return -1;
137 }
138
139 void WJpeg::setRotate(int amount) {
140   rotate=amount;
141 }
142
143
144
145 extern "C" {
146
147
148 struct my_error_mgr {
149   struct jpeg_error_mgr pub;    /* "public" fields */
150   FILE *infile;                 /* to be used in error handler */
151
152   jmp_buf setjmp_buffer;        /* for return to caller */
153 };
154
155 typedef struct my_error_mgr * my_error_ptr;
156
157 /*
158  * Here's the routine that will replace the standard error_exit method:
159  */
160
161 METHODDEF(void)
162 my_error_exit (j_common_ptr cinfo)
163 {
164   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
165   my_error_ptr myerr = (my_error_ptr) cinfo->err;
166
167   /* Always display the message. */
168   /* We could postpone this until after returning, if we chose. */
169   (*cinfo->err->output_message) (cinfo);
170   if (myerr->infile) fclose(myerr->infile);
171   /* Return control to the setjmp point */
172   longjmp(myerr->setjmp_buffer, 1);
173 }
174
175 }
176
177 bool WJpeg::hasError() {
178   return jerror;
179 }
180 void WJpeg::draw()
181 {
182   jerror=false;
183   if (drawJpeg() != 0) {
184     jerror=true;
185     drawTextCentre(tr("Jpeg ERROR"), 240, 180, Colour::LIGHTTEXT);
186   }
187 }
188
189 /* handle picture rotation
190    90: xr=h-y
191        yr=x
192    180:xr=w-x
193        yr=h-y
194    270:xr=y
195        yr=w-x
196 */
197 void WJpeg::drawPixel(int x, int y,int w,int h,int xpos, int ypos,Colour c){
198   int xb=0;
199   int yb=0;
200   switch(rotate) {
201      case ROT_0:
202         xb=x;
203         yb=y;
204         break;
205      case ROT_90:
206         xb=h-y;
207         yb=x;
208         break;
209      case ROT_180:
210         xb=w-x;
211         yb=h-y;
212         break;
213      case ROT_270:
214         xb=y;
215         yb=w-x;
216         break;
217      }
218    xb+=xpos;
219    yb+=ypos;
220    if (xb < 0 || yb < 0 ) {
221      Log::getInstance()->log("WJpeg:drawPixel",Log::ERR,"pixpos < 0 x=%d, y=%d",xb,yb);
222      return;
223    }
224    Boxx::drawPixel((UINT)xb,(UINT)yb,c);
225 }
226
227 int WJpeg::drawJpeg() {
228 //#ifndef WIN32
229   Log* logger = Log::getInstance();
230   unsigned char* buffer =NULL;
231   struct jpeg_decompress_struct cinfo;
232   struct my_error_mgr jerr;
233   jerr.infile=NULL;
234   cinfo.err = jpeg_std_error(&jerr.pub);
235   jerr.pub.error_exit = my_error_exit;
236   /* Establish the setjmp return context for my_error_exit to use. */
237   if (setjmp(jerr.setjmp_buffer)) {
238     /* If we get here, the JPEG code has signaled an error.
239      * We need to clean up the JPEG object, close the input file, and return.
240      */
241     if (reader) jpeg_memio_cleanup(&cinfo);
242     jpeg_destroy_decompress(&cinfo);
243     logger->log("BJpeg", Log::ERR, "JPEG error");
244     if (buffer) free(buffer);
245     return 1;
246   }
247   int xpos=0;
248   int ypos=0;
249   jpeg_create_decompress(&cinfo);
250   if (fileName && ! reader) {
251     jsize=0; //TODO: compute size for local files
252 #ifdef WIN32
253     jerr.infile=fopen(fileName+1, "rb");
254 #else 
255     jerr.infile=fopen(fileName, "rb");
256 #endif
257     if (jerr.infile == NULL)
258     {
259       logger->log("BJpeg", Log::ERR, "Can't open JPEG");
260       jpeg_destroy_decompress(&cinfo);
261       return 1;
262     }
263     logger->log("BJpeg", Log::DEBUG, "File opened");
264     jpeg_stdio_src(&cinfo, jerr.infile);
265   }
266   else if (reader) {
267      jsize=reader->initRead(fileName);
268      if (jsize <= 0) {
269         logger->log("BJpeg", Log::ERR, "Can't init JPEG transfer");
270         jpeg_destroy_decompress(&cinfo);
271         return 1;
272      }
273      jpeg_memio_src(&cinfo,(void *)reader);
274   }
275   else {
276      logger->log("BJpeg", Log::ERR, "neither  filename nor reader set");
277      jpeg_destroy_decompress(&cinfo);
278      return 1;
279   }
280   jpeg_read_header(&cinfo, TRUE);
281   logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", cinfo.image_width, cinfo.image_height, rotate);
282   int picturew=cinfo.image_width;
283   int pictureh=cinfo.image_height;
284   switch (rotate){
285     case ROT_90:
286     case ROT_270:
287       pictureh=cinfo.image_width;
288       picturew=cinfo.image_height;
289       break;
290   }
291   if (! useImageDimensions) {
292     //scale - we can have factors 1,2,4,8
293     int scalew=getWidth()*1000/picturew;
294     int scaleh=getHeight()*1000/pictureh;
295     int scale=scaleh;
296     if (scalew < scaleh) scale=scalew;
297     int fac=8;
298     //we allow for 10% bigger...
299     if (scale >= 900) fac=1;
300     else if (scale >= 450 ) fac=2;
301     else if (scale >= 225 ) fac=4;
302     cinfo.scale_denom=fac;
303     logger->log("BJpeg", Log::DEBUG, "JPEG scaling (1/1000) pw=%i ph=%i w=%i h=%i r=%i f=%i",
304        getWidth(),
305        getHeight(),
306        scalew,scaleh,scale,fac);
307     jscale=fac;
308     }
309
310   //remember picture parameters
311   jheight=pictureh;
312   jwidth=picturew;
313
314   jpeg_start_decompress(&cinfo);
315   //recompute width based on rotation (consider scale)
316   picturew=cinfo.output_width;
317   pictureh=cinfo.output_height;
318   switch (rotate){
319     case ROT_90:
320     case ROT_270:
321       pictureh=cinfo.output_width;
322       picturew=cinfo.output_height;
323       break;
324   }  
325   //if our image is smaller - center it
326   if (! useImageDimensions) {
327      xpos=(((int)getWidth())-picturew)/2;
328      if (xpos <0) xpos=0;
329      ypos=(((int)getHeight())-pictureh)/2;
330      if (ypos <0) ypos=0;
331   }
332   //center point for rotation
333   int w=cinfo.output_width;
334   int h=cinfo.output_height;
335   logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, iw=%i, ih=%i", picturew, pictureh,xpos,ypos,w,h);
336
337   // Init the surface
338
339 // Temp disabled for boxx. what does this do anyway .. - cjt
340 /*
341   if (useImageDimensions) setDimensions(picturew, pictureh);
342   fillColour(backgroundColour);
343 */
344
345
346   //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
347   int linelen=cinfo.output_width*3;
348 #ifdef USE_BUFFER
349   // MAKE THE 2D ARRAY
350   buffer = (unsigned char*)malloc(config.output_height * linelen);
351   logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, width = %i height = %i", buffer, cinfo.output_height, linelen);
352   if (buffer == NULL) {
353     if (reader) jpeg_memio_cleanup(&cinfo);
354     jpeg_destroy_decompress(&cinfo);
355     if (jerr.infile) fclose(jerr.infile);
356     logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
357     return 1;
358   }
359 #endif
360
361   //unsigned char* bufferPointers[area.h];
362   //for(UINT ps = 0; ps < area.h; ps++) bufferPointers[ps] = buffer + (ps * area.w * 3);
363   
364   logger->log("BJpeg", Log::DEBUG, "header w=%d,h=%d",cinfo.output_width,cinfo.output_height);
365 #ifndef USE_BUFFER
366   //unsigned char lbuf[linelen];
367   unsigned char *lbuf=new unsigned char[linelen];
368   unsigned char * ptr=lbuf;
369 #else
370   unsigned char * ptr=buffer;
371 #endif
372
373   int rowsread = 0;
374
375   Colour c;
376   startFastDraw();//Tell the surface, that we will draw a lot of pixel,
377   //so that performance, can be optimized
378   while (cinfo.output_scanline < cinfo.output_height)
379   {
380 //  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
381     rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
382 #ifdef USE_BUFFER
383     ptr+=linelen;
384 #else
385      int x=0;
386      for (unsigned char * lp=ptr;lp < (ptr+linelen);lp+=3,x++) {
387        c.red=*lp ;
388        c.green=*(lp+1);
389        c.blue=*(lp+2);
390        drawPixel(x, rowsread-1,w,h,xpos,ypos, c);
391        }
392     
393 #endif
394   }
395   endFastDraw();
396
397   logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
398
399   jpeg_finish_decompress(&cinfo);
400   if (reader) jpeg_memio_cleanup(&cinfo);
401   jpeg_destroy_decompress(&cinfo);
402
403   if (jerr.infile) fclose(jerr.infile);
404
405   logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done, x, y %u %u", area.w, area.h);
406 #ifdef USE_BUFFER
407   Colour c;
408   UINT x, y, xoff;
409   unsigned char* p;
410   surface->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
411   //so that performance, can be optimized
412   for (y = 0; y < numlines; y++)
413   {
414     p = bufferPointers[y];
415
416     for (x = 0; x < sfclen; x++)
417     {
418       xoff = x * 3;
419
420 //      c = (  (0xFF000000        )
421 //           | (p[xoff    ]  << 16)
422 //           | (p[xoff + 1]  <<  8)
423 //           | (p[xoff + 2]       ) );
424
425       c.red = p[xoff];
426       c.green = p[xoff + 1];
427       c.blue = p[xoff + 2];
428
429       drawPixel(x, y, w,h,xpos,ypos,c);
430     }
431   }
432   surface->endFastDraw();
433   delete [] lbuf;
434   free(buffer);
435 #endif
436   logger->log("BJpeg", Log::DEBUG, "deleted buffer");
437 /*#else
438   DWORD width,height;
439   width=height=1;
440   if (!reader) 
441   {
442   ((SurfaceWin*)surface)->drawJpeg(fileName+1,offsetX,offsetY,&width,&height);//This should went into the abstract base classes?
443   //Windows has a problem with the leading / fixme
444   } else {
445       ULONG jsize;
446       jsize=reader->initRead(fileName);
447       char *buffer;
448       if (jsize==reader->readChunk(0,jsize,&buffer))
449       {
450            ((SurfaceWin*)surface)->drawJpeg(buffer,jsize,offsetX,offsetY,&width,&height);//This should went into the abstract base classes?
451             free(buffer);
452       }
453
454   }
455   
456  // setDimensions(width, height);
457   jwidth=width;
458   jheight=height;
459
460 #endif*/
461   return 0;
462 }
463
464
465 extern "C" {
466 ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
467   JpegReader *rd=(JpegReader *)cb;
468   return rd->readChunk(offset,size,buf);
469 }
470 }
471 //the memory buffer reader for the jpeg lib
472 //taken from jdatasrc.c
473
474 extern "C" {
475 /* Expanded data source object for stdio input */
476 #include "jinclude.h"
477 #include "jpeglib.h"
478 #include "jerror.h"/* Expanded data source object for stdio input */
479
480 typedef struct {
481   struct jpeg_source_mgr pub;   /* public fields */
482
483   JOCTET * buffer;              /* start of buffer */
484   boolean start_of_file;        /* have we gotten any data yet? */
485   void * userdata;              /* used for callback */
486   ULONG offset;
487 } my_source_mgr;
488
489 typedef my_source_mgr * my_src_ptr;
490
491 #define INPUT_BUF_SIZE  (64*4096)       /* choose an efficiently fread'able size */
492
493
494 /*
495  * Initialize source --- called by jpeg_read_header
496  * before any data is actually read.
497  */
498
499 METHODDEF(void)
500 linit_source (j_decompress_ptr cinfo)
501 {
502   my_src_ptr src = (my_src_ptr) cinfo->src;
503
504   /* We reset the empty-input-file flag for each image,
505    * but we don't clear the input buffer.
506    * This is correct behavior for reading a series of images from one source.
507    */
508   src->start_of_file = TRUE;
509   src->offset=0;
510 }
511
512
513 /*
514  * Fill the input buffer --- called whenever buffer is emptied.
515  *
516  * In typical applications, this should read fresh data into the buffer
517  * (ignoring the current state of next_input_byte & bytes_in_buffer),
518  * reset the pointer & count to the start of the buffer, and return TRUE
519  * indicating that the buffer has been reloaded.  It is not necessary to
520  * fill the buffer entirely, only to obtain at least one more byte.
521  *
522  * There is no such thing as an EOF return.  If the end of the file has been
523  * reached, the routine has a choice of ERREXIT() or inserting fake data into
524  * the buffer.  In most cases, generating a warning message and inserting a
525  * fake EOI marker is the best course of action --- this will allow the
526  * decompressor to output however much of the image is there.  However,
527  * the resulting error message is misleading if the real problem is an empty
528  * input file, so we handle that case specially.
529  *
530  * In applications that need to be able to suspend compression due to input
531  * not being available yet, a FALSE return indicates that no more data can be
532  * obtained right now, but more may be forthcoming later.  In this situation,
533  * the decompressor will return to its caller (with an indication of the
534  * number of scanlines it has read, if any).  The application should resume
535  * decompression after it has loaded more data into the input buffer.  Note
536  * that there are substantial restrictions on the use of suspension --- see
537  * the documentation.
538  *
539  * When suspending, the decompressor will back up to a convenient restart point
540  * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
541  * indicate where the restart point will be if the current call returns FALSE.
542  * Data beyond this point must be rescanned after resumption, so move it to
543  * the front of the buffer rather than discarding it.
544  */
545
546 METHODDEF(boolean)
547 lfill_input_buffer (j_decompress_ptr cinfo)
548 {
549   my_src_ptr src = (my_src_ptr) cinfo->src;
550   size_t nbytes;
551   if (src->buffer) free(src->buffer);
552   src->buffer=NULL;
553   nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
554
555   if (nbytes <= 0) {
556     WARNMS(cinfo, JWRN_JPEG_EOF);
557     src->buffer =  (JOCTET *)malloc(2);
558     src->buffer[0] = (JOCTET) 0xFF;
559     src->buffer[1] = (JOCTET) JPEG_EOI;
560     nbytes = 2;
561
562   }
563   src->offset+=nbytes;
564
565   src->pub.next_input_byte = src->buffer;
566   src->pub.bytes_in_buffer = nbytes;
567   src->start_of_file = FALSE;
568
569   return TRUE;
570 }
571
572
573 /*
574  * Skip data --- used to skip over a potentially large amount of
575  * uninteresting data (such as an APPn marker).
576  *
577  * Writers of suspendable-input applications must note that skip_input_data
578  * is not granted the right to give a suspension return.  If the skip extends
579  * beyond the data currently in the buffer, the buffer can be marked empty so
580  * that the next read will cause a fill_input_buffer call that can suspend.
581  * Arranging for additional bytes to be discarded before reloading the input
582  * buffer is the application writer's problem.
583  */
584
585 METHODDEF(void)
586 lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
587 {
588   my_src_ptr src = (my_src_ptr) cinfo->src;
589
590   /* Just a dumb implementation for now.  Could use fseek() except
591    * it doesn't work on pipes.  Not clear that being smart is worth
592    * any trouble anyway --- large skips are infrequent.
593    */
594   if (num_bytes > 0) {
595     while (num_bytes > (long) src->pub.bytes_in_buffer) {
596       num_bytes -= (long) src->pub.bytes_in_buffer;
597       (void) lfill_input_buffer(cinfo);
598       /* note we assume that fill_input_buffer will never return FALSE,
599        * so suspension need not be handled.
600        */
601     }
602     src->pub.next_input_byte += (size_t) num_bytes;
603     src->pub.bytes_in_buffer -= (size_t) num_bytes;
604   }
605 }
606
607
608 /*
609  * An additional method that can be provided by data source modules is the
610  * resync_to_restart method for error recovery in the presence of RST markers.
611  * For the moment, this source module just uses the default resync method
612  * provided by the JPEG library.  That method assumes that no backtracking
613  * is possible.
614  */
615
616
617 /*
618  * Terminate source --- called by jpeg_finish_decompress
619  * after all data has been read.  Often a no-op.
620  *
621  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
622  * application must deal with any cleanup that should happen even
623  * for error exit.
624  */
625
626 METHODDEF(void)
627 lterm_source (j_decompress_ptr cinfo)
628 {
629   /* no work necessary here */
630 }
631
632
633 /*
634  * Prepare for input from a stdio stream.
635  * The caller must have already opened the stream, and is responsible
636  * for closing it after finishing decompression.
637  */
638
639 extern "C" void
640 jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
641 {
642   my_src_ptr src;
643
644   /* The source object and input buffer are made permanent so that a series
645    * of JPEG images can be read from the same file by calling jpeg_stdio_src
646    * only before the first one.  (If we discarded the buffer at the end of
647    * one image, we'd likely lose the start of the next one.)
648    * This makes it unsafe to use this manager and a different source
649    * manager serially with the same JPEG object.  Caveat programmer.
650    */
651   if (cinfo->src == NULL) {     /* first time for this JPEG object? */
652     cinfo->src = (struct jpeg_source_mgr *)
653       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
654                                   SIZEOF(my_source_mgr));
655     src = (my_src_ptr) cinfo->src;
656     src->buffer = NULL;
657   }
658
659   src = (my_src_ptr) cinfo->src;
660   src->pub.init_source = linit_source;
661   src->pub.fill_input_buffer = lfill_input_buffer;
662   src->pub.skip_input_data = lskip_input_data;
663   src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
664   src->pub.term_source = lterm_source;
665   src->userdata=userdata;
666   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
667   src->pub.next_input_byte = NULL; /* until buffer loaded */
668   src->offset=0;
669   src->userdata=userdata;
670   if (src->buffer) {
671      free(src->buffer);
672      src->buffer=NULL;
673      }
674 }
675 /* cleanup to be called before cleanup of cinfo*/
676 extern "C" void
677 jpeg_memio_cleanup (j_decompress_ptr cinfo) {
678   my_src_ptr src=(my_src_ptr)cinfo->src;
679   Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
680   if (src && src->buffer) {
681     free(src->buffer);
682     src->buffer=NULL;
683     }
684 }
685 }
686