ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

image.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Google (Evan Stade)
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include <stdarg.h>
00020 
00021 #define NONAMELESSUNION
00022 
00023 #include "windef.h"
00024 #include "winbase.h"
00025 #include "winuser.h"
00026 #include "wingdi.h"
00027 
00028 #define COBJMACROS
00029 #include "objbase.h"
00030 #include "olectl.h"
00031 #include "ole2.h"
00032 
00033 #include "initguid.h"
00034 #include "wincodec.h"
00035 #include "gdiplus.h"
00036 #include "gdiplus_private.h"
00037 #include "wine/debug.h"
00038 
00039 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
00040 
00041 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
00042 
00043 static INT ipicture_pixel_height(IPicture *pic)
00044 {
00045     HDC hdcref;
00046     OLE_YSIZE_HIMETRIC y;
00047 
00048     IPicture_get_Height(pic, &y);
00049 
00050     hdcref = GetDC(0);
00051 
00052     y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
00053     ReleaseDC(0, hdcref);
00054 
00055     return y;
00056 }
00057 
00058 static INT ipicture_pixel_width(IPicture *pic)
00059 {
00060     HDC hdcref;
00061     OLE_XSIZE_HIMETRIC x;
00062 
00063     IPicture_get_Width(pic, &x);
00064 
00065     hdcref = GetDC(0);
00066 
00067     x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
00068 
00069     ReleaseDC(0, hdcref);
00070 
00071     return x;
00072 }
00073 
00074 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
00075     RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
00076 {
00077     FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
00078     /*
00079      * Note: According to Jose Roca's GDI+ docs, this function is not
00080      * implemented in Windows's GDI+.
00081      */
00082     return NotImplemented;
00083 }
00084 
00085 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
00086     INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
00087     GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
00088 {
00089     FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
00090     /*
00091      * Note: According to Jose Roca's GDI+ docs, this function is not
00092      * implemented in Windows's GDI+.
00093      */
00094     return NotImplemented;
00095 }
00096 
00097 static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
00098 {
00099     *index = (row[x/8]>>(7-x%8)) & 1;
00100 }
00101 
00102 static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
00103 {
00104     if (x & 1)
00105         *index = row[x/2]&0xf;
00106     else
00107         *index = row[x/2]>>4;
00108 }
00109 
00110 static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
00111 {
00112     *index = row[x];
00113 }
00114 
00115 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00116     const BYTE *row, UINT x)
00117 {
00118     *r = *g = *b = row[x*2+1];
00119     *a = 255;
00120 }
00121 
00122 static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00123     const BYTE *row, UINT x)
00124 {
00125     WORD pixel = *((const WORD*)(row)+x);
00126     *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
00127     *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
00128     *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
00129     *a = 255;
00130 }
00131 
00132 static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00133     const BYTE *row, UINT x)
00134 {
00135     WORD pixel = *((const WORD*)(row)+x);
00136     *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
00137     *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
00138     *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
00139     *a = 255;
00140 }
00141 
00142 static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00143     const BYTE *row, UINT x)
00144 {
00145     WORD pixel = *((const WORD*)(row)+x);
00146     *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
00147     *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
00148     *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
00149     if ((pixel&0x8000) == 0x8000)
00150         *a = 255;
00151     else
00152         *a = 0;
00153 }
00154 
00155 static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00156     const BYTE *row, UINT x)
00157 {
00158     *r = row[x*3+2];
00159     *g = row[x*3+1];
00160     *b = row[x*3];
00161     *a = 255;
00162 }
00163 
00164 static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00165     const BYTE *row, UINT x)
00166 {
00167     *r = row[x*4+2];
00168     *g = row[x*4+1];
00169     *b = row[x*4];
00170     *a = 255;
00171 }
00172 
00173 static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00174     const BYTE *row, UINT x)
00175 {
00176     *r = row[x*4+2];
00177     *g = row[x*4+1];
00178     *b = row[x*4];
00179     *a = row[x*4+3];
00180 }
00181 
00182 static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00183     const BYTE *row, UINT x)
00184 {
00185     *a = row[x*4+3];
00186     if (*a == 0)
00187         *r = *g = *b = 0;
00188     else
00189     {
00190         *r = row[x*4+2] * 255 / *a;
00191         *g = row[x*4+1] * 255 / *a;
00192         *b = row[x*4] * 255 / *a;
00193     }
00194 }
00195 
00196 static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00197     const BYTE *row, UINT x)
00198 {
00199     *r = row[x*6+5];
00200     *g = row[x*6+3];
00201     *b = row[x*6+1];
00202     *a = 255;
00203 }
00204 
00205 static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00206     const BYTE *row, UINT x)
00207 {
00208     *r = row[x*8+5];
00209     *g = row[x*8+3];
00210     *b = row[x*8+1];
00211     *a = row[x*8+7];
00212 }
00213 
00214 static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
00215     const BYTE *row, UINT x)
00216 {
00217     *a = row[x*8+7];
00218     if (*a == 0)
00219         *r = *g = *b = 0;
00220     else
00221     {
00222         *r = row[x*8+5] * 255 / *a;
00223         *g = row[x*8+3] * 255 / *a;
00224         *b = row[x*8+1] * 255 / *a;
00225     }
00226 }
00227 
00228 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
00229     ARGB *color)
00230 {
00231     BYTE r, g, b, a;
00232     BYTE index;
00233     BYTE *row;
00234     TRACE("%p %d %d %p\n", bitmap, x, y, color);
00235 
00236     if(!bitmap || !color ||
00237        x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
00238         return InvalidParameter;
00239 
00240     row = bitmap->bits+bitmap->stride*y;
00241 
00242     switch (bitmap->format)
00243     {
00244         case PixelFormat1bppIndexed:
00245             getpixel_1bppIndexed(&index,row,x);
00246             break;
00247         case PixelFormat4bppIndexed:
00248             getpixel_4bppIndexed(&index,row,x);
00249             break;
00250         case PixelFormat8bppIndexed:
00251             getpixel_8bppIndexed(&index,row,x);
00252             break;
00253         case PixelFormat16bppGrayScale:
00254             getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
00255             break;
00256         case PixelFormat16bppRGB555:
00257             getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
00258             break;
00259         case PixelFormat16bppRGB565:
00260             getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
00261             break;
00262         case PixelFormat16bppARGB1555:
00263             getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
00264             break;
00265         case PixelFormat24bppRGB:
00266             getpixel_24bppRGB(&r,&g,&b,&a,row,x);
00267             break;
00268         case PixelFormat32bppRGB:
00269             getpixel_32bppRGB(&r,&g,&b,&a,row,x);
00270             break;
00271         case PixelFormat32bppARGB:
00272             getpixel_32bppARGB(&r,&g,&b,&a,row,x);
00273             break;
00274         case PixelFormat32bppPARGB:
00275             getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
00276             break;
00277         case PixelFormat48bppRGB:
00278             getpixel_48bppRGB(&r,&g,&b,&a,row,x);
00279             break;
00280         case PixelFormat64bppARGB:
00281             getpixel_64bppARGB(&r,&g,&b,&a,row,x);
00282             break;
00283         case PixelFormat64bppPARGB:
00284             getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
00285             break;
00286         default:
00287             FIXME("not implemented for format 0x%x\n", bitmap->format);
00288             return NotImplemented;
00289     }
00290 
00291     if (bitmap->format & PixelFormatIndexed)
00292         *color = bitmap->image.palette_entries[index];
00293     else
00294         *color = a<<24|r<<16|g<<8|b;
00295 
00296     return Ok;
00297 }
00298 
00299 static inline UINT get_palette_index(BYTE r, BYTE g, BYTE b, BYTE a, GpBitmap* bitmap) {
00300     BYTE index = 0;
00301     int best_distance = 0x7fff;
00302     int distance;
00303     int i;
00304     /* This algorithm scans entire palette,
00305        computes difference from desired color (all color components have equal weight)
00306        and returns the index of color with least difference.
00307 
00308        Note: Maybe it could be replaced with a better algorithm for better image quality
00309        and performance, though better algorithm would probably need some pre-built lookup
00310        tables and thus may actually be slower if this method is called only few times per
00311        every image.
00312     */
00313     for(i=0;i<bitmap->image.palette_size;i++) {
00314         ARGB color=bitmap->image.palette_entries[i];
00315         distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff));
00316         if (distance<best_distance) {
00317             best_distance=distance;
00318             index=i;
00319         }
00320     }
00321     return index;
00322 }
00323 
00324 static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
00325     BYTE *row, UINT x, GpBitmap* bitmap)
00326 {
00327      BYTE index = get_palette_index(r,g,b,a,bitmap);
00328      row[x]=index;
00329 }
00330 
00331 static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
00332     BYTE *row, UINT x, GpBitmap* bitmap)
00333 {
00334     row[x/8]  = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,bitmap)<<(7-x%8));
00335 }
00336 
00337 static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
00338     BYTE *row, UINT x, GpBitmap* bitmap)
00339 {
00340     if (x & 1)
00341         row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,bitmap);
00342     else
00343         row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,bitmap)<<4;
00344 }
00345 
00346 static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
00347     BYTE *row, UINT x)
00348 {
00349     *((WORD*)(row)+x) = (r+g+b)*85;
00350 }
00351 
00352 static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
00353     BYTE *row, UINT x)
00354 {
00355     *((WORD*)(row)+x) = (r<<7&0x7c00)|
00356                         (g<<2&0x03e0)|
00357                         (b>>3&0x001f);
00358 }
00359 
00360 static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
00361     BYTE *row, UINT x)
00362 {
00363     *((WORD*)(row)+x) = (r<<8&0xf800)|
00364                          (g<<3&0x07e0)|
00365                          (b>>3&0x001f);
00366 }
00367 
00368 static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
00369     BYTE *row, UINT x)
00370 {
00371     *((WORD*)(row)+x) = (a<<8&0x8000)|
00372                         (r<<7&0x7c00)|
00373                         (g<<2&0x03e0)|
00374                         (b>>3&0x001f);
00375 }
00376 
00377 static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
00378     BYTE *row, UINT x)
00379 {
00380     row[x*3+2] = r;
00381     row[x*3+1] = g;
00382     row[x*3] = b;
00383 }
00384 
00385 static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
00386     BYTE *row, UINT x)
00387 {
00388     *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
00389 }
00390 
00391 static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
00392     BYTE *row, UINT x)
00393 {
00394     *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
00395 }
00396 
00397 static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
00398     BYTE *row, UINT x)
00399 {
00400     r = r * a / 255;
00401     g = g * a / 255;
00402     b = b * a / 255;
00403     *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
00404 }
00405 
00406 static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
00407     BYTE *row, UINT x)
00408 {
00409     row[x*6+5] = row[x*6+4] = r;
00410     row[x*6+3] = row[x*6+2] = g;
00411     row[x*6+1] = row[x*6] = b;
00412 }
00413 
00414 static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
00415     BYTE *row, UINT x)
00416 {
00417     UINT64 a64=a, r64=r, g64=g, b64=b;
00418     *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
00419 }
00420 
00421 static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
00422     BYTE *row, UINT x)
00423 {
00424     UINT64 a64, r64, g64, b64;
00425     a64 = a * 257;
00426     r64 = r * a / 255;
00427     g64 = g * a / 255;
00428     b64 = b * a / 255;
00429     *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
00430 }
00431 
00432 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
00433     ARGB color)
00434 {
00435     BYTE a, r, g, b;
00436     BYTE *row;
00437     TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
00438 
00439     if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
00440         return InvalidParameter;
00441 
00442     a = color>>24;
00443     r = color>>16;
00444     g = color>>8;
00445     b = color;
00446 
00447     row = bitmap->bits + bitmap->stride * y;
00448 
00449     switch (bitmap->format)
00450     {
00451         case PixelFormat16bppGrayScale:
00452             setpixel_16bppGrayScale(r,g,b,a,row,x);
00453             break;
00454         case PixelFormat16bppRGB555:
00455             setpixel_16bppRGB555(r,g,b,a,row,x);
00456             break;
00457         case PixelFormat16bppRGB565:
00458             setpixel_16bppRGB565(r,g,b,a,row,x);
00459             break;
00460         case PixelFormat16bppARGB1555:
00461             setpixel_16bppARGB1555(r,g,b,a,row,x);
00462             break;
00463         case PixelFormat24bppRGB:
00464             setpixel_24bppRGB(r,g,b,a,row,x);
00465             break;
00466         case PixelFormat32bppRGB:
00467             setpixel_32bppRGB(r,g,b,a,row,x);
00468             break;
00469         case PixelFormat32bppARGB:
00470             setpixel_32bppARGB(r,g,b,a,row,x);
00471             break;
00472         case PixelFormat32bppPARGB:
00473             setpixel_32bppPARGB(r,g,b,a,row,x);
00474             break;
00475         case PixelFormat48bppRGB:
00476             setpixel_48bppRGB(r,g,b,a,row,x);
00477             break;
00478         case PixelFormat64bppARGB:
00479             setpixel_64bppARGB(r,g,b,a,row,x);
00480             break;
00481         case PixelFormat64bppPARGB:
00482             setpixel_64bppPARGB(r,g,b,a,row,x);
00483             break;
00484         case PixelFormat8bppIndexed:
00485             setpixel_8bppIndexed(r,g,b,a,row,x,bitmap);
00486             break;
00487         case PixelFormat4bppIndexed:
00488             setpixel_4bppIndexed(r,g,b,a,row,x,bitmap);
00489             break;
00490         case PixelFormat1bppIndexed:
00491             setpixel_1bppIndexed(r,g,b,a,row,x,bitmap);
00492             break;
00493         default:
00494             FIXME("not implemented for format 0x%x\n", bitmap->format);
00495             return NotImplemented;
00496     }
00497 
00498     return Ok;
00499 }
00500 
00501 GpStatus convert_pixels(INT width, INT height,
00502     INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
00503     INT src_stride, const BYTE *src_bits, PixelFormat src_format, ARGB *src_palette)
00504 {
00505     INT x, y;
00506 
00507     if (src_format == dst_format ||
00508         (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
00509     {
00510         UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
00511         for (y=0; y<height; y++)
00512             memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
00513         return Ok;
00514     }
00515 
00516 #define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
00517     for (x=0; x<width; x++) \
00518         for (y=0; y<height; y++) { \
00519             BYTE index; \
00520             BYTE *color; \
00521             getpixel_function(&index, src_bits+src_stride*y, x); \
00522             color = (BYTE*)(&src_palette[index]); \
00523             setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
00524         } \
00525     return Ok; \
00526 } while (0);
00527 
00528 #define convert_rgb_to_rgb(getpixel_function, setpixel_function) do { \
00529     for (x=0; x<width; x++) \
00530         for (y=0; y<height; y++) { \
00531             BYTE r, g, b, a; \
00532             getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
00533             setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x); \
00534         } \
00535     return Ok; \
00536 } while (0);
00537 
00538     switch (src_format)
00539     {
00540     case PixelFormat1bppIndexed:
00541         switch (dst_format)
00542         {
00543         case PixelFormat16bppGrayScale:
00544             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppGrayScale);
00545         case PixelFormat16bppRGB555:
00546             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB555);
00547         case PixelFormat16bppRGB565:
00548             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB565);
00549         case PixelFormat16bppARGB1555:
00550             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppARGB1555);
00551         case PixelFormat24bppRGB:
00552             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_24bppRGB);
00553         case PixelFormat32bppRGB:
00554             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppRGB);
00555         case PixelFormat32bppARGB:
00556             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppARGB);
00557         case PixelFormat32bppPARGB:
00558             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppPARGB);
00559         case PixelFormat48bppRGB:
00560             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_48bppRGB);
00561         case PixelFormat64bppARGB:
00562             convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_64bppARGB);
00563         default:
00564             break;
00565         }
00566         break;
00567     case PixelFormat4bppIndexed:
00568         switch (dst_format)
00569         {
00570         case PixelFormat16bppGrayScale:
00571             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppGrayScale);
00572         case PixelFormat16bppRGB555:
00573             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB555);
00574         case PixelFormat16bppRGB565:
00575             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB565);
00576         case PixelFormat16bppARGB1555:
00577             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppARGB1555);
00578         case PixelFormat24bppRGB:
00579             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_24bppRGB);
00580         case PixelFormat32bppRGB:
00581             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppRGB);
00582         case PixelFormat32bppARGB:
00583             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppARGB);
00584         case PixelFormat32bppPARGB:
00585             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppPARGB);
00586         case PixelFormat48bppRGB:
00587             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_48bppRGB);
00588         case PixelFormat64bppARGB:
00589             convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_64bppARGB);
00590         default:
00591             break;
00592         }
00593         break;
00594     case PixelFormat8bppIndexed:
00595         switch (dst_format)
00596         {
00597         case PixelFormat16bppGrayScale:
00598             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppGrayScale);
00599         case PixelFormat16bppRGB555:
00600             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB555);
00601         case PixelFormat16bppRGB565:
00602             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB565);
00603         case PixelFormat16bppARGB1555:
00604             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppARGB1555);
00605         case PixelFormat24bppRGB:
00606             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_24bppRGB);
00607         case PixelFormat32bppRGB:
00608             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppRGB);
00609         case PixelFormat32bppARGB:
00610             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppARGB);
00611         case PixelFormat32bppPARGB:
00612             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppPARGB);
00613         case PixelFormat48bppRGB:
00614             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_48bppRGB);
00615         case PixelFormat64bppARGB:
00616             convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_64bppARGB);
00617         default:
00618             break;
00619         }
00620         break;
00621     case PixelFormat16bppGrayScale:
00622         switch (dst_format)
00623         {
00624         case PixelFormat16bppRGB555:
00625             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555);
00626         case PixelFormat16bppRGB565:
00627             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB565);
00628         case PixelFormat16bppARGB1555:
00629             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppARGB1555);
00630         case PixelFormat24bppRGB:
00631             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_24bppRGB);
00632         case PixelFormat32bppRGB:
00633             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppRGB);
00634         case PixelFormat32bppARGB:
00635             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppARGB);
00636         case PixelFormat32bppPARGB:
00637             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppPARGB);
00638         case PixelFormat48bppRGB:
00639             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_48bppRGB);
00640         case PixelFormat64bppARGB:
00641             convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_64bppARGB);
00642         default:
00643             break;
00644         }
00645         break;
00646     case PixelFormat16bppRGB555:
00647         switch (dst_format)
00648         {
00649         case PixelFormat16bppGrayScale:
00650             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale);
00651         case PixelFormat16bppRGB565:
00652             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppRGB565);
00653         case PixelFormat16bppARGB1555:
00654             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppARGB1555);
00655         case PixelFormat24bppRGB:
00656             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_24bppRGB);
00657         case PixelFormat32bppRGB:
00658             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppRGB);
00659         case PixelFormat32bppARGB:
00660             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppARGB);
00661         case PixelFormat32bppPARGB:
00662             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppPARGB);
00663         case PixelFormat48bppRGB:
00664             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_48bppRGB);
00665         case PixelFormat64bppARGB:
00666             convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_64bppARGB);
00667         default:
00668             break;
00669         }
00670         break;
00671     case PixelFormat16bppRGB565:
00672         switch (dst_format)
00673         {
00674         case PixelFormat16bppGrayScale:
00675             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale);
00676         case PixelFormat16bppRGB555:
00677             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppRGB555);
00678         case PixelFormat16bppARGB1555:
00679             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppARGB1555);
00680         case PixelFormat24bppRGB:
00681             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_24bppRGB);
00682         case PixelFormat32bppRGB:
00683             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppRGB);
00684         case PixelFormat32bppARGB:
00685             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppARGB);
00686         case PixelFormat32bppPARGB:
00687             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppPARGB);
00688         case PixelFormat48bppRGB:
00689             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_48bppRGB);
00690         case PixelFormat64bppARGB:
00691             convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_64bppARGB);
00692         default:
00693             break;
00694         }
00695         break;
00696     case PixelFormat16bppARGB1555:
00697         switch (dst_format)
00698         {
00699         case PixelFormat16bppGrayScale:
00700             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale);
00701         case PixelFormat16bppRGB555:
00702             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB555);
00703         case PixelFormat16bppRGB565:
00704             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB565);
00705         case PixelFormat24bppRGB:
00706             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_24bppRGB);
00707         case PixelFormat32bppRGB:
00708             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppRGB);
00709         case PixelFormat32bppARGB:
00710             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppARGB);
00711         case PixelFormat32bppPARGB:
00712             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppPARGB);
00713         case PixelFormat48bppRGB:
00714             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_48bppRGB);
00715         case PixelFormat64bppARGB:
00716             convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_64bppARGB);
00717         default:
00718             break;
00719         }
00720         break;
00721     case PixelFormat24bppRGB:
00722         switch (dst_format)
00723         {
00724         case PixelFormat16bppGrayScale:
00725             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale);
00726         case PixelFormat16bppRGB555:
00727             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB555);
00728         case PixelFormat16bppRGB565:
00729             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB565);
00730         case PixelFormat16bppARGB1555:
00731             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppARGB1555);
00732         case PixelFormat32bppRGB:
00733             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppRGB);
00734         case PixelFormat32bppARGB:
00735             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppARGB);
00736         case PixelFormat32bppPARGB:
00737             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppPARGB);
00738         case PixelFormat48bppRGB:
00739             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_48bppRGB);
00740         case PixelFormat64bppARGB:
00741             convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_64bppARGB);
00742         default:
00743             break;
00744         }
00745         break;
00746     case PixelFormat32bppRGB:
00747         switch (dst_format)
00748         {
00749         case PixelFormat16bppGrayScale:
00750             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale);
00751         case PixelFormat16bppRGB555:
00752             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB555);
00753         case PixelFormat16bppRGB565:
00754             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB565);
00755         case PixelFormat16bppARGB1555:
00756             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppARGB1555);
00757         case PixelFormat24bppRGB:
00758             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_24bppRGB);
00759         case PixelFormat32bppARGB:
00760             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppARGB);
00761         case PixelFormat32bppPARGB:
00762             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppPARGB);
00763         case PixelFormat48bppRGB:
00764             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_48bppRGB);
00765         case PixelFormat64bppARGB:
00766             convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_64bppARGB);
00767         default:
00768             break;
00769         }
00770         break;
00771     case PixelFormat32bppARGB:
00772         switch (dst_format)
00773         {
00774         case PixelFormat16bppGrayScale:
00775             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale);
00776         case PixelFormat16bppRGB555:
00777             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB555);
00778         case PixelFormat16bppRGB565:
00779             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB565);
00780         case PixelFormat16bppARGB1555:
00781             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppARGB1555);
00782         case PixelFormat24bppRGB:
00783             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_24bppRGB);
00784         case PixelFormat32bppPARGB:
00785             convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
00786             return Ok;
00787         case PixelFormat48bppRGB:
00788             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_48bppRGB);
00789         case PixelFormat64bppARGB:
00790             convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_64bppARGB);
00791         default:
00792             break;
00793         }
00794         break;
00795     case PixelFormat32bppPARGB:
00796         switch (dst_format)
00797         {
00798         case PixelFormat16bppGrayScale:
00799             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale);
00800         case PixelFormat16bppRGB555:
00801             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB555);
00802         case PixelFormat16bppRGB565:
00803             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB565);
00804         case PixelFormat16bppARGB1555:
00805             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppARGB1555);
00806         case PixelFormat24bppRGB:
00807             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_24bppRGB);
00808         case PixelFormat32bppRGB:
00809             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppRGB);
00810         case PixelFormat32bppARGB:
00811             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppARGB);
00812         case PixelFormat48bppRGB:
00813             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_48bppRGB);
00814         case PixelFormat64bppARGB:
00815             convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_64bppARGB);
00816         default:
00817             break;
00818         }
00819         break;
00820     case PixelFormat48bppRGB:
00821         switch (dst_format)
00822         {
00823         case PixelFormat16bppGrayScale:
00824             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale);
00825         case PixelFormat16bppRGB555:
00826             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB555);
00827         case PixelFormat16bppRGB565:
00828             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB565);
00829         case PixelFormat16bppARGB1555:
00830             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppARGB1555);
00831         case PixelFormat24bppRGB:
00832             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_24bppRGB);
00833         case PixelFormat32bppRGB:
00834             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppRGB);
00835         case PixelFormat32bppARGB:
00836             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppARGB);
00837         case PixelFormat32bppPARGB:
00838             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppPARGB);
00839         case PixelFormat64bppARGB:
00840             convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_64bppARGB);
00841         default:
00842             break;
00843         }
00844         break;
00845     case PixelFormat64bppARGB:
00846         switch (dst_format)
00847         {
00848         case PixelFormat16bppGrayScale:
00849             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale);
00850         case PixelFormat16bppRGB555:
00851             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB555);
00852         case PixelFormat16bppRGB565:
00853             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB565);
00854         case PixelFormat16bppARGB1555:
00855             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppARGB1555);
00856         case PixelFormat24bppRGB:
00857             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_24bppRGB);
00858         case PixelFormat32bppRGB:
00859             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppRGB);
00860         case PixelFormat32bppARGB:
00861             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppARGB);
00862         case PixelFormat32bppPARGB:
00863             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppPARGB);
00864         case PixelFormat48bppRGB:
00865             convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_48bppRGB);
00866         default:
00867             break;
00868         }
00869         break;
00870     case PixelFormat64bppPARGB:
00871         switch (dst_format)
00872         {
00873         case PixelFormat16bppGrayScale:
00874             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale);
00875         case PixelFormat16bppRGB555:
00876             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB555);
00877         case PixelFormat16bppRGB565:
00878             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB565);
00879         case PixelFormat16bppARGB1555:
00880             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppARGB1555);
00881         case PixelFormat24bppRGB:
00882             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_24bppRGB);
00883         case PixelFormat32bppRGB:
00884             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppRGB);
00885         case PixelFormat32bppARGB:
00886             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppARGB);
00887         case PixelFormat32bppPARGB:
00888             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppPARGB);
00889         case PixelFormat48bppRGB:
00890             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_48bppRGB);
00891         case PixelFormat64bppARGB:
00892             convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_64bppARGB);
00893         default:
00894             break;
00895         }
00896         break;
00897     default:
00898         break;
00899     }
00900 
00901 #undef convert_indexed_to_rgb
00902 #undef convert_rgb_to_rgb
00903 
00904     return NotImplemented;
00905 }
00906 
00907 /* This function returns a pointer to an array of pixels that represents the
00908  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
00909  * flags.  It is correct behavior that a user who calls this function with write
00910  * privileges can write to the whole bitmap (not just the area in rect).
00911  *
00912  * FIXME: only used portion of format is bits per pixel. */
00913 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
00914     UINT flags, PixelFormat format, BitmapData* lockeddata)
00915 {
00916     INT bitspp = PIXELFORMATBPP(format);
00917     GpRect act_rect; /* actual rect to be used */
00918     GpStatus stat;
00919 
00920     TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
00921 
00922     if(!lockeddata || !bitmap)
00923         return InvalidParameter;
00924 
00925     if(rect){
00926         if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
00927           (rect->Y + rect->Height > bitmap->height) || !flags)
00928             return InvalidParameter;
00929 
00930         act_rect = *rect;
00931     }
00932     else{
00933         act_rect.X = act_rect.Y = 0;
00934         act_rect.Width  = bitmap->width;
00935         act_rect.Height = bitmap->height;
00936     }
00937 
00938     if(bitmap->lockmode)
00939     {
00940         WARN("bitmap is already locked and cannot be locked again\n");
00941         return WrongState;
00942     }
00943 
00944     if (bitmap->bits && bitmap->format == format && !(flags & ImageLockModeUserInputBuf))
00945     {
00946         /* no conversion is necessary; just use the bits directly */
00947         lockeddata->Width = act_rect.Width;
00948         lockeddata->Height = act_rect.Height;
00949         lockeddata->PixelFormat = format;
00950         lockeddata->Reserved = flags;
00951         lockeddata->Stride = bitmap->stride;
00952         lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
00953                             bitmap->stride * act_rect.Y;
00954 
00955         bitmap->lockmode = flags;
00956         bitmap->numlocks++;
00957 
00958         return Ok;
00959     }
00960 
00961     /* Make sure we can convert to the requested format. */
00962     if (flags & ImageLockModeRead)
00963     {
00964         stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
00965         if (stat == NotImplemented)
00966         {
00967             FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
00968             return NotImplemented;
00969         }
00970     }
00971 
00972     /* If we're opening for writing, make sure we'll be able to write back in
00973      * the original format. */
00974     if (flags & ImageLockModeWrite)
00975     {
00976         stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
00977         if (stat == NotImplemented)
00978         {
00979             FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
00980             return NotImplemented;
00981         }
00982     }
00983 
00984     lockeddata->Width  = act_rect.Width;
00985     lockeddata->Height = act_rect.Height;
00986     lockeddata->PixelFormat = format;
00987     lockeddata->Reserved = flags;
00988 
00989     if(!(flags & ImageLockModeUserInputBuf))
00990     {
00991         lockeddata->Stride = (((act_rect.Width * bitspp + 7) / 8) + 3) & ~3;
00992 
00993         bitmap->bitmapbits = GdipAlloc(lockeddata->Stride * act_rect.Height);
00994 
00995         if (!bitmap->bitmapbits) return OutOfMemory;
00996 
00997         lockeddata->Scan0  = bitmap->bitmapbits;
00998     }
00999 
01000     if (flags & ImageLockModeRead)
01001     {
01002         static int fixme=0;
01003 
01004         if (!fixme && (PIXELFORMATBPP(bitmap->format) * act_rect.X) % 8 != 0)
01005         {
01006             FIXME("Cannot copy rows that don't start at a whole byte.\n");
01007             fixme = 1;
01008         }
01009 
01010         stat = convert_pixels(act_rect.Width, act_rect.Height,
01011             lockeddata->Stride, lockeddata->Scan0, format,
01012             bitmap->stride,
01013             bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8,
01014             bitmap->format, bitmap->image.palette_entries);
01015 
01016         if (stat != Ok)
01017         {
01018             GdipFree(bitmap->bitmapbits);
01019             bitmap->bitmapbits = NULL;
01020             return stat;
01021         }
01022     }
01023 
01024     bitmap->lockmode = flags;
01025     bitmap->numlocks++;
01026     bitmap->lockx = act_rect.X;
01027     bitmap->locky = act_rect.Y;
01028 
01029     return Ok;
01030 }
01031 
01032 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
01033 {
01034     TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
01035 
01036     if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
01037         return InvalidParameter;
01038 
01039     bitmap->image.xres = xdpi;
01040     bitmap->image.yres = ydpi;
01041 
01042     return Ok;
01043 }
01044 
01045 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
01046     BitmapData* lockeddata)
01047 {
01048     GpStatus stat;
01049     static int fixme=0;
01050 
01051     TRACE("(%p,%p)\n", bitmap, lockeddata);
01052 
01053     if(!bitmap || !lockeddata)
01054         return InvalidParameter;
01055 
01056     if(!bitmap->lockmode)
01057         return WrongState;
01058 
01059     if(!(lockeddata->Reserved & ImageLockModeWrite)){
01060         if(!(--bitmap->numlocks))
01061             bitmap->lockmode = 0;
01062 
01063         GdipFree(bitmap->bitmapbits);
01064         bitmap->bitmapbits = NULL;
01065         return Ok;
01066     }
01067 
01068     if (!bitmap->bitmapbits && !(lockeddata->Reserved & ImageLockModeUserInputBuf))
01069     {
01070         /* we passed a direct reference; no need to do anything */
01071         bitmap->lockmode = 0;
01072         bitmap->numlocks = 0;
01073         return Ok;
01074     }
01075 
01076     if (!fixme && (PIXELFORMATBPP(bitmap->format) * bitmap->lockx) % 8 != 0)
01077     {
01078         FIXME("Cannot copy rows that don't start at a whole byte.\n");
01079         fixme = 1;
01080     }
01081 
01082     stat = convert_pixels(lockeddata->Width, lockeddata->Height,
01083         bitmap->stride,
01084         bitmap->bits + bitmap->stride * bitmap->locky + PIXELFORMATBPP(bitmap->format) * bitmap->lockx / 8,
01085         bitmap->format,
01086         lockeddata->Stride, lockeddata->Scan0, lockeddata->PixelFormat, NULL);
01087 
01088     if (stat != Ok)
01089     {
01090         ERR("failed to convert pixels; this should never happen\n");
01091     }
01092 
01093     GdipFree(bitmap->bitmapbits);
01094     bitmap->bitmapbits = NULL;
01095     bitmap->lockmode = 0;
01096     bitmap->numlocks = 0;
01097 
01098     return stat;
01099 }
01100 
01101 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
01102     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
01103 {
01104     BitmapData lockeddata_src, lockeddata_dst;
01105     int i;
01106     UINT row_size;
01107     Rect area;
01108     GpStatus stat;
01109 
01110     TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
01111 
01112     if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
01113         x < 0 || y < 0 ||
01114         x + width > srcBitmap->width || y + height > srcBitmap->height)
01115     {
01116         TRACE("<-- InvalidParameter\n");
01117         return InvalidParameter;
01118     }
01119 
01120     if (format == PixelFormatDontCare)
01121         format = srcBitmap->format;
01122 
01123     area.X = roundr(x);
01124     area.Y = roundr(y);
01125     area.Width = roundr(width);
01126     area.Height = roundr(height);
01127 
01128     stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
01129         &lockeddata_src);
01130     if (stat != Ok) return stat;
01131 
01132     stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
01133         0, lockeddata_src.PixelFormat, NULL, dstBitmap);
01134     if (stat == Ok)
01135     {
01136         stat = GdipBitmapLockBits(*dstBitmap, NULL, ImageLockModeWrite,
01137             lockeddata_src.PixelFormat, &lockeddata_dst);
01138 
01139         if (stat == Ok)
01140         {
01141             /* copy the image data */
01142             row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
01143             for (i=0; i<lockeddata_src.Height; i++)
01144                 memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
01145                        (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
01146                        row_size);
01147 
01148             GdipBitmapUnlockBits(*dstBitmap, &lockeddata_dst);
01149         }
01150 
01151         if (stat != Ok)
01152             GdipDisposeImage((GpImage*)*dstBitmap);
01153     }
01154 
01155     GdipBitmapUnlockBits(srcBitmap, &lockeddata_src);
01156 
01157     if (stat != Ok)
01158     {
01159         *dstBitmap = NULL;
01160     }
01161 
01162     return stat;
01163 }
01164 
01165 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
01166     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
01167 {
01168     TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
01169 
01170     return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
01171 }
01172 
01173 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
01174 {
01175     GpStatus stat = GenericError;
01176 
01177     TRACE("%p, %p\n", image, cloneImage);
01178 
01179     if (!image || !cloneImage)
01180         return InvalidParameter;
01181 
01182     if (image->picture)
01183     {
01184         IStream* stream;
01185         HRESULT hr;
01186         INT size;
01187         LARGE_INTEGER move;
01188 
01189         hr = CreateStreamOnHGlobal(0, TRUE, &stream);
01190         if (FAILED(hr))
01191             return GenericError;
01192 
01193         hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
01194         if(FAILED(hr))
01195         {
01196             WARN("Failed to save image on stream\n");
01197             goto out;
01198         }
01199 
01200         /* Set seek pointer back to the beginning of the picture */
01201         move.QuadPart = 0;
01202         hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
01203         if (FAILED(hr))
01204             goto out;
01205 
01206         stat = GdipLoadImageFromStream(stream, cloneImage);
01207         if (stat != Ok) WARN("Failed to load image from stream\n");
01208 
01209     out:
01210         IStream_Release(stream);
01211         return stat;
01212     }
01213     else if (image->type == ImageTypeBitmap)
01214     {
01215         GpBitmap *bitmap = (GpBitmap*)image;
01216         BitmapData lockeddata_src, lockeddata_dst;
01217         int i;
01218         UINT row_size;
01219 
01220         stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
01221             &lockeddata_src);
01222         if (stat != Ok) return stat;
01223 
01224         stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
01225             0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
01226         if (stat == Ok)
01227         {
01228             stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
01229                 lockeddata_src.PixelFormat, &lockeddata_dst);
01230 
01231             if (stat == Ok)
01232             {
01233                 /* copy the image data */
01234                 row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
01235                 for (i=0; i<lockeddata_src.Height; i++)
01236                     memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
01237                            (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
01238                            row_size);
01239 
01240                 GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
01241             }
01242 
01243             if (stat != Ok)
01244                 GdipDisposeImage(*cloneImage);
01245         }
01246 
01247         GdipBitmapUnlockBits(bitmap, &lockeddata_src);
01248 
01249         if (stat != Ok)
01250         {
01251             *cloneImage = NULL;
01252         }
01253         else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
01254 
01255         return stat;
01256     }
01257     else
01258     {
01259         ERR("GpImage with no IPicture or bitmap?!\n");
01260         return NotImplemented;
01261     }
01262 }
01263 
01264 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
01265     GpBitmap **bitmap)
01266 {
01267     GpStatus stat;
01268     IStream *stream;
01269 
01270     TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
01271 
01272     if(!filename || !bitmap)
01273         return InvalidParameter;
01274 
01275     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
01276 
01277     if(stat != Ok)
01278         return stat;
01279 
01280     stat = GdipCreateBitmapFromStream(stream, bitmap);
01281 
01282     IStream_Release(stream);
01283 
01284     return stat;
01285 }
01286 
01287 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
01288                                                VOID *bits, GpBitmap **bitmap)
01289 {
01290     DWORD height, stride;
01291     PixelFormat format;
01292 
01293     FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
01294 
01295     if (!info || !bits || !bitmap)
01296         return InvalidParameter;
01297 
01298     height = abs(info->bmiHeader.biHeight);
01299     stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
01300 
01301     if(info->bmiHeader.biHeight > 0) /* bottom-up */
01302     {
01303         bits = (BYTE*)bits + (height - 1) * stride;
01304         stride = -stride;
01305     }
01306 
01307     switch(info->bmiHeader.biBitCount) {
01308     case 1:
01309         format = PixelFormat1bppIndexed;
01310         break;
01311     case 4:
01312         format = PixelFormat4bppIndexed;
01313         break;
01314     case 8:
01315         format = PixelFormat8bppIndexed;
01316         break;
01317     case 16:
01318         format = PixelFormat16bppRGB555;
01319         break;
01320     case 24:
01321         format = PixelFormat24bppRGB;
01322         break;
01323     case 32:
01324         format = PixelFormat32bppRGB;
01325         break;
01326     default:
01327         FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
01328         *bitmap = NULL;
01329         return InvalidParameter;
01330     }
01331 
01332     return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
01333                                      bits, bitmap);
01334 
01335 }
01336 
01337 /* FIXME: no icm */
01338 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
01339     GpBitmap **bitmap)
01340 {
01341     TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
01342 
01343     return GdipCreateBitmapFromFile(filename, bitmap);
01344 }
01345 
01346 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
01347     GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
01348 {
01349     HBITMAP hbm;
01350     GpStatus stat = InvalidParameter;
01351 
01352     TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
01353 
01354     if(!lpBitmapName || !bitmap)
01355         return InvalidParameter;
01356 
01357     /* load DIB */
01358     hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
01359                      LR_CREATEDIBSECTION);
01360 
01361     if(hbm){
01362         stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
01363         DeleteObject(hbm);
01364     }
01365 
01366     return stat;
01367 }
01368 
01369 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
01370     HBITMAP* hbmReturn, ARGB background)
01371 {
01372     GpStatus stat;
01373     HBITMAP result;
01374     UINT width, height;
01375     BITMAPINFOHEADER bih;
01376     LPBYTE bits;
01377     BitmapData lockeddata;
01378     TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
01379 
01380     if (!bitmap || !hbmReturn) return InvalidParameter;
01381 
01382     GdipGetImageWidth((GpImage*)bitmap, &width);
01383     GdipGetImageHeight((GpImage*)bitmap, &height);
01384 
01385     bih.biSize = sizeof(bih);
01386     bih.biWidth = width;
01387     bih.biHeight = height;
01388     bih.biPlanes = 1;
01389     bih.biBitCount = 32;
01390     bih.biCompression = BI_RGB;
01391     bih.biSizeImage = 0;
01392     bih.biXPelsPerMeter = 0;
01393     bih.biYPelsPerMeter = 0;
01394     bih.biClrUsed = 0;
01395     bih.biClrImportant = 0;
01396 
01397     result = CreateDIBSection(0, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
01398 
01399     if (result)
01400     {
01401         lockeddata.Stride = -width * 4;
01402         lockeddata.Scan0 = bits + (width * 4 * (height - 1));
01403 
01404         stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead|ImageLockModeUserInputBuf,
01405             PixelFormat32bppPARGB, &lockeddata);
01406 
01407         if (stat == Ok)
01408             stat = GdipBitmapUnlockBits(bitmap, &lockeddata);
01409     }
01410     else
01411         stat = GenericError;
01412 
01413     if (stat != Ok && result)
01414     {
01415         DeleteObject(result);
01416         result = NULL;
01417     }
01418 
01419     *hbmReturn = result;
01420 
01421     return stat;
01422 }
01423 
01424 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
01425     GpMetafile* metafile, BOOL* succ, EmfType emfType,
01426     const WCHAR* description, GpMetafile** out_metafile)
01427 {
01428     static int calls;
01429 
01430     TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
01431         debugstr_w(description), out_metafile);
01432 
01433     if(!ref || !metafile || !out_metafile)
01434         return InvalidParameter;
01435 
01436     *succ = FALSE;
01437     *out_metafile = NULL;
01438 
01439     if(!(calls++))
01440         FIXME("not implemented\n");
01441 
01442     return NotImplemented;
01443 }
01444 
01445 /* FIXME: this should create a bitmap in the given size with the attributes
01446  * (resolution etc.) of the graphics object */
01447 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
01448     GpGraphics* target, GpBitmap** bitmap)
01449 {
01450     static int calls;
01451     GpStatus ret;
01452 
01453     TRACE("(%d, %d, %p, %p)\n", width, height, target, bitmap);
01454 
01455     if(!target || !bitmap)
01456         return InvalidParameter;
01457 
01458     if(!(calls++))
01459         FIXME("hacked stub\n");
01460 
01461     ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat24bppRGB,
01462                                     NULL, bitmap);
01463 
01464     return ret;
01465 }
01466 
01467 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
01468 {
01469     GpStatus stat;
01470     ICONINFO iinfo;
01471     BITMAP bm;
01472     int ret;
01473     UINT width, height;
01474     GpRect rect;
01475     BitmapData lockeddata;
01476     HDC screendc;
01477     BOOL has_alpha;
01478     int x, y;
01479     BYTE *bits;
01480     BITMAPINFOHEADER bih;
01481     DWORD *src;
01482     BYTE *dst_row;
01483     DWORD *dst;
01484 
01485     TRACE("%p, %p\n", hicon, bitmap);
01486 
01487     if(!bitmap || !GetIconInfo(hicon, &iinfo))
01488         return InvalidParameter;
01489 
01490     /* get the size of the icon */
01491     ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
01492     if (ret == 0) {
01493         DeleteObject(iinfo.hbmColor);
01494         DeleteObject(iinfo.hbmMask);
01495         return GenericError;
01496     }
01497 
01498     width = bm.bmWidth;
01499 
01500     if (iinfo.hbmColor)
01501         height = abs(bm.bmHeight);
01502     else /* combined bitmap + mask */
01503         height = abs(bm.bmHeight) / 2;
01504 
01505     bits = HeapAlloc(GetProcessHeap(), 0, 4*width*height);
01506     if (!bits) {
01507         DeleteObject(iinfo.hbmColor);
01508         DeleteObject(iinfo.hbmMask);
01509         return OutOfMemory;
01510     }
01511 
01512     stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB, NULL, bitmap);
01513     if (stat != Ok) {
01514         DeleteObject(iinfo.hbmColor);
01515         DeleteObject(iinfo.hbmMask);
01516         HeapFree(GetProcessHeap(), 0, bits);
01517         return stat;
01518     }
01519 
01520     rect.X = 0;
01521     rect.Y = 0;
01522     rect.Width = width;
01523     rect.Height = height;
01524 
01525     stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
01526     if (stat != Ok) {
01527         DeleteObject(iinfo.hbmColor);
01528         DeleteObject(iinfo.hbmMask);
01529         HeapFree(GetProcessHeap(), 0, bits);
01530         GdipDisposeImage((GpImage*)*bitmap);
01531         return stat;
01532     }
01533 
01534     bih.biSize = sizeof(bih);
01535     bih.biWidth = width;
01536     bih.biHeight = -height;
01537     bih.biPlanes = 1;
01538     bih.biBitCount = 32;
01539     bih.biCompression = BI_RGB;
01540     bih.biSizeImage = 0;
01541     bih.biXPelsPerMeter = 0;
01542     bih.biYPelsPerMeter = 0;
01543     bih.biClrUsed = 0;
01544     bih.biClrImportant = 0;
01545 
01546     screendc = GetDC(0);
01547     if (iinfo.hbmColor)
01548     {
01549         GetDIBits(screendc, iinfo.hbmColor, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
01550 
01551         if (bm.bmBitsPixel == 32)
01552         {
01553             has_alpha = FALSE;
01554 
01555             /* If any pixel has a non-zero alpha, ignore hbmMask */
01556             src = (DWORD*)bits;
01557             for (x=0; x<width && !has_alpha; x++)
01558                 for (y=0; y<height && !has_alpha; y++)
01559                     if ((*src++ & 0xff000000) != 0)
01560                         has_alpha = TRUE;
01561         }
01562         else has_alpha = FALSE;
01563     }
01564     else
01565     {
01566         GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
01567         has_alpha = FALSE;
01568     }
01569 
01570     /* copy the image data to the Bitmap */
01571     src = (DWORD*)bits;
01572     dst_row = lockeddata.Scan0;
01573     for (y=0; y<height; y++)
01574     {
01575         memcpy(dst_row, src, width*4);
01576         src += width;
01577         dst_row += lockeddata.Stride;
01578     }
01579 
01580     if (!has_alpha)
01581     {
01582         if (iinfo.hbmMask)
01583         {
01584             /* read alpha data from the mask */
01585             if (iinfo.hbmColor)
01586                 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
01587             else
01588                 GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
01589 
01590             src = (DWORD*)bits;
01591             dst_row = lockeddata.Scan0;
01592             for (y=0; y<height; y++)
01593             {
01594                 dst = (DWORD*)dst_row;
01595                 for (x=0; x<height; x++)
01596                 {
01597                     DWORD src_value = *src++;
01598                     if (src_value)
01599                         *dst++ = 0;
01600                     else
01601                         *dst++ |= 0xff000000;
01602                 }
01603                 dst_row += lockeddata.Stride;
01604             }
01605         }
01606         else
01607         {
01608             /* set constant alpha of 255 */
01609             dst_row = bits;
01610             for (y=0; y<height; y++)
01611             {
01612                 dst = (DWORD*)dst_row;
01613                 for (x=0; x<height; x++)
01614                     *dst++ |= 0xff000000;
01615                 dst_row += lockeddata.Stride;
01616             }
01617         }
01618     }
01619 
01620     ReleaseDC(0, screendc);
01621 
01622     DeleteObject(iinfo.hbmColor);
01623     DeleteObject(iinfo.hbmMask);
01624 
01625     GdipBitmapUnlockBits(*bitmap, &lockeddata);
01626 
01627     HeapFree(GetProcessHeap(), 0, bits);
01628 
01629     return Ok;
01630 }
01631 
01632 static void generate_halftone_palette(ARGB *entries, UINT count)
01633 {
01634     static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
01635     UINT i;
01636 
01637     for (i=0; i<8 && i<count; i++)
01638     {
01639         entries[i] = 0xff000000;
01640         if (i&1) entries[i] |= 0x800000;
01641         if (i&2) entries[i] |= 0x8000;
01642         if (i&4) entries[i] |= 0x80;
01643     }
01644 
01645     if (8 < count)
01646         entries[i] = 0xffc0c0c0;
01647 
01648     for (i=9; i<16 && i<count; i++)
01649     {
01650         entries[i] = 0xff000000;
01651         if (i&1) entries[i] |= 0xff0000;
01652         if (i&2) entries[i] |= 0xff00;
01653         if (i&4) entries[i] |= 0xff;
01654     }
01655 
01656     for (i=16; i<40 && i<count; i++)
01657     {
01658         entries[i] = 0;
01659     }
01660 
01661     for (i=40; i<256 && i<count; i++)
01662     {
01663         entries[i] = 0xff000000;
01664         entries[i] |= halftone_values[(i-40)%6];
01665         entries[i] |= halftone_values[((i-40)/6)%6] << 8;
01666         entries[i] |= halftone_values[((i-40)/36)%6] << 16;
01667     }
01668 }
01669 
01670 static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
01671 {
01672     HDC screendc = GetDC(0);
01673 
01674     if (!screendc) return GenericError;
01675 
01676     *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
01677     *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
01678 
01679     ReleaseDC(0, screendc);
01680 
01681     return Ok;
01682 }
01683 
01684 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
01685     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
01686 {
01687     BITMAPINFO* pbmi;
01688     HBITMAP hbitmap=NULL;
01689     INT row_size, dib_stride;
01690     BYTE *bits=NULL, *own_bits=NULL;
01691     REAL xres, yres;
01692     GpStatus stat;
01693 
01694     TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
01695 
01696     if (!bitmap) return InvalidParameter;
01697 
01698     if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
01699         *bitmap = NULL;
01700         return InvalidParameter;
01701     }
01702 
01703     if(scan0 && !stride)
01704         return InvalidParameter;
01705 
01706     stat = get_screen_resolution(&xres, &yres);
01707     if (stat != Ok) return stat;
01708 
01709     row_size = (width * PIXELFORMATBPP(format)+7) / 8;
01710     dib_stride = (row_size + 3) & ~3;
01711 
01712     if(stride == 0)
01713         stride = dib_stride;
01714 
01715     if (format & PixelFormatGDI && !(format & (PixelFormatAlpha|PixelFormatIndexed)) && !scan0)
01716     {
01717         pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
01718         if (!pbmi)
01719             return OutOfMemory;
01720 
01721         pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
01722         pbmi->bmiHeader.biWidth = width;
01723         pbmi->bmiHeader.biHeight = -height;
01724         pbmi->bmiHeader.biPlanes = 1;
01725         /* FIXME: use the rest of the data from format */
01726         pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
01727         pbmi->bmiHeader.biCompression = BI_RGB;
01728         pbmi->bmiHeader.biSizeImage = 0;
01729         pbmi->bmiHeader.biXPelsPerMeter = 0;
01730         pbmi->bmiHeader.biYPelsPerMeter = 0;
01731         pbmi->bmiHeader.biClrUsed = 0;
01732         pbmi->bmiHeader.biClrImportant = 0;
01733 
01734         hbitmap = CreateDIBSection(0, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
01735 
01736         GdipFree(pbmi);
01737 
01738         if (!hbitmap) return GenericError;
01739 
01740         stride = dib_stride;
01741     }
01742     else
01743     {
01744         /* Not a GDI format; don't try to make an HBITMAP. */
01745         if (scan0)
01746             bits = scan0;
01747         else
01748         {
01749             INT size = abs(stride) * height;
01750 
01751             own_bits = bits = GdipAlloc(size);
01752             if (!own_bits) return OutOfMemory;
01753 
01754             if (stride < 0)
01755                 bits += stride * (1 - height);
01756         }
01757     }
01758 
01759     *bitmap = GdipAlloc(sizeof(GpBitmap));
01760     if(!*bitmap)
01761     {
01762         DeleteObject(hbitmap);
01763         GdipFree(own_bits);
01764         return OutOfMemory;
01765     }
01766 
01767     (*bitmap)->image.type = ImageTypeBitmap;
01768     memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
01769     (*bitmap)->image.flags = ImageFlagsNone;
01770     (*bitmap)->image.palette_flags = 0;
01771     (*bitmap)->image.palette_count = 0;
01772     (*bitmap)->image.palette_size = 0;
01773     (*bitmap)->image.palette_entries = NULL;
01774     (*bitmap)->image.xres = xres;
01775     (*bitmap)->image.yres = yres;
01776     (*bitmap)->width = width;
01777     (*bitmap)->height = height;
01778     (*bitmap)->format = format;
01779     (*bitmap)->image.picture = NULL;
01780     (*bitmap)->hbitmap = hbitmap;
01781     (*bitmap)->hdc = NULL;
01782     (*bitmap)->bits = bits;
01783     (*bitmap)->stride = stride;
01784     (*bitmap)->own_bits = own_bits;
01785 
01786     /* set format-related flags */
01787     if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed))
01788         (*bitmap)->image.flags |= ImageFlagsHasAlpha;
01789 
01790     if (format == PixelFormat1bppIndexed ||
01791         format == PixelFormat4bppIndexed ||
01792         format == PixelFormat8bppIndexed)
01793     {
01794         (*bitmap)->image.palette_size = (*bitmap)->image.palette_count = 1 << PIXELFORMATBPP(format);
01795         (*bitmap)->image.palette_entries = GdipAlloc(sizeof(ARGB) * ((*bitmap)->image.palette_size));
01796 
01797         if (!(*bitmap)->image.palette_entries)
01798         {
01799             GdipDisposeImage(&(*bitmap)->image);
01800             *bitmap = NULL;
01801             return OutOfMemory;
01802         }
01803 
01804         if (format == PixelFormat1bppIndexed)
01805         {
01806             (*bitmap)->image.palette_flags = PaletteFlagsGrayScale;
01807             (*bitmap)->image.palette_entries[0] = 0xff000000;
01808             (*bitmap)->image.palette_entries[1] = 0xffffffff;
01809         }
01810         else
01811         {
01812             if (format == PixelFormat8bppIndexed)
01813                 (*bitmap)->image.palette_flags = PaletteFlagsHalftone;
01814 
01815             generate_halftone_palette((*bitmap)->image.palette_entries,
01816                 (*bitmap)->image.palette_count);
01817         }
01818     }
01819 
01820     TRACE("<-- %p\n", *bitmap);
01821 
01822     return Ok;
01823 }
01824 
01825 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
01826     GpBitmap **bitmap)
01827 {
01828     GpStatus stat;
01829 
01830     TRACE("%p %p\n", stream, bitmap);
01831 
01832     stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
01833 
01834     if(stat != Ok)
01835         return stat;
01836 
01837     if((*bitmap)->image.type != ImageTypeBitmap){
01838         GdipDisposeImage(&(*bitmap)->image);
01839         *bitmap = NULL;
01840         return GenericError; /* FIXME: what error to return? */
01841     }
01842 
01843     return Ok;
01844 }
01845 
01846 /* FIXME: no icm */
01847 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
01848     GpBitmap **bitmap)
01849 {
01850     TRACE("%p %p\n", stream, bitmap);
01851 
01852     return GdipCreateBitmapFromStream(stream, bitmap);
01853 }
01854 
01855 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
01856     GpCachedBitmap **cachedbmp)
01857 {
01858     GpStatus stat;
01859 
01860     TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
01861 
01862     if(!bitmap || !graphics || !cachedbmp)
01863         return InvalidParameter;
01864 
01865     *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
01866     if(!*cachedbmp)
01867         return OutOfMemory;
01868 
01869     stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
01870     if(stat != Ok){
01871         GdipFree(*cachedbmp);
01872         return stat;
01873     }
01874 
01875     return Ok;
01876 }
01877 
01878 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
01879 {
01880     GpStatus stat;
01881     BitmapData lockeddata;
01882     ULONG andstride, xorstride, bitssize;
01883     LPBYTE andbits, xorbits, androw, xorrow, srcrow;
01884     UINT x, y;
01885 
01886     TRACE("(%p, %p)\n", bitmap, hicon);
01887 
01888     if (!bitmap || !hicon)
01889         return InvalidParameter;
01890 
01891     stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead,
01892         PixelFormat32bppPARGB, &lockeddata);
01893     if (stat == Ok)
01894     {
01895         andstride = ((lockeddata.Width+31)/32)*4;
01896         xorstride = lockeddata.Width*4;
01897         bitssize = (andstride + xorstride) * lockeddata.Height;
01898 
01899         andbits = GdipAlloc(bitssize);
01900 
01901         if (andbits)
01902         {
01903             xorbits = andbits + andstride * lockeddata.Height;
01904 
01905             for (y=0; y<lockeddata.Height; y++)
01906             {
01907                 srcrow = ((LPBYTE)lockeddata.Scan0) + lockeddata.Stride * y;
01908 
01909                 androw = andbits + andstride * y;
01910                 for (x=0; x<lockeddata.Width; x++)
01911                     if (srcrow[3+4*x] >= 128)
01912                         androw[x/8] |= 1 << (7-x%8);
01913 
01914                 xorrow = xorbits + xorstride * y;
01915                 memcpy(xorrow, srcrow, xorstride);
01916             }
01917 
01918             *hicon = CreateIcon(NULL, lockeddata.Width, lockeddata.Height, 1, 32,
01919                 andbits, xorbits);
01920 
01921             GdipFree(andbits);
01922         }
01923         else
01924             stat = OutOfMemory;
01925 
01926         GdipBitmapUnlockBits(bitmap, &lockeddata);
01927     }
01928 
01929     return stat;
01930 }
01931 
01932 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
01933 {
01934     TRACE("%p\n", cachedbmp);
01935 
01936     if(!cachedbmp)
01937         return InvalidParameter;
01938 
01939     GdipDisposeImage(cachedbmp->image);
01940     GdipFree(cachedbmp);
01941 
01942     return Ok;
01943 }
01944 
01945 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
01946     GpCachedBitmap *cachedbmp, INT x, INT y)
01947 {
01948     TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
01949 
01950     if(!graphics || !cachedbmp)
01951         return InvalidParameter;
01952 
01953     return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
01954 }
01955 
01956 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
01957     LPBYTE pData16, INT iMapMode, INT eFlags)
01958 {
01959     FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
01960     return NotImplemented;
01961 }
01962 
01963 /* Internal utility function: Replace the image data of dst with that of src,
01964  * and free src. */
01965 static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
01966 {
01967     GdipFree(dst->bitmapbits);
01968     DeleteDC(dst->hdc);
01969     DeleteObject(dst->hbitmap);
01970 
01971     if (clobber_palette)
01972     {
01973         GdipFree(dst->image.palette_entries);
01974         dst->image.palette_flags = src->image.palette_flags;
01975         dst->image.palette_count = src->image.palette_count;
01976         dst->image.palette_entries = src->image.palette_entries;
01977     }
01978     else
01979         GdipFree(src->image.palette_entries);
01980 
01981     dst->image.xres = src->image.xres;
01982     dst->image.yres = src->image.yres;
01983     dst->width = src->width;
01984     dst->height = src->height;
01985     dst->format = src->format;
01986     dst->hbitmap = src->hbitmap;
01987     dst->hdc = src->hdc;
01988     dst->bits = src->bits;
01989     dst->stride = src->stride;
01990     dst->own_bits = src->own_bits;
01991 
01992     GdipFree(src);
01993 }
01994 
01995 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
01996 {
01997     TRACE("%p\n", image);
01998 
01999     if(!image)
02000         return InvalidParameter;
02001 
02002     if (image->type == ImageTypeBitmap)
02003     {
02004         GdipFree(((GpBitmap*)image)->bitmapbits);
02005         GdipFree(((GpBitmap*)image)->own_bits);
02006         DeleteDC(((GpBitmap*)image)->hdc);
02007         DeleteObject(((GpBitmap*)image)->hbitmap);
02008     }
02009     else if (image->type == ImageTypeMetafile)
02010     {
02011         GpMetafile *metafile = (GpMetafile*)image;
02012         GdipFree(metafile->comment_data);
02013         DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
02014         DeleteEnhMetaFile(metafile->hemf);
02015         if (metafile->record_graphics)
02016         {
02017             WARN("metafile closed while recording\n");
02018             /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
02019             metafile->record_graphics->image = NULL;
02020             metafile->record_graphics->busy = TRUE;
02021         }
02022     }
02023     else
02024     {
02025         WARN("invalid image: %p\n", image);
02026         return ObjectBusy;
02027     }
02028     if (image->picture)
02029         IPicture_Release(image->picture);
02030     GdipFree(image->palette_entries);
02031     image->type = ~0;
02032     GdipFree(image);
02033 
02034     return Ok;
02035 }
02036 
02037 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
02038 {
02039     static int calls;
02040 
02041     TRACE("(%p,%p)\n", image, item);
02042 
02043     if(!image || !item)
02044         return InvalidParameter;
02045 
02046     if (!(calls++))
02047         FIXME("not implemented\n");
02048 
02049     return NotImplemented;
02050 }
02051 
02052 GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item)
02053 {
02054     static int calls;
02055 
02056     TRACE("(%p,%p)\n", image, item);
02057 
02058     if (!(calls++))
02059         FIXME("not implemented\n");
02060 
02061     return NotImplemented;
02062 }
02063 
02064 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
02065     GpUnit *srcUnit)
02066 {
02067     TRACE("%p %p %p\n", image, srcRect, srcUnit);
02068 
02069     if(!image || !srcRect || !srcUnit)
02070         return InvalidParameter;
02071     if(image->type == ImageTypeMetafile){
02072         *srcRect = ((GpMetafile*)image)->bounds;
02073         *srcUnit = ((GpMetafile*)image)->unit;
02074     }
02075     else if(image->type == ImageTypeBitmap){
02076         srcRect->X = srcRect->Y = 0.0;
02077         srcRect->Width = (REAL) ((GpBitmap*)image)->width;
02078         srcRect->Height = (REAL) ((GpBitmap*)image)->height;
02079         *srcUnit = UnitPixel;
02080     }
02081     else{
02082         srcRect->X = srcRect->Y = 0.0;
02083         srcRect->Width = ipicture_pixel_width(image->picture);
02084         srcRect->Height = ipicture_pixel_height(image->picture);
02085         *srcUnit = UnitPixel;
02086     }
02087 
02088     TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
02089           srcRect->Width, srcRect->Height, *srcUnit);
02090 
02091     return Ok;
02092 }
02093 
02094 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
02095     REAL *height)
02096 {
02097     TRACE("%p %p %p\n", image, width, height);
02098 
02099     if(!image || !height || !width)
02100         return InvalidParameter;
02101 
02102     if(image->type == ImageTypeMetafile){
02103         HDC hdc = GetDC(0);
02104         REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
02105 
02106         ReleaseDC(0, hdc);
02107 
02108         *height = convert_unit(res, ((GpMetafile*)image)->unit) *
02109                         ((GpMetafile*)image)->bounds.Height;
02110 
02111         *width = convert_unit(res, ((GpMetafile*)image)->unit) *
02112                         ((GpMetafile*)image)->bounds.Width;
02113     }
02114 
02115     else if(image->type == ImageTypeBitmap){
02116         *height = ((GpBitmap*)image)->height;
02117         *width = ((GpBitmap*)image)->width;
02118     }
02119     else{
02120         *height = ipicture_pixel_height(image->picture);
02121         *width = ipicture_pixel_width(image->picture);
02122     }
02123 
02124     TRACE("returning (%f, %f)\n", *height, *width);
02125     return Ok;
02126 }
02127 
02128 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
02129     GpGraphics **graphics)
02130 {
02131     HDC hdc;
02132     GpStatus stat;
02133 
02134     TRACE("%p %p\n", image, graphics);
02135 
02136     if(!image || !graphics)
02137         return InvalidParameter;
02138 
02139     if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
02140     {
02141         hdc = ((GpBitmap*)image)->hdc;
02142 
02143         if(!hdc){
02144             hdc = CreateCompatibleDC(0);
02145             SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
02146             ((GpBitmap*)image)->hdc = hdc;
02147         }
02148 
02149         stat = GdipCreateFromHDC(hdc, graphics);
02150 
02151         if (stat == Ok)
02152             (*graphics)->image = image;
02153     }
02154     else if (image->type == ImageTypeMetafile)
02155         stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
02156     else
02157         stat = graphics_from_image(image, graphics);
02158 
02159     return stat;
02160 }
02161 
02162 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
02163 {
02164     TRACE("%p %p\n", image, height);
02165 
02166     if(!image || !height)
02167         return InvalidParameter;
02168 
02169     if(image->type == ImageTypeMetafile){
02170         HDC hdc = GetDC(0);
02171         REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
02172 
02173         ReleaseDC(0, hdc);
02174 
02175         *height = roundr(convert_unit(res, ((GpMetafile*)image)->unit) *
02176                         ((GpMetafile*)image)->bounds.Height);
02177     }
02178     else if(image->type == ImageTypeBitmap)
02179         *height = ((GpBitmap*)image)->height;
02180     else
02181         *height = ipicture_pixel_height(image->picture);
02182 
02183     TRACE("returning %d\n", *height);
02184 
02185     return Ok;
02186 }
02187 
02188 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
02189 {
02190     if(!image || !res)
02191         return InvalidParameter;
02192 
02193     *res = image->xres;
02194 
02195     TRACE("(%p) <-- %0.2f\n", image, *res);
02196 
02197     return Ok;
02198 }
02199 
02200 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
02201 {
02202     TRACE("%p %p\n", image, size);
02203 
02204     if(!image || !size)
02205         return InvalidParameter;
02206 
02207     if (image->palette_count == 0)
02208         *size = sizeof(ColorPalette);
02209     else
02210         *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette_count;
02211 
02212     TRACE("<-- %u\n", *size);
02213 
02214     return Ok;
02215 }
02216 
02217 /* FIXME: test this function for non-bitmap types */
02218 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
02219 {
02220     TRACE("%p %p\n", image, format);
02221 
02222     if(!image || !format)
02223         return InvalidParameter;
02224 
02225     if(image->type != ImageTypeBitmap)
02226         *format = PixelFormat24bppRGB;
02227     else
02228         *format = ((GpBitmap*) image)->format;
02229 
02230     return Ok;
02231 }
02232 
02233 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
02234 {
02235     TRACE("(%p, %p)\n", image, format);
02236 
02237     if(!image || !format)
02238         return InvalidParameter;
02239 
02240     memcpy(format, &image->format, sizeof(GUID));
02241 
02242     return Ok;
02243 }
02244 
02245 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
02246 {
02247     TRACE("%p %p\n", image, type);
02248 
02249     if(!image || !type)
02250         return InvalidParameter;
02251 
02252     *type = image->type;
02253 
02254     return Ok;
02255 }
02256 
02257 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
02258 {
02259     if(!image || !res)
02260         return InvalidParameter;
02261 
02262     *res = image->yres;
02263 
02264     TRACE("(%p) <-- %0.2f\n", image, *res);
02265 
02266     return Ok;
02267 }
02268 
02269 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
02270 {
02271     TRACE("%p %p\n", image, width);
02272 
02273     if(!image || !width)
02274         return InvalidParameter;
02275 
02276     if(image->type == ImageTypeMetafile){
02277         HDC hdc = GetDC(0);
02278         REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
02279 
02280         ReleaseDC(0, hdc);
02281 
02282         *width = roundr(convert_unit(res, ((GpMetafile*)image)->unit) *
02283                         ((GpMetafile*)image)->bounds.Width);
02284     }
02285     else if(image->type == ImageTypeBitmap)
02286         *width = ((GpBitmap*)image)->width;
02287     else
02288         *width = ipicture_pixel_width(image->picture);
02289 
02290     TRACE("returning %d\n", *width);
02291 
02292     return Ok;
02293 }
02294 
02295 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
02296     MetafileHeader * header)
02297 {
02298     static int calls;
02299 
02300     TRACE("(%p, %p)\n", metafile, header);
02301 
02302     if(!metafile || !header)
02303         return InvalidParameter;
02304 
02305     if(!(calls++))
02306         FIXME("not implemented\n");
02307 
02308     memset(header, 0, sizeof(MetafileHeader));
02309 
02310     return Ok;
02311 }
02312 
02313 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
02314     MetafileHeader *header)
02315 {
02316     static int calls;
02317 
02318     if(!hEmf || !header)
02319         return InvalidParameter;
02320 
02321     if(!(calls++))
02322         FIXME("not implemented\n");
02323 
02324     memset(header, 0, sizeof(MetafileHeader));
02325 
02326     return Ok;
02327 }
02328 
02329 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
02330     MetafileHeader *header)
02331 {
02332     static int calls;
02333 
02334     TRACE("(%s,%p)\n", debugstr_w(filename), header);
02335 
02336     if(!filename || !header)
02337         return InvalidParameter;
02338 
02339     if(!(calls++))
02340         FIXME("not implemented\n");
02341 
02342     memset(header, 0, sizeof(MetafileHeader));
02343 
02344     return Ok;
02345 }
02346 
02347 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
02348     MetafileHeader *header)
02349 {
02350     static int calls;
02351 
02352     TRACE("(%p,%p)\n", stream, header);
02353 
02354     if(!stream || !header)
02355         return InvalidParameter;
02356 
02357     if(!(calls++))
02358         FIXME("not implemented\n");
02359 
02360     memset(header, 0, sizeof(MetafileHeader));
02361 
02362     return Ok;
02363 }
02364 
02365 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
02366     UINT num, PropertyItem* items)
02367 {
02368     static int calls;
02369 
02370     TRACE("(%p, %u, %u, %p)\n", image, size, num, items);
02371 
02372     if(!(calls++))
02373         FIXME("not implemented\n");
02374 
02375     return InvalidParameter;
02376 }
02377 
02378 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT* num)
02379 {
02380     static int calls;
02381 
02382     TRACE("(%p, %p)\n", image, num);
02383 
02384     if(!(calls++))
02385         FIXME("not implemented\n");
02386 
02387     *num = 0;
02388     return Ok;
02389 }
02390 
02391 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID* list)
02392 {
02393     static int calls;
02394 
02395     TRACE("(%p, %u, %p)\n", image, num, list);
02396 
02397     if(!(calls++))
02398         FIXME("not implemented\n");
02399 
02400     return InvalidParameter;
02401 }
02402 
02403 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID id, UINT size,
02404     PropertyItem* buffer)
02405 {
02406     static int calls;
02407 
02408     TRACE("(%p, %u, %u, %p)\n", image, id, size, buffer);
02409 
02410     if(!(calls++))
02411         FIXME("not implemented\n");
02412 
02413     return InvalidParameter;
02414 }
02415 
02416 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
02417     UINT* size)
02418 {
02419     static int calls;
02420 
02421     TRACE("%p %x %p\n", image, pid, size);
02422 
02423     if(!size || !image)
02424         return InvalidParameter;
02425 
02426     if(!(calls++))
02427         FIXME("not implemented\n");
02428 
02429     return NotImplemented;
02430 }
02431 
02432 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
02433 {
02434     static int calls;
02435 
02436     TRACE("(%p,%p,%p)\n", image, size, num);
02437 
02438     if(!(calls++))
02439         FIXME("not implemented\n");
02440 
02441     return InvalidParameter;
02442 }
02443 
02444 struct image_format_dimension
02445 {
02446     const GUID *format;
02447     const GUID *dimension;
02448 };
02449 
02450 static struct image_format_dimension image_format_dimensions[] =
02451 {
02452     {&ImageFormatGIF, &FrameDimensionTime},
02453     {&ImageFormatIcon, &FrameDimensionResolution},
02454     {NULL}
02455 };
02456 
02457 /* FIXME: Need to handle multi-framed images */
02458 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
02459     GDIPCONST GUID* dimensionID, UINT* count)
02460 {
02461     static int calls;
02462 
02463     TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
02464 
02465     if(!image || !count)
02466         return InvalidParameter;
02467 
02468     if(!(calls++))
02469         FIXME("returning frame count of 1\n");
02470 
02471     *count = 1;
02472 
02473     return Ok;
02474 }
02475 
02476 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
02477     UINT* count)
02478 {
02479     TRACE("(%p, %p)\n", image, count);
02480 
02481     /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
02482 
02483     if(!image || !count)
02484         return InvalidParameter;
02485 
02486     *count = 1;
02487 
02488     return Ok;
02489 }
02490 
02491 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
02492     GUID* dimensionIDs, UINT count)
02493 {
02494     int i;
02495     const GUID *result=NULL;
02496 
02497     TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
02498 
02499     if(!image || !dimensionIDs || count != 1)
02500         return InvalidParameter;
02501 
02502     for (i=0; image_format_dimensions[i].format; i++)
02503     {
02504         if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
02505         {
02506             result = image_format_dimensions[i].dimension;
02507             break;
02508         }
02509     }
02510 
02511     if (!result)
02512         result = &FrameDimensionPage;
02513 
02514     memcpy(dimensionIDs, result, sizeof(GUID));
02515 
02516     return Ok;
02517 }
02518 
02519 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
02520     GDIPCONST GUID* dimensionID, UINT frameidx)
02521 {
02522     static int calls;
02523 
02524     TRACE("(%p, %s, %u)\n", image, debugstr_guid(dimensionID), frameidx);
02525 
02526     if(!image || !dimensionID)
02527         return InvalidParameter;
02528 
02529     if(!(calls++))
02530         FIXME("not implemented\n");
02531 
02532     return Ok;
02533 }
02534 
02535 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
02536                                           GpImage **image)
02537 {
02538     GpStatus stat;
02539     IStream *stream;
02540 
02541     TRACE("(%s) %p\n", debugstr_w(filename), image);
02542 
02543     if (!filename || !image)
02544         return InvalidParameter;
02545 
02546     stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
02547 
02548     if (stat != Ok)
02549         return stat;
02550 
02551     stat = GdipLoadImageFromStream(stream, image);
02552 
02553     IStream_Release(stream);
02554 
02555     return stat;
02556 }
02557 
02558 /* FIXME: no icm handling */
02559 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
02560 {
02561     TRACE("(%s) %p\n", debugstr_w(filename), image);
02562 
02563     return GdipLoadImageFromFile(filename, image);
02564 }
02565 
02566 static const WICPixelFormatGUID *wic_pixel_formats[] = {
02567     &GUID_WICPixelFormat16bppBGR555,
02568     &GUID_WICPixelFormat24bppBGR,
02569     &GUID_WICPixelFormat32bppBGR,
02570     &GUID_WICPixelFormat32bppBGRA,
02571     &GUID_WICPixelFormat32bppPBGRA,
02572     NULL
02573 };
02574 
02575 static const PixelFormat wic_gdip_formats[] = {
02576     PixelFormat16bppRGB555,
02577     PixelFormat24bppRGB,
02578     PixelFormat32bppRGB,
02579     PixelFormat32bppARGB,
02580     PixelFormat32bppPARGB,
02581 };
02582 
02583 static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **image)
02584 {
02585     GpStatus status=Ok;
02586     GpBitmap *bitmap;
02587     HRESULT hr;
02588     IWICBitmapDecoder *decoder;
02589     IWICBitmapFrameDecode *frame;
02590     IWICBitmapSource *source=NULL;
02591     WICPixelFormatGUID wic_format;
02592     PixelFormat gdip_format=0;
02593     int i;
02594     UINT width, height;
02595     BitmapData lockeddata;
02596     WICRect wrc;
02597     HRESULT initresult;
02598 
02599     initresult = CoInitialize(NULL);
02600 
02601     hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
02602         &IID_IWICBitmapDecoder, (void**)&decoder);
02603     if (FAILED(hr)) goto end;
02604 
02605     hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
02606     if (SUCCEEDED(hr))
02607         hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
02608 
02609     if (SUCCEEDED(hr)) /* got frame */
02610     {
02611         hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
02612 
02613         if (SUCCEEDED(hr))
02614         {
02615             for (i=0; wic_pixel_formats[i]; i++)
02616             {
02617                 if (IsEqualGUID(&wic_format, wic_pixel_formats[i]))
02618                 {
02619                     source = (IWICBitmapSource*)frame;
02620                     IWICBitmapSource_AddRef(source);
02621                     gdip_format = wic_gdip_formats[i];
02622                     break;
02623                 }
02624             }
02625             if (!source)
02626             {
02627                 /* unknown format; fall back on 32bppARGB */
02628                 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
02629                 gdip_format = PixelFormat32bppARGB;
02630             }
02631         }
02632 
02633         if (SUCCEEDED(hr)) /* got source */
02634         {
02635             hr = IWICBitmapSource_GetSize(source, &width, &height);
02636 
02637             if (SUCCEEDED(hr))
02638                 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
02639                     NULL, &bitmap);
02640 
02641             if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
02642             {
02643                 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
02644                     gdip_format, &lockeddata);
02645                 if (status == Ok) /* locked bitmap */
02646                 {
02647                     wrc.X = 0;
02648                     wrc.Width = width;
02649                     wrc.Height = 1;
02650                     for (i=0; i<height; i++)
02651                     {
02652                         wrc.Y = i;
02653                         hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
02654                             abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
02655                         if (FAILED(hr)) break;
02656                     }
02657 
02658                     GdipBitmapUnlockBits(bitmap, &lockeddata);
02659                 }
02660 
02661                 if (SUCCEEDED(hr) && status == Ok)
02662                     *image = (GpImage*)bitmap;
02663                 else
02664                 {
02665                     *image = NULL;
02666                     GdipDisposeImage((GpImage*)bitmap);
02667                 }
02668 
02669                 if (SUCCEEDED(hr) && status == Ok)
02670                 {
02671                     double dpix, dpiy;
02672                     hr = IWICBitmapSource_GetResolution(source, &dpix, &dpiy);
02673                     if (SUCCEEDED(hr))
02674                     {
02675                         bitmap->image.xres = dpix;
02676                         bitmap->image.yres = dpiy;
02677                     }
02678                     hr = S_OK;
02679                 }
02680             }
02681 
02682             IWICBitmapSource_Release(source);
02683         }
02684 
02685         IWICBitmapFrameDecode_Release(frame);
02686     }
02687 
02688     IWICBitmapDecoder_Release(decoder);
02689 
02690 end:
02691     if (SUCCEEDED(initresult)) CoUninitialize();
02692 
02693     if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
02694 
02695     if (status == Ok)
02696     {
02697         /* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
02698         bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
02699     }
02700 
02701     return status;
02702 }
02703 
02704 static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **image)
02705 {
02706     return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
02707 }
02708 
02709 static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
02710 {
02711     GpStatus status;
02712     GpBitmap* bitmap;
02713 
02714     status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
02715 
02716     bitmap = (GpBitmap*)*image;
02717 
02718     if (status == Ok && bitmap->format == PixelFormat32bppARGB)
02719     {
02720         /* WIC supports bmp files with alpha, but gdiplus does not */
02721         bitmap->format = PixelFormat32bppRGB;
02722     }
02723 
02724     return status;
02725 }
02726 
02727 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
02728 {
02729     return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
02730 }
02731 
02732 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
02733 {
02734     return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
02735 }
02736 
02737 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
02738 {
02739     return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
02740 }
02741 
02742 static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, GpImage **image)
02743 {
02744     return decode_image_wic(stream, &CLSID_WICTiffDecoder, image);
02745 }
02746 
02747 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
02748 {
02749     IPicture *pic;
02750 
02751     TRACE("%p %p\n", stream, image);
02752 
02753     if(!stream || !image)
02754         return InvalidParameter;
02755 
02756     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
02757         (LPVOID*) &pic) != S_OK){
02758         TRACE("Could not load picture\n");
02759         return GenericError;
02760     }
02761 
02762     /* FIXME: missing initialization code */
02763     *image = GdipAlloc(sizeof(GpMetafile));
02764     if(!*image) return OutOfMemory;
02765     (*image)->type = ImageTypeMetafile;
02766     (*image)->picture = pic;
02767     (*image)->flags   = ImageFlagsNone;
02768     (*image)->palette_flags = 0;
02769     (*image)->palette_count = 0;
02770     (*image)->palette_size = 0;
02771     (*image)->palette_entries = NULL;
02772 
02773     TRACE("<-- %p\n", *image);
02774 
02775     return Ok;
02776 }
02777 
02778 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
02779     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
02780 
02781 typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image);
02782 
02783 typedef struct image_codec {
02784     ImageCodecInfo info;
02785     encode_image_func encode_func;
02786     decode_image_func decode_func;
02787 } image_codec;
02788 
02789 typedef enum {
02790     BMP,
02791     JPEG,
02792     GIF,
02793     TIFF,
02794     EMF,
02795     WMF,
02796     PNG,
02797     ICO,
02798     NUM_CODECS
02799 } ImageFormat;
02800 
02801 static const struct image_codec codecs[NUM_CODECS];
02802 
02803 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
02804 {
02805     BYTE signature[8];
02806     const BYTE *pattern, *mask;
02807     LARGE_INTEGER seek;
02808     HRESULT hr;
02809     UINT bytesread;
02810     int i, j, sig;
02811 
02812     /* seek to the start of the stream */
02813     seek.QuadPart = 0;
02814     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
02815     if (FAILED(hr)) return hresult_to_status(hr);
02816 
02817     /* read the first 8 bytes */
02818     /* FIXME: This assumes all codecs have signatures <= 8 bytes in length */
02819     hr = IStream_Read(stream, signature, 8, &bytesread);
02820     if (FAILED(hr)) return hresult_to_status(hr);
02821     if (hr == S_FALSE || bytesread == 0) return GenericError;
02822 
02823     for (i = 0; i < NUM_CODECS; i++) {
02824         if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
02825             bytesread >= codecs[i].info.SigSize)
02826         {
02827             for (sig=0; sig<codecs[i].info.SigCount; sig++)
02828             {
02829                 pattern = &codecs[i].info.SigPattern[codecs[i].info.SigSize*sig];
02830                 mask = &codecs[i].info.SigMask[codecs[i].info.SigSize*sig];
02831                 for (j=0; j<codecs[i].info.SigSize; j++)
02832                     if ((signature[j] & mask[j]) != pattern[j])
02833                         break;
02834                 if (j == codecs[i].info.SigSize)
02835                 {
02836                     *result = &codecs[i];
02837                     return Ok;
02838                 }
02839             }
02840         }
02841     }
02842 
02843     TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
02844         signature[0],signature[1],signature[2],signature[3],
02845         signature[4],signature[5],signature[6],signature[7]);
02846 
02847     return GenericError;
02848 }
02849 
02850 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
02851 {
02852     GpStatus stat;
02853     LARGE_INTEGER seek;
02854     HRESULT hr;
02855     const struct image_codec *codec=NULL;
02856 
02857     /* choose an appropriate image decoder */
02858     stat = get_decoder_info(stream, &codec);
02859     if (stat != Ok) return stat;
02860 
02861     /* seek to the start of the stream */
02862     seek.QuadPart = 0;
02863     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
02864     if (FAILED(hr)) return hresult_to_status(hr);
02865 
02866     /* call on the image decoder to do the real work */
02867     stat = codec->decode_func(stream, &codec->info.Clsid, image);
02868 
02869     /* take note of the original data format */
02870     if (stat == Ok)
02871     {
02872         memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
02873     }
02874 
02875     return stat;
02876 }
02877 
02878 /* FIXME: no ICM */
02879 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
02880 {
02881     TRACE("%p %p\n", stream, image);
02882 
02883     return GdipLoadImageFromStream(stream, image);
02884 }
02885 
02886 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
02887 {
02888     static int calls;
02889 
02890     TRACE("(%p,%u)\n", image, propId);
02891 
02892     if(!image)
02893         return InvalidParameter;
02894 
02895     if(!(calls++))
02896         FIXME("not implemented\n");
02897 
02898     return NotImplemented;
02899 }
02900 
02901 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
02902 {
02903     static int calls;
02904 
02905     TRACE("(%p,%p)\n", image, item);
02906 
02907     if(!(calls++))
02908         FIXME("not implemented\n");
02909 
02910     return NotImplemented;
02911 }
02912 
02913 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
02914                                         GDIPCONST CLSID *clsidEncoder,
02915                                         GDIPCONST EncoderParameters *encoderParams)
02916 {
02917     GpStatus stat;
02918     IStream *stream;
02919 
02920     TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
02921 
02922     if (!image || !filename|| !clsidEncoder)
02923         return InvalidParameter;
02924 
02925     stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
02926     if (stat != Ok)
02927         return GenericError;
02928 
02929     stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
02930 
02931     IStream_Release(stream);
02932     return stat;
02933 }
02934 
02935 /*************************************************************************
02936  * Encoding functions -
02937  *   These functions encode an image in different image file formats.
02938  */
02939 #define BITMAP_FORMAT_BMP   0x4d42 /* "BM" */
02940 #define BITMAP_FORMAT_JPEG  0xd8ff
02941 #define BITMAP_FORMAT_GIF   0x4947
02942 #define BITMAP_FORMAT_PNG   0x5089
02943 #define BITMAP_FORMAT_APM   0xcdd7
02944 
02945 static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
02946     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
02947 {
02948     GpStatus stat;
02949     GpBitmap *bitmap;
02950     IWICBitmapEncoder *encoder;
02951     IWICBitmapFrameEncode *frameencode;
02952     IPropertyBag2 *encoderoptions;
02953     HRESULT hr;
02954     UINT width, height;
02955     PixelFormat gdipformat=0;
02956     WICPixelFormatGUID wicformat;
02957     GpRect rc;
02958     BitmapData lockeddata;
02959     HRESULT initresult;
02960     UINT i;
02961 
02962     if (image->type != ImageTypeBitmap)
02963         return GenericError;
02964 
02965     bitmap = (GpBitmap*)image;
02966 
02967     GdipGetImageWidth(image, &width);
02968     GdipGetImageHeight(image, &height);
02969 
02970     rc.X = 0;
02971     rc.Y = 0;
02972     rc.Width = width;
02973     rc.Height = height;
02974 
02975     initresult = CoInitialize(NULL);
02976 
02977     hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
02978         &IID_IWICBitmapEncoder, (void**)&encoder);
02979     if (FAILED(hr))
02980     {
02981         if (SUCCEEDED(initresult)) CoUninitialize();
02982         return hresult_to_status(hr);
02983     }
02984 
02985     hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
02986 
02987     if (SUCCEEDED(hr))
02988     {
02989         hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
02990     }
02991 
02992     if (SUCCEEDED(hr)) /* created frame */
02993     {
02994         hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
02995 
02996         if (SUCCEEDED(hr))
02997             hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
02998 
02999         if (SUCCEEDED(hr))
03000             /* FIXME: use the resolution from the image */
03001             hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0);
03002 
03003         if (SUCCEEDED(hr))
03004         {
03005             for (i=0; wic_pixel_formats[i]; i++)
03006             {
03007                 if (wic_gdip_formats[i] == bitmap->format)
03008                     break;
03009             }
03010             if (wic_pixel_formats[i])
03011                 memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID));
03012             else
03013                 memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
03014 
03015             hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
03016 
03017             for (i=0; wic_pixel_formats[i]; i++)
03018             {
03019                 if (IsEqualGUID(&wicformat, wic_pixel_formats[i]))
03020                     break;
03021             }
03022             if (wic_pixel_formats[i])
03023                 gdipformat = wic_gdip_formats[i];
03024             else
03025             {
03026                 ERR("cannot provide pixel format %s\n", debugstr_guid(&wicformat));
03027                 hr = E_FAIL;
03028             }
03029         }
03030 
03031         if (SUCCEEDED(hr))
03032         {
03033             stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
03034                 &lockeddata);
03035 
03036             if (stat == Ok)
03037             {
03038                 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
03039                 BYTE *row;
03040 
03041                 /* write one row at a time in case stride is negative */
03042                 row = lockeddata.Scan0;
03043                 for (i=0; i<lockeddata.Height; i++)
03044                 {
03045                     hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
03046                     if (FAILED(hr)) break;
03047                     row += lockeddata.Stride;
03048                 }
03049 
03050                 GdipBitmapUnlockBits(bitmap, &lockeddata);
03051             }
03052             else
03053                 hr = E_FAIL;
03054         }
03055 
03056         if (SUCCEEDED(hr))
03057             hr = IWICBitmapFrameEncode_Commit(frameencode);
03058 
03059         IWICBitmapFrameEncode_Release(frameencode);
03060         IPropertyBag2_Release(encoderoptions);
03061     }
03062 
03063     if (SUCCEEDED(hr))
03064         hr = IWICBitmapEncoder_Commit(encoder);
03065 
03066     IWICBitmapEncoder_Release(encoder);
03067 
03068     if (SUCCEEDED(initresult)) CoUninitialize();
03069 
03070     return hresult_to_status(hr);
03071 }
03072 
03073 static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
03074     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
03075 {
03076     return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
03077 }
03078 
03079 static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
03080     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
03081 {
03082     return encode_image_WIC(image, stream, &CLSID_WICTiffEncoder, params);
03083 }
03084 
03085 static GpStatus encode_image_png(GpImage *image, IStream* stream,
03086     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
03087 {
03088     return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
03089 }
03090 
03091 static GpStatus encode_image_jpeg(GpImage *image, IStream* stream,
03092     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
03093 {
03094     return encode_image_WIC(image, stream, &CLSID_WICJpegEncoder, params);
03095 }
03096 
03097 /*****************************************************************************
03098  * GdipSaveImageToStream [GDIPLUS.@]
03099  */
03100 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
03101     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
03102 {
03103     GpStatus stat;
03104     encode_image_func encode_image;
03105     int i;
03106 
03107     TRACE("%p %p %p %p\n", image, stream, clsid, params);
03108 
03109     if(!image || !stream)
03110         return InvalidParameter;
03111 
03112     /* select correct encoder */
03113     encode_image = NULL;
03114     for (i = 0; i < NUM_CODECS; i++) {
03115         if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
03116             IsEqualCLSID(clsid, &codecs[i].info.Clsid))
03117             encode_image = codecs[i].encode_func;
03118     }
03119     if (encode_image == NULL)
03120         return UnknownImageFormat;
03121 
03122     stat = encode_image(image, stream, clsid, params);
03123 
03124     return stat;
03125 }
03126 
03127 /*****************************************************************************
03128  * GdipGetImagePalette [GDIPLUS.@]
03129  */
03130 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
03131 {
03132     TRACE("(%p,%p,%i)\n", image, palette, size);
03133 
03134     if (!image || !palette)
03135         return InvalidParameter;
03136 
03137     if (size < (sizeof(UINT)*2+sizeof(ARGB)*image->palette_count))
03138     {
03139         TRACE("<-- InsufficientBuffer\n");
03140         return InsufficientBuffer;
03141     }
03142 
03143     palette->Flags = image->palette_flags;
03144     palette->Count = image->palette_count;
03145     memcpy(palette->Entries, image->palette_entries, sizeof(ARGB)*image->palette_count);
03146 
03147     return Ok;
03148 }
03149 
03150 /*****************************************************************************
03151  * GdipSetImagePalette [GDIPLUS.@]
03152  */
03153 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
03154     GDIPCONST ColorPalette *palette)
03155 {
03156     TRACE("(%p,%p)\n", image, palette);
03157 
03158     if(!image || !palette || palette->Count > 256)
03159         return InvalidParameter;
03160 
03161     if (palette->Count > image->palette_size)
03162     {
03163         ARGB *new_palette;
03164 
03165         new_palette = GdipAlloc(sizeof(ARGB) * palette->Count);
03166         if (!new_palette) return OutOfMemory;
03167 
03168         GdipFree(image->palette_entries);
03169         image->palette_entries = new_palette;
03170         image->palette_size = palette->Count;
03171     }
03172 
03173     image->palette_flags = palette->Flags;
03174     image->palette_count = palette->Count;
03175     memcpy(image->palette_entries, palette->Entries, sizeof(ARGB)*palette->Count);
03176 
03177     return Ok;
03178 }
03179 
03180 /*************************************************************************
03181  * Encoders -
03182  *   Structures that represent which formats we support for encoding.
03183  */
03184 
03185 /* ImageCodecInfo creation routines taken from libgdiplus */
03186 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
03187 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
03188 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
03189 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
03190 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
03191 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
03192 
03193 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
03194 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
03195 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
03196 static const WCHAR jpeg_format[] = {'J','P','E','G',0};
03197 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
03198 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
03199 
03200 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
03201 static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
03202 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
03203 static const WCHAR gif_format[] = {'G','I','F',0};
03204 static const BYTE gif_sig_pattern[4] = "GIF8";
03205 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
03206 
03207 static const WCHAR tiff_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'T','I','F','F', 0};
03208 static const WCHAR tiff_extension[] = {'*','.','T','I','F','F',';','*','.','T','I','F',0};
03209 static const WCHAR tiff_mimetype[] = {'i','m','a','g','e','/','t','i','f','f', 0};
03210 static const WCHAR tiff_format[] = {'T','I','F','F',0};
03211 static const BYTE tiff_sig_pattern[] = {0x49,0x49,42,0,0x4d,0x4d,0,42};
03212 static const BYTE tiff_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
03213 
03214 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
03215 static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
03216 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
03217 static const WCHAR emf_format[] = {'E','M','F',0};
03218 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
03219 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
03220 
03221 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
03222 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
03223 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
03224 static const WCHAR wmf_format[] = {'W','M','F',0};
03225 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
03226 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
03227 
03228 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
03229 static const WCHAR png_extension[] = {'*','.','P','N','G',0};
03230 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
03231 static const WCHAR png_format[] = {'P','N','G',0};
03232 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
03233 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
03234 
03235 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
03236 static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
03237 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
03238 static const WCHAR ico_format[] = {'I','C','O',0};
03239 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
03240 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
03241 
03242 static const struct image_codec codecs[NUM_CODECS] = {
03243     {
03244         { /* BMP */
03245             /* Clsid */              { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03246             /* FormatID */           { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03247             /* CodecName */          bmp_codecname,
03248             /* DllName */            NULL,
03249             /* FormatDescription */  bmp_format,
03250             /* FilenameExtension */  bmp_extension,
03251             /* MimeType */           bmp_mimetype,
03252             /* Flags */              ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
03253             /* Version */            1,
03254             /* SigCount */           1,
03255             /* SigSize */            2,
03256             /* SigPattern */         bmp_sig_pattern,
03257             /* SigMask */            bmp_sig_mask,
03258         },
03259         encode_image_BMP,
03260         decode_image_bmp
03261     },
03262     {
03263         { /* JPEG */
03264             /* Clsid */              { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03265             /* FormatID */           { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03266             /* CodecName */          jpeg_codecname,
03267             /* DllName */            NULL,
03268             /* FormatDescription */  jpeg_format,
03269             /* FilenameExtension */  jpeg_extension,
03270             /* MimeType */           jpeg_mimetype,
03271             /* Flags */              ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
03272             /* Version */            1,
03273             /* SigCount */           1,
03274             /* SigSize */            2,
03275             /* SigPattern */         jpeg_sig_pattern,
03276             /* SigMask */            jpeg_sig_mask,
03277         },
03278         encode_image_jpeg,
03279         decode_image_jpeg
03280     },
03281     {
03282         { /* GIF */
03283             /* Clsid */              { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03284             /* FormatID */           { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03285             /* CodecName */          gif_codecname,
03286             /* DllName */            NULL,
03287             /* FormatDescription */  gif_format,
03288             /* FilenameExtension */  gif_extension,
03289             /* MimeType */           gif_mimetype,
03290             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
03291             /* Version */            1,
03292             /* SigCount */           1,
03293             /* SigSize */            4,
03294             /* SigPattern */         gif_sig_pattern,
03295             /* SigMask */            gif_sig_mask,
03296         },
03297         NULL,
03298         decode_image_gif
03299     },
03300     {
03301         { /* TIFF */
03302             /* Clsid */              { 0x557cf405, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03303             /* FormatID */           { 0xb96b3cb1U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03304             /* CodecName */          tiff_codecname,
03305             /* DllName */            NULL,
03306             /* FormatDescription */  tiff_format,
03307             /* FilenameExtension */  tiff_extension,
03308             /* MimeType */           tiff_mimetype,
03309             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsEncoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
03310             /* Version */            1,
03311             /* SigCount */           2,
03312             /* SigSize */            4,
03313             /* SigPattern */         tiff_sig_pattern,
03314             /* SigMask */            tiff_sig_mask,
03315         },
03316         encode_image_tiff,
03317         decode_image_tiff
03318     },
03319     {
03320         { /* EMF */
03321             /* Clsid */              { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03322             /* FormatID */           { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03323             /* CodecName */          emf_codecname,
03324             /* DllName */            NULL,
03325             /* FormatDescription */  emf_format,
03326             /* FilenameExtension */  emf_extension,
03327             /* MimeType */           emf_mimetype,
03328             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
03329             /* Version */            1,
03330             /* SigCount */           1,
03331             /* SigSize */            4,
03332             /* SigPattern */         emf_sig_pattern,
03333             /* SigMask */            emf_sig_mask,
03334         },
03335         NULL,
03336         decode_image_olepicture_metafile
03337     },
03338     {
03339         { /* WMF */
03340             /* Clsid */              { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03341             /* FormatID */           { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03342             /* CodecName */          wmf_codecname,
03343             /* DllName */            NULL,
03344             /* FormatDescription */  wmf_format,
03345             /* FilenameExtension */  wmf_extension,
03346             /* MimeType */           wmf_mimetype,
03347             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
03348             /* Version */            1,
03349             /* SigCount */           1,
03350             /* SigSize */            2,
03351             /* SigPattern */         wmf_sig_pattern,
03352             /* SigMask */            wmf_sig_mask,
03353         },
03354         NULL,
03355         decode_image_olepicture_metafile
03356     },
03357     {
03358         { /* PNG */
03359             /* Clsid */              { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03360             /* FormatID */           { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03361             /* CodecName */          png_codecname,
03362             /* DllName */            NULL,
03363             /* FormatDescription */  png_format,
03364             /* FilenameExtension */  png_extension,
03365             /* MimeType */           png_mimetype,
03366             /* Flags */              ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
03367             /* Version */            1,
03368             /* SigCount */           1,
03369             /* SigSize */            8,
03370             /* SigPattern */         png_sig_pattern,
03371             /* SigMask */            png_sig_mask,
03372         },
03373         encode_image_png,
03374         decode_image_png
03375     },
03376     {
03377         { /* ICO */
03378             /* Clsid */              { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
03379             /* FormatID */           { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
03380             /* CodecName */          ico_codecname,
03381             /* DllName */            NULL,
03382             /* FormatDescription */  ico_format,
03383             /* FilenameExtension */  ico_extension,
03384             /* MimeType */           ico_mimetype,
03385             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
03386             /* Version */            1,
03387             /* SigCount */           1,
03388             /* SigSize */            4,
03389             /* SigPattern */         ico_sig_pattern,
03390             /* SigMask */            ico_sig_mask,
03391         },
03392         NULL,
03393         decode_image_icon
03394     },
03395 };
03396 
03397 /*****************************************************************************
03398  * GdipGetImageDecodersSize [GDIPLUS.@]
03399  */
03400 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
03401 {
03402     int decoder_count=0;
03403     int i;
03404     TRACE("%p %p\n", numDecoders, size);
03405 
03406     if (!numDecoders || !size)
03407         return InvalidParameter;
03408 
03409     for (i=0; i<NUM_CODECS; i++)
03410     {
03411         if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
03412             decoder_count++;
03413     }
03414 
03415     *numDecoders = decoder_count;
03416     *size = decoder_count * sizeof(ImageCodecInfo);
03417 
03418     return Ok;
03419 }
03420 
03421 /*****************************************************************************
03422  * GdipGetImageDecoders [GDIPLUS.@]
03423  */
03424 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
03425 {
03426     int i, decoder_count=0;
03427     TRACE("%u %u %p\n", numDecoders, size, decoders);
03428 
03429     if (!decoders ||
03430         size != numDecoders * sizeof(ImageCodecInfo))
03431         return GenericError;
03432 
03433     for (i=0; i<NUM_CODECS; i++)
03434     {
03435         if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
03436         {
03437             if (decoder_count == numDecoders) return GenericError;
03438             memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
03439             decoder_count++;
03440         }
03441     }
03442 
03443     if (decoder_count < numDecoders) return GenericError;
03444 
03445     return Ok;
03446 }
03447 
03448 /*****************************************************************************
03449  * GdipGetImageEncodersSize [GDIPLUS.@]
03450  */
03451 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
03452 {
03453     int encoder_count=0;
03454     int i;
03455     TRACE("%p %p\n", numEncoders, size);
03456 
03457     if (!numEncoders || !size)
03458         return InvalidParameter;
03459 
03460     for (i=0; i<NUM_CODECS; i++)
03461     {
03462         if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
03463             encoder_count++;
03464     }
03465 
03466     *numEncoders = encoder_count;
03467     *size = encoder_count * sizeof(ImageCodecInfo);
03468 
03469     return Ok;
03470 }
03471 
03472 /*****************************************************************************
03473  * GdipGetImageEncoders [GDIPLUS.@]
03474  */
03475 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
03476 {
03477     int i, encoder_count=0;
03478     TRACE("%u %u %p\n", numEncoders, size, encoders);
03479 
03480     if (!encoders ||
03481         size != numEncoders * sizeof(ImageCodecInfo))
03482         return GenericError;
03483 
03484     for (i=0; i<NUM_CODECS; i++)
03485     {
03486         if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
03487         {
03488             if (encoder_count == numEncoders) return GenericError;
03489             memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
03490             encoder_count++;
03491         }
03492     }
03493 
03494     if (encoder_count < numEncoders) return GenericError;
03495 
03496     return Ok;
03497 }
03498 
03499 GpStatus WINGDIPAPI GdipGetEncoderParameterListSize(GpImage *image,
03500     GDIPCONST CLSID* clsidEncoder, UINT *size)
03501 {
03502     static int calls;
03503 
03504     TRACE("(%p,%s,%p)\n", image, debugstr_guid(clsidEncoder), size);
03505 
03506     if(!(calls++))
03507         FIXME("not implemented\n");
03508 
03509     *size = 0;
03510 
03511     return NotImplemented;
03512 }
03513 
03514 static PixelFormat get_16bpp_format(HBITMAP hbm)
03515 {
03516     BITMAPV4HEADER bmh;
03517     HDC hdc;
03518     PixelFormat result;
03519 
03520     hdc = CreateCompatibleDC(NULL);
03521 
03522     memset(&bmh, 0, sizeof(bmh));
03523     bmh.bV4Size = sizeof(bmh);
03524     bmh.bV4Width = 1;
03525     bmh.bV4Height = 1;
03526     bmh.bV4V4Compression = BI_BITFIELDS;
03527     bmh.bV4BitCount = 16;
03528 
03529     GetDIBits(hdc, hbm, 0, 0, NULL, (BITMAPINFO*)&bmh, DIB_RGB_COLORS);
03530 
03531     if (bmh.bV4RedMask == 0x7c00 &&
03532         bmh.bV4GreenMask == 0x3e0 &&
03533         bmh.bV4BlueMask == 0x1f)
03534     {
03535         result = PixelFormat16bppRGB555;
03536     }
03537     else if (bmh.bV4RedMask == 0xf800 &&
03538         bmh.bV4GreenMask == 0x7e0 &&
03539         bmh.bV4BlueMask == 0x1f)
03540     {
03541         result = PixelFormat16bppRGB565;
03542     }
03543     else
03544     {
03545         FIXME("unrecognized bitfields %x,%x,%x\n", bmh.bV4RedMask,
03546             bmh.bV4GreenMask, bmh.bV4BlueMask);
03547         result = PixelFormatUndefined;
03548     }
03549 
03550     DeleteDC(hdc);
03551 
03552     return result;
03553 }
03554 
03555 /*****************************************************************************
03556  * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
03557  */
03558 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
03559 {
03560     BITMAP bm;
03561     GpStatus retval;
03562     PixelFormat format;
03563     BitmapData lockeddata;
03564     INT y;
03565 
03566     TRACE("%p %p %p\n", hbm, hpal, bitmap);
03567 
03568     if(!hbm || !bitmap)
03569         return InvalidParameter;
03570 
03571     if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
03572             return InvalidParameter;
03573 
03574     /* TODO: Figure out the correct format for 16, 32, 64 bpp */
03575     switch(bm.bmBitsPixel) {
03576         case 1:
03577             format = PixelFormat1bppIndexed;
03578             break;
03579         case 4:
03580             format = PixelFormat4bppIndexed;
03581             break;
03582         case 8:
03583             format = PixelFormat8bppIndexed;
03584             break;
03585         case 16:
03586             format = get_16bpp_format(hbm);
03587             if (format == PixelFormatUndefined)
03588                 return InvalidParameter;
03589             break;
03590         case 24:
03591             format = PixelFormat24bppRGB;
03592             break;
03593         case 32:
03594             format = PixelFormat32bppRGB;
03595             break;
03596         case 48:
03597             format = PixelFormat48bppRGB;
03598             break;
03599         default:
03600             FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
03601             return InvalidParameter;
03602     }
03603 
03604     retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0,
03605         format, NULL, bitmap);
03606 
03607     if (retval == Ok)
03608     {
03609         retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite,
03610             format, &lockeddata);
03611         if (retval == Ok)
03612         {
03613             if (bm.bmBits)
03614             {
03615                 for (y=0; y<bm.bmHeight; y++)
03616                 {
03617                     memcpy((BYTE*)lockeddata.Scan0+lockeddata.Stride*y,
03618                            (BYTE*)bm.bmBits+bm.bmWidthBytes*(bm.bmHeight-1-y),
03619                            bm.bmWidthBytes);
03620                 }
03621             }
03622             else
03623             {
03624                 HDC hdc;
03625                 HBITMAP oldhbm;
03626                 BITMAPINFO *pbmi;
03627                 INT src_height, dst_stride;
03628                 BYTE *dst_bits;
03629 
03630                 hdc = CreateCompatibleDC(NULL);
03631                 oldhbm = SelectObject(hdc, hbm);
03632 
03633                 pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
03634 
03635                 if (pbmi)
03636                 {
03637                     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
03638                     pbmi->bmiHeader.biBitCount = 0;
03639 
03640                     GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
03641 
03642                     src_height = abs(pbmi->bmiHeader.biHeight);
03643 
03644                     if (pbmi->bmiHeader.biHeight > 0)
03645                     {
03646                         dst_bits = (BYTE*)lockeddata.Scan0+lockeddata.Stride*(src_height-1);
03647                         dst_stride = -lockeddata.Stride;
03648                     }
03649                     else
03650                     {
03651                         dst_bits = lockeddata.Scan0;
03652                         dst_stride = lockeddata.Stride;
03653                     }
03654 
03655                     for (y=0; y<src_height; y++)
03656                     {
03657                         GetDIBits(hdc, hbm, y, 1, dst_bits+dst_stride*y,
03658                             pbmi, DIB_RGB_COLORS);
03659                     }
03660 
03661                     GdipFree(pbmi);
03662                 }
03663                 else
03664                     retval = OutOfMemory;
03665 
03666                 SelectObject(hdc, oldhbm);
03667                 DeleteDC(hdc);
03668             }
03669 
03670             GdipBitmapUnlockBits(*bitmap, &lockeddata);
03671         }
03672 
03673         if (retval == Ok && hpal)
03674         {
03675             WORD num_palette_entries;
03676             PALETTEENTRY *palette_entries=NULL;
03677             ColorPalette *palette=NULL;
03678             int i;
03679 
03680             if (!GetObjectW(hpal, sizeof(num_palette_entries), &num_palette_entries))
03681                 retval = GenericError;
03682 
03683             if (retval == Ok)
03684             {
03685                 palette_entries = GdipAlloc(sizeof(PALETTEENTRY) * num_palette_entries);
03686                 palette = GdipAlloc(sizeof(ColorPalette) + sizeof(ARGB) * (num_palette_entries-1));
03687 
03688                 if (!palette_entries || !palette)
03689                     retval = OutOfMemory;
03690             }
03691 
03692             if (retval == Ok)
03693             {
03694                 if (!GetPaletteEntries(hpal, 0, num_palette_entries, palette_entries))
03695                     retval = GenericError;
03696             }
03697 
03698             if (retval == Ok)
03699             {
03700                 palette->Flags = 0;
03701                 palette->Count = num_palette_entries;
03702 
03703                 for (i=0; i<num_palette_entries; i++)
03704                 {
03705                     PALETTEENTRY * entry = &palette_entries[i];
03706                     palette->Entries[i] = 0xff000000 | entry->peRed << 16 |
03707                         entry->peGreen << 8 | entry->peBlue;
03708                 }
03709 
03710                 retval = GdipSetImagePalette((GpImage*)*bitmap, palette);
03711             }
03712 
03713             GdipFree(palette_entries);
03714             GdipFree(palette);
03715         }
03716 
03717         if (retval != Ok)
03718         {
03719             GdipDisposeImage((GpImage*)*bitmap);
03720             *bitmap = NULL;
03721         }
03722     }
03723 
03724     return retval;
03725 }
03726 
03727 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
03728 {
03729     FIXME("(%p): stub\n", effect);
03730     /* note: According to Jose Roca's GDI+ Docs, this is not implemented
03731      * in Windows's gdiplus */
03732     return NotImplemented;
03733 }
03734 
03735 /*****************************************************************************
03736  * GdipSetEffectParameters [GDIPLUS.@]
03737  */
03738 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
03739     const VOID *params, const UINT size)
03740 {
03741     static int calls;
03742 
03743     TRACE("(%p,%p,%u)\n", effect, params, size);
03744 
03745     if(!(calls++))
03746         FIXME("not implemented\n");
03747 
03748     return NotImplemented;
03749 }
03750 
03751 /*****************************************************************************
03752  * GdipGetImageFlags [GDIPLUS.@]
03753  */
03754 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
03755 {
03756     TRACE("%p %p\n", image, flags);
03757 
03758     if(!image || !flags)
03759         return InvalidParameter;
03760 
03761     *flags = image->flags;
03762 
03763     return Ok;
03764 }
03765 
03766 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
03767 {
03768     TRACE("(%d, %p)\n", control, param);
03769 
03770     switch(control){
03771         case TestControlForceBilinear:
03772             if(param)
03773                 FIXME("TestControlForceBilinear not handled\n");
03774             break;
03775         case TestControlNoICM:
03776             if(param)
03777                 FIXME("TestControlNoICM not handled\n");
03778             break;
03779         case TestControlGetBuildNumber:
03780             *((DWORD*)param) = 3102;
03781             break;
03782     }
03783 
03784     return Ok;
03785 }
03786 
03787 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
03788                             HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
03789                             MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
03790                             GpMetafile **metafile)
03791 {
03792     FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
03793                                  frameUnit, debugstr_w(desc), metafile);
03794 
03795     return NotImplemented;
03796 }
03797 
03798 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
03799                             GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
03800                             GDIPCONST WCHAR *desc, GpMetafile **metafile)
03801 {
03802     FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
03803                                  frameUnit, debugstr_w(desc), metafile);
03804 
03805     return NotImplemented;
03806 }
03807 
03808 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
03809 {
03810     TRACE("%p\n", image);
03811 
03812     return Ok;
03813 }
03814 
03815 /*****************************************************************************
03816  * GdipGetImageThumbnail [GDIPLUS.@]
03817  */
03818 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
03819                             GpImage **ret_image, GetThumbnailImageAbort cb,
03820                             VOID * cb_data)
03821 {
03822     GpStatus stat;
03823     GpGraphics *graphics;
03824     UINT srcwidth, srcheight;
03825 
03826     TRACE("(%p %u %u %p %p %p)\n",
03827         image, width, height, ret_image, cb, cb_data);
03828 
03829     if (!image || !ret_image)
03830         return InvalidParameter;
03831 
03832     if (!width) width = 120;
03833     if (!height) height = 120;
03834 
03835     GdipGetImageWidth(image, &srcwidth);
03836     GdipGetImageHeight(image, &srcheight);
03837 
03838     stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB,
03839         NULL, (GpBitmap**)ret_image);
03840 
03841     if (stat == Ok)
03842     {
03843         stat = GdipGetImageGraphicsContext(*ret_image, &graphics);
03844 
03845         if (stat == Ok)
03846         {
03847             stat = GdipDrawImageRectRectI(graphics, image,
03848                 0, 0, width, height, 0, 0, srcwidth, srcheight, UnitPixel,
03849                 NULL, NULL, NULL);
03850 
03851             GdipDeleteGraphics(graphics);
03852         }
03853 
03854         if (stat != Ok)
03855         {
03856             GdipDisposeImage(*ret_image);
03857             *ret_image = NULL;
03858         }
03859     }
03860 
03861     return stat;
03862 }
03863 
03864 /*****************************************************************************
03865  * GdipImageRotateFlip [GDIPLUS.@]
03866  */
03867 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
03868 {
03869     GpBitmap *new_bitmap;
03870     GpBitmap *bitmap;
03871     int bpp, bytesperpixel;
03872     int rotate_90, flip_x, flip_y;
03873     int src_x_offset, src_y_offset;
03874     LPBYTE src_origin;
03875     UINT x, y, width, height;
03876     BitmapData src_lock, dst_lock;
03877     GpStatus stat;
03878 
03879     TRACE("(%p, %u)\n", image, type);
03880 
03881     rotate_90 = type&1;
03882     flip_x = (type&6) == 2 || (type&6) == 4;
03883     flip_y = (type&3) == 1 || (type&3) == 2;
03884 
03885     if (image->type != ImageTypeBitmap)
03886     {
03887         FIXME("Not implemented for type %i\n", image->type);
03888         return NotImplemented;
03889     }
03890 
03891     bitmap = (GpBitmap*)image;
03892     bpp = PIXELFORMATBPP(bitmap->format);
03893 
03894     if (bpp < 8)
03895     {
03896         FIXME("Not implemented for %i bit images\n", bpp);
03897         return NotImplemented;
03898     }
03899 
03900     if (rotate_90)
03901     {
03902         width = bitmap->height;
03903         height = bitmap->width;
03904     }
03905     else
03906     {
03907         width = bitmap->width;
03908         height = bitmap->height;
03909     }
03910 
03911     bytesperpixel = bpp/8;
03912 
03913     stat = GdipCreateBitmapFromScan0(width, height, 0, bitmap->format, NULL, &new_bitmap);
03914 
03915     if (stat != Ok)
03916         return stat;
03917 
03918     stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format, &src_lock);
03919 
03920     if (stat == Ok)
03921     {
03922         stat = GdipBitmapLockBits(new_bitmap, NULL, ImageLockModeWrite, bitmap->format, &dst_lock);
03923 
03924         if (stat == Ok)
03925         {
03926             LPBYTE src_row, src_pixel;
03927             LPBYTE dst_row, dst_pixel;
03928 
03929             src_origin = src_lock.Scan0;
03930             if (flip_x) src_origin += bytesperpixel * (bitmap->width - 1);
03931             if (flip_y) src_origin += src_lock.Stride * (bitmap->height - 1);
03932 
03933             if (rotate_90)
03934             {
03935                 if (flip_y) src_x_offset = -src_lock.Stride;
03936                 else src_x_offset = src_lock.Stride;
03937                 if (flip_x) src_y_offset = -bytesperpixel;
03938                 else src_y_offset = bytesperpixel;
03939             }
03940             else
03941             {
03942                 if (flip_x) src_x_offset = -bytesperpixel;
03943                 else src_x_offset = bytesperpixel;
03944                 if (flip_y) src_y_offset = -src_lock.Stride;
03945                 else src_y_offset = src_lock.Stride;
03946             }
03947 
03948             src_row = src_origin;
03949             dst_row = dst_lock.Scan0;
03950             for (y=0; y<height; y++)
03951             {
03952                 src_pixel = src_row;
03953                 dst_pixel = dst_row;
03954                 for (x=0; x<width; x++)
03955                 {
03956                     /* FIXME: This could probably be faster without memcpy. */
03957                     memcpy(dst_pixel, src_pixel, bytesperpixel);
03958                     dst_pixel += bytesperpixel;
03959                     src_pixel += src_x_offset;
03960                 }
03961                 src_row += src_y_offset;
03962                 dst_row += dst_lock.Stride;
03963             }
03964 
03965             GdipBitmapUnlockBits(new_bitmap, &dst_lock);
03966         }
03967 
03968         GdipBitmapUnlockBits(bitmap, &src_lock);
03969     }
03970 
03971     if (stat == Ok)
03972         move_bitmap(bitmap, new_bitmap, FALSE);
03973     else
03974         GdipDisposeImage((GpImage*)new_bitmap);
03975 
03976     return stat;
03977 }
03978 
03979 /*****************************************************************************
03980  * GdipConvertToEmfPlusToFile [GDIPLUS.@]
03981  */
03982 
03983 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
03984                                                GpMetafile* metafile, BOOL* conversionSuccess,
03985                                                const WCHAR* filename, EmfType emfType,
03986                                                const WCHAR* description, GpMetafile** out_metafile)
03987 {
03988     FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
03989     return NotImplemented;
03990 }

Generated on Sat May 26 2012 04:19:06 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.