Image.cpp
上传用户:hmc_gdtv
上传日期:2013-08-04
资源大小:798k
文件大小:23k
源码类别:

Windows Mobile

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 2001,2002,2003 Mike Matsnev.  All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice immediately at the beginning of the file, without modification,
  10.  *    this list of conditions, and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. Absolutely no warranty of function or purpose is made by the author
  15.  *    Mike Matsnev.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  * 
  28.  * $Id: Image.cpp,v 1.12.2.7 2003/09/21 12:07:35 mike Exp $
  29.  * 
  30.  */
  31. // XXX handle out of memory exceptions gracefully
  32. #ifdef STANDALONE
  33. #include <windows.h>
  34. #else
  35. #include <afxwin.h>
  36. #endif
  37. #include <string.h>
  38. #include <stdlib.h>
  39. #include <setjmp.h>
  40. #include <math.h>
  41. extern "C" {
  42.   #include <jpeglib.h>
  43.   #include <jerror.h>
  44.   #include <png.h>
  45. };
  46. #include "ptr.h"
  47. #include "Image.h"
  48. #ifndef STANDALONE
  49. #include "config.h"
  50. #include "TextViewNG.h"
  51. #endif
  52. #define INBUF_SIZE    4096
  53. // supported bitmap formats
  54. enum {
  55.   BF_UNKNOWN,
  56.   BF_565,
  57.   BF_555,
  58.   BF_888
  59. };
  60. struct GXDisplayProperties {
  61. DWORD cxWidth;
  62. DWORD cyHeight; // notice lack of 'th' in the word height.
  63. long cbxPitch; // number of bytes to move right one x pixel - can be negative.
  64. long cbyPitch; // number of bytes to move down one y pixel - can be negative.
  65. long cBPP; // # of bits in each pixel
  66. DWORD ffFormat; // format flags.
  67. };
  68. #define kfDirect555 0x40 // 5 bits each for red, green and blue values in a pixel.
  69. #define kfDirect565 0x80 // 5 red bits, 6 green bits and 5 blue bits per pixel
  70. #define kfDirect888 0x100 // 8 bits each for red, green and blue values in a pixel.
  71. #define kfDirect444 0x200 // 4 red, 4 green, 4 blue
  72. typedef unsigned char u8;
  73. typedef unsigned int u32;
  74. typedef signed int s32;
  75. typedef unsigned short u16;
  76. static u8   gamma_table[256];
  77. static void set_gamma(double image_gamma) {
  78.   double    disp_gamma=
  79. #ifdef STANDALONE
  80.     1.8;
  81. #else
  82.     CTVApp::GetInt(_T("Gamma"),DEF_GAMMA)/1000000.0;
  83. #endif
  84.   if (disp_gamma<1)
  85.     disp_gamma=1;
  86.   if (disp_gamma>5)
  87.     disp_gamma=5;
  88.   double    g=1/(image_gamma*disp_gamma);
  89.   int     i;
  90.   for (i=0;i<256;++i)
  91.     gamma_table[i]=((int)(pow(i/256.0,g)*256.0));
  92. }
  93. // returns resized line with pixels scaled by inw
  94. static void resize_line_plain(u8 *in,u32 inw,u32 *out,u32 outw,u8 * /* bg */) {
  95.   u32   inptr=0; // input pixel position inside the output pixel
  96.   u32   outptr=inw;
  97.   u8   *top=in+inw*3; // pixel after the last
  98.   out[0]=out[1]=out[2]=0; // initialize first output pixel
  99.   do { // for each input pixel
  100.     if (inptr+outw>outptr) { // input pixel crosses two output pixels
  101.       // red
  102.       out[0] += in[0] * (outptr - inptr); // add to current pixel
  103.       out[3] = in[0] * (outw - (outptr - inptr)); // and initialize the next one
  104.       // green
  105.       out[1] += in[1] * (outptr - inptr); // add to current pixel
  106.       out[4] = in[1] * (outw - (outptr - inptr)); // and initialize the next one
  107.       // blue
  108.       out[2] += in[2] * (outptr - inptr); // add to current pixel
  109.       out[5] = in[2] * (outw - (outptr - inptr)); // and initialize the next one
  110.       // advance to next pixel
  111.       out += 3;
  112.       outptr += inw;
  113.     } else { // completely contained
  114.       out[0] += in[0] * outw;
  115.       out[1] += in[1] * outw;
  116.       out[2] += in[2] * outw;
  117.     }
  118.     in+=3; // next input pixel
  119.     inptr+=outw;
  120.   } while (in<top);
  121. }
  122. // returns resized line with pixels scaled by inw
  123. static void resize_line_alpha(u8 *in,u32 inw,u32 *out,u32 outw,u8 *bg) {
  124.   u32   inptr=0; // input pixel position inside the output pixel
  125.   u32   outptr=inw;
  126.   u8   *top=in+inw*4; // pixel after the last
  127.   u8   pval; // current pixel value
  128.   u8   transp;
  129.   u8   opacity;
  130.   out[0]=out[1]=out[2]=0; // initialize first output pixel
  131.   do { // for each input pixel
  132.     opacity = in[3];
  133.     transp = 255 - in[3];
  134.     if (inptr+outw>outptr) { // input pixel crosses two output pixels
  135.       // red
  136.       pval = (in[0]*opacity + bg[0]*transp)>>8;
  137.       out[0] += pval * (outptr - inptr); // add to current pixel
  138.       out[3] = pval * (outw - (outptr - inptr)); // and initialize the next one
  139.       // green
  140.       pval = (in[1]*opacity + bg[1]*transp)>>8;
  141.       out[1] += pval * (outptr - inptr); // add to current pixel
  142.       out[4] = pval * (outw - (outptr - inptr)); // and initialize the next one
  143.       // blue
  144.       pval = (in[2]*opacity + bg[2]*transp)>>8;
  145.       out[2] += pval * (outptr - inptr); // add to current pixel
  146.       out[5] = pval * (outw - (outptr - inptr)); // and initialize the next one
  147.       // advance to next pixel
  148.       out += 3;
  149.       outptr += inw;
  150.     } else { // completely contained
  151.       out[0] += ((in[0]*opacity + bg[0]*transp) * outw) >> 8;
  152.       out[1] += ((in[1]*opacity + bg[1]*transp) * outw) >> 8;
  153.       out[2] += ((in[2]*opacity + bg[2]*transp) * outw) >> 8;
  154.     }
  155.     in+=4; // next input pixel
  156.     inptr+=outw;
  157.   } while (in<top);
  158. }
  159. struct imagestore {
  160.   HBITMAP bmp;
  161.   u8   *bits;
  162.   int   hstep;
  163.   int   vstep;
  164.   u32   width;
  165.   u32   height;
  166.   u32   realwidth;
  167.   u32   realheight;
  168.   int   bmformat;
  169.   void   (*packbits)(imagestore *is,u8* src);
  170. };
  171. struct resize_state {
  172.   u32   *accum;
  173.   u32   *lb;
  174.   s32   *error;
  175.   s32   *nexterror;
  176.   u32   inptr;
  177.   u32   outptr;
  178.   u8   *dest;
  179.   u32   inw,inh;
  180.   u32   outw,outh;
  181.   u32   outscale;
  182.   u32   inscale;
  183.   s32   max;
  184.   u32   mask[3];
  185.   u32   *membuf;
  186.   int   odd;
  187.   u8   bg[4]; // background color for transparent images
  188.   // we store a function pointer here to handle transparency properly
  189.   void   (*resize_line)(u8 *in,u32 inw,u32 *out,u32 outw,u8 *bg);
  190.   imagestore  *output;
  191. };
  192. static void packbits_24_to_15(imagestore *is,u8 *src) {
  193.   u32   i;
  194.   u8   *bits=is->bits;
  195.   s32   hstep=is->hstep;
  196.   u32   width=is->width;
  197.   for (i=0;i<width;++i) {
  198.     *(u16*)bits=((u16)(gamma_table[src[0]]&0xF8)<<7)|
  199.       ((u16)(gamma_table[src[1]]&0xF8)<<2)|
  200.       (gamma_table[src[2]]>>3);
  201.     src+=3;
  202.     bits+=hstep;
  203.   }
  204.   is->bits+=is->vstep;
  205. }
  206. static void packbits_24_to_16(imagestore *is,u8 *src) {
  207.   u32   i;
  208.   u8   *bits=is->bits;
  209.   s32   hstep=is->hstep;
  210.   u32   width=is->width;
  211.   for (i=0;i<width;++i) {
  212.     *(u16*)bits=((u16)(gamma_table[src[0]]&0xF8)<<8)|
  213.       ((u16)(gamma_table[src[1]]&0xFC)<<3)|
  214.       (gamma_table[src[2]]>>3);
  215.     src+=3;
  216.     bits+=hstep;
  217.   }
  218.   is->bits+=is->vstep;
  219. }
  220. static void packbits_24_to_24(imagestore *is,u8 *src) {
  221.   u32   i;
  222.   u8   *bits=is->bits;
  223.   s32   hstep=is->hstep;
  224.   u32   width=is->width;
  225.   for (i=0;i<width;i++) {
  226.     bits[0]=gamma_table[src[2]];
  227.     bits[1]=gamma_table[src[1]];
  228.     bits[2]=gamma_table[src[0]];
  229.     src+=3;
  230.     bits+=hstep;
  231.   }
  232.   is->bits+=is->vstep;
  233. }
  234. static bool resize_state_init(resize_state *rs,u32 iinw,u32 iinh,imagestore *iout)
  235. {
  236.   rs->output=iout;
  237.   rs->inw=iinw;
  238.   rs->inh=iinh;
  239.   rs->outw=iout->width;
  240.   rs->outh=iout->height;
  241.   u32 *p=(u32*)malloc(sizeof(u32)*13*(rs->outw+2));
  242.   if (!p)
  243.     return false;
  244.   memset(p,0,sizeof(u32)*(6*rs->outw+6*(rs->outw+2)+rs->outw));
  245.   rs->membuf=p;
  246.   rs->odd=0;
  247.   switch (iout->bmformat) {
  248.   case BF_555:
  249.     rs->mask[0]=rs->mask[1]=rs->mask[2]=0xfffffff8;
  250.     break;
  251.   case BF_565:
  252.     rs->mask[0]=0xfffffff8;
  253.     rs->mask[1]=0xfffffffc;
  254.     rs->mask[2]=0xfffffff8;
  255.     break;
  256.   case BF_888:
  257.     rs->mask[0]=rs->mask[1]=rs->mask[2]=0xffffffff;
  258.     break;
  259. #ifndef STANDALONE
  260.   default:
  261.     ASSERT(0);
  262. #endif
  263.   }
  264.   rs->inptr=0;
  265.   rs->outptr=rs->inh;
  266.   rs->accum=p; p+=3*(rs->outw+2);
  267.   rs->lb=p; p+=3*(rs->outw+2);
  268.   rs->nexterror=(s32*)p+3; p+=3*(rs->outw+2);
  269.   rs->error=(s32*)p+3; p+=3*(rs->outw+2);
  270.   rs->dest=(u8*)p; p+=rs->outw;
  271.   rs->outscale=(u32)(4294967296.0/(rs->inw*rs->inh));
  272.   rs->inscale=rs->inw*rs->inh;
  273.   rs->max=rs->inscale*256-1;
  274.   rs->resize_line=resize_line_plain;
  275.   return true;
  276. }
  277. static void resize_set_alpha(resize_state *rs,COLORREF bg) {
  278.   rs->resize_line=resize_line_alpha;
  279.   rs->bg[0]=GetRValue(bg);
  280.   rs->bg[1]=GetGValue(bg);
  281.   rs->bg[2]=GetBValue(bg);
  282. }
  283. static void resize_state_destroy(resize_state *rs) {
  284.   if (rs) {
  285.     free(rs->membuf);
  286.     free(rs);
  287.   }
  288. }
  289. static resize_state *resize_state_create(u32 iinw,u32 iinh,imagestore *out) {
  290.   resize_state *rs=(resize_state *)malloc(sizeof(resize_state));
  291.   if (rs && resize_state_init(rs,iinw,iinh,out))
  292.     return rs;
  293.   free(rs);
  294.   return NULL;
  295. }
  296. __inline s32 CLIP(s32 v,s32 m) {
  297.   return v<0 ? 0 : v>m ? m : v;
  298. }
  299. #define CLIPADD(rs,i,n) CLIP(rs->lb[i+n]+rs->error[i+n],rs->max)
  300. #define M64(a,b,m) ((unsigned int)(((__int64)(a)*(b))>>32)&(m))
  301. #define PIXEL_EVEN(rs,i,c) 
  302.   u = CLIPADD(rs,i,c); 
  303.   v = M64(u,rs->outscale,rs->mask[c]); 
  304.   e = u - v*rs->inscale; 
  305.   rs->error[i+3+c] += (e*7)>>4; 
  306.   rs->nexterror[i-3+c] += (e*3)>>4; 
  307.   rs->nexterror[i+0+c] += (e*5)>>4; 
  308.   rs->nexterror[i+3+c] += e>>4; 
  309.   rs->dest[i+c] = v;
  310. #define PIXEL_ODD(rs,i,c) 
  311.   u = CLIPADD(rs,i,c); 
  312.   v = M64(u,rs->outscale,rs->mask[c]); 
  313.   e = u-v*rs->inscale; 
  314.   rs->error[i-3+c] += (e*7)>>4; 
  315.   rs->nexterror[i+3+c] += (e*3)>>4; 
  316.   rs->nexterror[i+0+c] += (e*5)>>4; 
  317.   rs->nexterror[i-3+c] += e>>4; 
  318.   rs->dest[i+c]=v;
  319. // dither lb into dest, left to right
  320. void resize_dither_even(struct resize_state *rs) {
  321.   u32   i;
  322.   s32   u,v,e;
  323.   for (i=0;i<3*rs->outw;i+=3) {
  324.     PIXEL_EVEN(rs,i,0);
  325.     PIXEL_EVEN(rs,i,1);
  326.     PIXEL_EVEN(rs,i,2);
  327.   }
  328. }
  329. // dither lb into dest, right to left
  330. void resize_dither_odd(struct resize_state *rs) {
  331.   s32   i;
  332.   s32   u,v,e;
  333.   for (i=3*rs->outw-3;i>=0;i-=3) {
  334.     PIXEL_ODD(rs,i,0);
  335.     PIXEL_ODD(rs,i,1);
  336.     PIXEL_ODD(rs,i,2);
  337.   }
  338. }
  339. // dither lb into dest
  340. void  resize_dither(struct resize_state *rs) {
  341.   s32   *tmp;
  342.   if (rs->odd)
  343.     resize_dither_odd(rs);
  344.   else
  345.     resize_dither_even(rs);
  346.   tmp=rs->error;
  347.   rs->error=rs->nexterror;
  348.   rs->nexterror=tmp;
  349.   memset(tmp,0,sizeof(s32)*3*rs->outw);
  350.   rs->odd=!rs->odd;
  351.   rs->output->packbits(rs->output,rs->dest);
  352. }
  353. void resize_add_line(struct resize_state *rs,u8 *line) {
  354.   u32   i;
  355.   // resize the line horizontally
  356.   rs->resize_line(line,rs->inw,rs->lb,rs->outw,rs->bg);
  357.   // perform one loop iteration
  358.   if (rs->inptr+rs->outh>=rs->outptr) {
  359.     u32     c1=rs->outptr-rs->inptr;
  360.     u32     c2=rs->outh-c1;
  361.     u32     v;
  362.     for (i=0;i<3*rs->outw;i+=3) {
  363.       v = rs->accum[i+0]+rs->lb[i+0]*c1;
  364.       rs->accum[i+0] = rs->lb[i+0]*c2;
  365.       rs->lb[i+0] = v;
  366.       v = rs->accum[i+1]+rs->lb[i+1]*c1;
  367.       rs->accum[i+1] = rs->lb[i+1]*c2;
  368.       rs->lb[i+1] = v;
  369.       v = rs->accum[i+2]+rs->lb[i+2]*c1;
  370.       rs->accum[i+2] = rs->lb[i+2]*c2;
  371.       rs->lb[i+2] = v;
  372.     }
  373.     resize_dither(rs);
  374.     rs->outptr+=rs->inh;
  375.   } else {
  376.     for (i=0;i<3*rs->outw;i+=3) {
  377.       rs->accum[i+0] += rs->lb[i+0]*rs->outh;
  378.       rs->accum[i+1] += rs->lb[i+1]*rs->outh;
  379.       rs->accum[i+2] += rs->lb[i+2]*rs->outh;
  380.     }
  381.   }
  382.   rs->inptr+=rs->outh;
  383. }
  384. struct my_src_mgr {
  385.   struct jpeg_source_mgr  pub;
  386.   ImageLoader::BinReader  *rdr;
  387.   JOCTET   *buffer;
  388. };
  389. METHODDEF(void) jsrc_init_source (j_decompress_ptr cinfo) {
  390.   // do nothing
  391. }
  392. METHODDEF(boolean) jsrc_fill_input_buffer (j_decompress_ptr cinfo) {
  393.   my_src_mgr *mgr=(my_src_mgr*)cinfo->src;
  394.   int   nr=mgr->rdr->Read(mgr->buffer,INBUF_SIZE);
  395.   if (nr<=0) { // eof
  396.     // fake EOI marker
  397.     mgr->buffer[0]=(JOCTET)0xff;
  398.     mgr->buffer[1]=(JOCTET)JPEG_EOI;
  399.     nr=2;
  400.   }
  401.   mgr->pub.bytes_in_buffer=nr;
  402.   mgr->pub.next_input_byte=mgr->buffer;
  403.   return TRUE;
  404. }
  405. METHODDEF(void) jsrc_skip_input_data (j_decompress_ptr cinfo, long bytes) {
  406.   my_src_mgr *mgr=(my_src_mgr*)cinfo->src;
  407.   if (bytes > 0) {
  408.     while (bytes > (long) mgr->pub.bytes_in_buffer) {
  409.       bytes -= (long) mgr->pub.bytes_in_buffer;
  410.       jsrc_fill_input_buffer(cinfo);
  411.       /* note we assume that fill_input_buffer will never return FALSE,
  412.        * so suspension need not be handled.
  413.        */
  414.     }
  415.     mgr->pub.next_input_byte += (size_t) bytes;
  416.     mgr->pub.bytes_in_buffer -= (size_t) bytes;
  417.   }
  418. }
  419. METHODDEF(void) jsrc_term_source(j_decompress_ptr cinfo) {
  420.   // do nothing
  421. }
  422. static void prepare_buffer(j_decompress_ptr cinfo,ImageLoader::BinReader *rdr) {
  423.   my_src_mgr  *mgr;
  424.   if (cinfo->src==NULL) {
  425.     cinfo->src=(struct jpeg_source_mgr *)
  426.       (cinfo->mem->alloc_small((j_common_ptr)cinfo,JPOOL_PERMANENT,
  427. sizeof(my_src_mgr)));
  428.     mgr=(my_src_mgr*)cinfo->src;
  429.     mgr->buffer=(JOCTET*)
  430.       (cinfo->mem->alloc_small((j_common_ptr)cinfo,JPOOL_PERMANENT,
  431. INBUF_SIZE*sizeof(JOCTET)));
  432.   }
  433.   mgr=(my_src_mgr*)cinfo->src;
  434.   mgr->rdr=rdr;
  435.   mgr->pub.init_source=jsrc_init_source;
  436.   mgr->pub.fill_input_buffer=jsrc_fill_input_buffer;
  437.   mgr->pub.skip_input_data=jsrc_skip_input_data;
  438.   mgr->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
  439.   mgr->pub.term_source=jsrc_term_source;
  440.   mgr->pub.bytes_in_buffer=0;
  441.   mgr->pub.next_input_byte=NULL;
  442. }
  443. struct my_error_mgr {
  444.   struct jpeg_error_mgr   pub;
  445.   jmp_buf   jb;
  446. };
  447. METHODDEF(void) je_error_exit(j_common_ptr cinfo) {
  448.   my_error_mgr   *mgr=(my_error_mgr*)cinfo->err;
  449.   /* Always display the message */
  450.   (*cinfo->err->output_message) (cinfo);
  451.   jpeg_destroy(cinfo);
  452.   longjmp(mgr->jb,1);
  453. }
  454. METHODDEF(void) je_output_message(j_common_ptr cinfo) {
  455.   char buffer[JMSG_LENGTH_MAX];
  456.   /* Create the message */
  457.   (*cinfo->err->format_message) (cinfo, buffer);
  458.   // do nothing at this time
  459. #if 0
  460.   MessageBoxA(GetActiveWindow(),buffer,"JPEG Decompressor",MB_OK);
  461. #endif
  462. }
  463. static void PNGAPI pngr_read_data(png_structp png_ptr,png_bytep data,png_size_t length) {
  464.   ImageLoader::BinReader  *rdr=(ImageLoader::BinReader*)png_get_io_ptr(png_ptr);
  465.   if (!rdr || rdr->Read(data,length)!=(int)length)
  466.     png_error(png_ptr,"Read Error");
  467. }
  468. static int  get_bitmap_format() {
  469.   static int     format=BF_UNKNOWN;
  470. #ifdef _WIN32_WCE
  471.   if (format!=BF_UNKNOWN)
  472.     return format;
  473.   HINSTANCE hLib;
  474.   if ((hLib=LoadLibrary(_T("gx.dll")))!=NULL) {
  475.     GXDisplayProperties (*gp)();
  476.     gp=(GXDisplayProperties (*)())GetProcAddress(hLib,
  477.       _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ"));
  478.     if (gp) {
  479.       GXDisplayProperties props=gp();
  480.       if (props.ffFormat&kfDirect555)
  481. format=BF_555;
  482.       else if (props.ffFormat&kfDirect565)
  483. format=BF_565;
  484.       else
  485. format=BF_888;
  486.     }
  487.     FreeLibrary(hLib);
  488.   }
  489. #endif
  490.   if (format!=BF_UNKNOWN)
  491.     return format;
  492.   HDC hDC=GetDC(NULL);
  493.   if (GetDeviceCaps(hDC,BITSPIXEL)==16)
  494.     format=BF_565;
  495.   else
  496.     format=BF_888;
  497.   ReleaseDC(NULL,hDC);
  498.   return format;
  499. }
  500. static imagestore *bminit(HDC hDC,int w,int h,int maxw,int maxh,int rotate)
  501. {
  502.   struct {
  503.     BITMAPINFOHEADER  h;
  504.     DWORD       masks[3];
  505.   } bi;
  506.   imagestore *im=(imagestore*)malloc(sizeof(imagestore));
  507.   if (!im)
  508.     return NULL;
  509.   void *data;
  510.   int bpp;
  511.   s32 rowstep;
  512.   im->bmformat=get_bitmap_format();
  513.   memset(&bi,0,sizeof(bi));
  514.   switch (im->bmformat) {
  515.   case BF_555:
  516.     bpp=2;
  517.     bi.masks[0]=0x7C00;
  518.     bi.masks[1]=0x03E0;
  519.     bi.masks[2]=0x001F;
  520.     bi.h.biCompression=BI_BITFIELDS;
  521.     im->packbits=packbits_24_to_15;
  522.     break;
  523.   case BF_565:
  524.     bpp=2;
  525.     bi.masks[0]=0xF800;
  526.     bi.masks[1]=0x07E0;
  527.     bi.masks[2]=0x001F;
  528.     bi.h.biCompression=BI_BITFIELDS;
  529.     im->packbits=packbits_24_to_16;
  530.     break;
  531.   case BF_888:
  532.     bpp=3;
  533. #ifdef _WIN32_WCE
  534.     bi.masks[0]=0xFF0000;
  535.     bi.masks[1]=0x00FF00;
  536.     bi.masks[2]=0x0000FF;
  537.     bi.h.biCompression=BI_BITFIELDS;
  538. #else
  539.     bi.h.biCompression=BI_RGB;
  540. #endif
  541.     im->packbits=packbits_24_to_24;
  542.     break;
  543. #ifndef STANDALONE
  544.   default:
  545.     ASSERT(0);
  546. #endif
  547.   }
  548.   if (w<=maxw && h<=maxh) {
  549.     im->width=w;
  550.     im->height=h;
  551.   } else {
  552.     if (maxw*h<maxh*w) {
  553.       im->width=maxw;
  554.       im->height=(h*maxw)/w;
  555.     } else {
  556.       im->width=(w*maxh)/h;
  557.       im->height=maxh;
  558.     }
  559.   }
  560.   if (rotate==0 || rotate==1800) {
  561.     im->realheight=im->height;
  562.     im->realwidth=im->width;
  563.   } else {
  564.     im->realheight=im->width;
  565.     im->realwidth=im->height;
  566.   }
  567.   if (!hDC)
  568.     return im;
  569.   rowstep=(im->realwidth*bpp+3)&~3;
  570.   bi.h.biSize=sizeof(bi.h);
  571.   bi.h.biWidth=im->realwidth;
  572.   bi.h.biHeight=im->realheight;
  573.   bi.h.biPlanes=1;
  574.   bi.h.biBitCount=bpp==2 ? 16 : 24;
  575.   if (!(im->bmp=CreateDIBSection(hDC,(BITMAPINFO*)&bi,DIB_RGB_COLORS,&data,NULL,0))) {
  576.     DWORD err=GetLastError();
  577.     free(im);
  578.     return NULL;
  579.   }
  580.   switch (rotate) {
  581.   case 2700:
  582.     im->hstep=-rowstep;
  583.     im->vstep=-bpp;
  584.     im->bits=(u8*)data+bpp*(im->realwidth-1)+rowstep*(im->realheight-1);
  585.     break;
  586.   case 1800:
  587.     im->hstep=-bpp;
  588.     im->vstep=rowstep;
  589.     im->bits=(u8*)data+bpp*(im->realwidth-1);
  590.     break;
  591.   case 900:
  592.     im->hstep=rowstep;
  593.     im->vstep=bpp;
  594.     im->bits=(u8*)data;
  595.     break;
  596.   case 0:
  597.     im->hstep=bpp;
  598.     im->vstep=-rowstep;
  599.     im->bits=(u8*)data+rowstep*(im->realheight-1);
  600.     break;
  601. #ifndef STANDALONE
  602.   default:
  603.     ASSERT(0);
  604. #endif
  605.   }
  606.   return im;
  607. }
  608. bool ImageLoader::Load(HDC hDC,const wchar_t *type,ImageLoader::BinReader *rdr,
  609.   int maxwidth,int maxheight,int rotation,HBITMAP& bmp,
  610.   int& width,int& height)
  611. {
  612.   imagestore     *is=NULL;
  613.   resize_state     *rs=NULL;
  614.   set_gamma(0.45455);
  615.   if (!wcscmp(type,L"image/jpeg")) { // only jpeg images are supported at the time
  616.     struct jpeg_decompress_struct   cinfo;
  617.     struct my_error_mgr     jerr;
  618.     cinfo.err=jpeg_std_error(&jerr.pub);
  619.     jerr.pub.error_exit=je_error_exit;
  620.     jerr.pub.output_message=je_output_message;
  621.     if (setjmp(jerr.jb))
  622.       goto common_exit;
  623.     jpeg_create_decompress(&cinfo);
  624.     prepare_buffer(&cinfo,rdr);
  625.     jpeg_read_header(&cinfo,TRUE);
  626.     // do some scaling
  627.     int scale,iw;
  628.     for (scale=1,iw=cinfo.image_width;scale<8;scale<<=1,iw>>=1)
  629.       if ((iw>>1)<maxwidth)
  630. break;
  631.     cinfo.scale_denom=scale;
  632.     cinfo.out_color_space=JCS_RGB;
  633.     jpeg_calc_output_dimensions(&cinfo);
  634.     is=bminit(hDC,cinfo.output_width,cinfo.output_height,maxwidth,maxheight,rotation);
  635.     if (is && hDC) {
  636.       if (is->width!=cinfo.output_width || is->height!=cinfo.output_height) {
  637. rs=resize_state_create(cinfo.output_width,cinfo.output_height,is);
  638. if (!rs)
  639.   goto outjpg;
  640.       }
  641.       jpeg_start_decompress(&cinfo);
  642.       JSAMPARRAY  line=cinfo.mem->alloc_sarray((j_common_ptr)&cinfo,
  643. JPOOL_IMAGE,cinfo.output_width*cinfo.output_components,
  644. 1);
  645.       if (rs) {
  646. while (cinfo.output_scanline<cinfo.output_height) {
  647.   jpeg_read_scanlines(&cinfo,line,1);
  648.   resize_add_line(rs,line[0]);
  649. }
  650.       } else {
  651. while (cinfo.output_scanline<cinfo.output_height) {
  652.   jpeg_read_scanlines(&cinfo,line,1);
  653.   is->packbits(is,line[0]);
  654. }
  655.       }
  656.       jpeg_finish_decompress(&cinfo);
  657.     }
  658. outjpg:
  659.     jpeg_destroy_decompress(&cinfo);
  660.   } else if (!wcscmp(type,L"image/png")) {
  661.     // create png read structures
  662.     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
  663.     if (!png_ptr) // out of memory?
  664.       return false;
  665.     png_infop info_ptr = png_create_info_struct(png_ptr);
  666.     if (!info_ptr) { // out of memory?
  667.       png_destroy_read_struct(&png_ptr,NULL,NULL);
  668.       return false;
  669.     }
  670.     // setup i/o routine
  671.     png_set_read_fn(png_ptr,rdr,pngr_read_data);
  672.     // init jmpbuf
  673.     if (setjmp(png_jmpbuf(png_ptr))) { // error occurred
  674.       png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
  675.       goto common_exit;
  676.     }
  677.     png_read_info(png_ptr,info_ptr);
  678.     png_uint_32 width,height;
  679.     int bit_depth,color_type,interlace_type;
  680.     png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,&color_type,
  681.  &interlace_type,NULL,NULL);
  682.     if (interlace_type!=PNG_INTERLACE_NONE) {
  683.       png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
  684.       return false;
  685.     }
  686.     // configure transformations, we always want RGB data in the end
  687.     if (color_type == PNG_COLOR_TYPE_PALETTE)
  688.       png_set_palette_to_rgb(png_ptr);
  689.     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
  690.       png_set_gray_1_2_4_to_8(png_ptr);
  691.     if (png_get_valid(png_ptr, info_ptr,PNG_INFO_tRNS))
  692.       png_set_tRNS_to_alpha(png_ptr);
  693.     if (bit_depth == 16)
  694.       png_set_strip_16(png_ptr);
  695.     if (bit_depth < 8)
  696.       png_set_packing(png_ptr);
  697.     if (color_type == PNG_COLOR_TYPE_GRAY ||
  698.         color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  699.       png_set_gray_to_rgb(png_ptr);
  700.     // update info after applying transformations
  701.     png_read_update_info(png_ptr,info_ptr);
  702.     // reload info
  703.     png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth,&color_type,
  704.  &interlace_type,NULL,NULL);
  705.     // ok, now configure storer and resizer
  706.     is=bminit(hDC,width,height,maxwidth,maxheight,rotation);
  707.     if (is && hDC) {
  708.       if (is->width!=width || is->height!=height) {
  709. rs=resize_state_create(width,height,is);
  710. if (!rs)
  711.   goto outpng;
  712.       }
  713.       // handle transparency
  714.       if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
  715. // create a resizer, because we use it to apply
  716. // transparency
  717. if (!rs) {
  718.   rs=resize_state_create(width,height,is);
  719.   if (!rs)
  720.     goto outpng;
  721. }
  722. png_color_16p image_background;
  723. if (png_get_bKGD(png_ptr, info_ptr, &image_background))
  724.   resize_set_alpha(rs,RGB(image_background->red>>8,
  725.   image_background->green>>8,
  726.   image_background->blue>>8));
  727. else
  728.   resize_set_alpha(rs,::GetBkColor(hDC));
  729.       }
  730.       // now read the image line by line
  731.       int rowbytes=png_get_rowbytes(png_ptr,info_ptr);
  732.       unsigned char *row=(unsigned char *)malloc(rowbytes);
  733.       if (!row)
  734. goto outpng;
  735.       if (rs) {
  736. for (int i=0;i<(int)height;++i) {
  737.   png_read_row(png_ptr,row,NULL);
  738.   resize_add_line(rs,row);
  739. }
  740.       } else {
  741. for (int i=0;i<(int)height;++i) {
  742.   png_read_row(png_ptr,row,NULL);
  743.   is->packbits(is,row);
  744. }
  745.       }
  746.       // destroy read struct
  747.       free(row);
  748.       png_read_end(png_ptr,NULL);
  749.     }
  750. outpng:
  751.     png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
  752.   } else
  753.     return false;
  754. common_exit:
  755.   if (is) {
  756.     bmp=is->bmp;
  757.     width=is->width;
  758.     height=is->height;
  759.   }
  760.   resize_state_destroy(rs);
  761.   free(is);
  762.   return is!=NULL;
  763. }