From 71710290299317d6db44b598b5d9cbbc4a5a59d7 Mon Sep 17 00:00:00 2001 From: Gregor Schneider Date: Sat, 28 Nov 2009 15:26:02 +0000 Subject: [PATCH] [gdiplus] - Update to current Wine sources - Now routes BMP drawing to gdi instead of doing ole32 magic (bug #3412) svn path=/trunk/; revision=44308 --- reactos/dll/win32/gdiplus/brush.c | 237 ++++++++-- reactos/dll/win32/gdiplus/gdiplus.c | 29 +- reactos/dll/win32/gdiplus/gdiplus.spec | 8 +- reactos/dll/win32/gdiplus/gdiplus_private.h | 6 +- reactos/dll/win32/gdiplus/graphics.c | 90 ++-- reactos/dll/win32/gdiplus/image.c | 464 ++++++++++++++------ 6 files changed, 612 insertions(+), 222 deletions(-) diff --git a/reactos/dll/win32/gdiplus/brush.c b/reactos/dll/win32/gdiplus/brush.c index 6220443b04d..bfce7d85bb5 100644 --- a/reactos/dll/win32/gdiplus/brush.c +++ b/reactos/dll/win32/gdiplus/brush.c @@ -143,7 +143,7 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) } case BrushTypeLinearGradient:{ GpLineGradient *dest, *src; - INT count; + INT count, pcount; dest = GdipAlloc(sizeof(GpLineGradient)); if(!dest) return OutOfMemory; @@ -157,11 +157,20 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) count = dest->blendcount; dest->blendfac = GdipAlloc(count * sizeof(REAL)); dest->blendpos = GdipAlloc(count * sizeof(REAL)); + pcount = dest->pblendcount; + if (pcount) + { + dest->pblendcolor = GdipAlloc(pcount * sizeof(ARGB)); + dest->pblendpos = GdipAlloc(pcount * sizeof(REAL)); + } - if (!dest->blendfac || !dest->blendpos) + if (!dest->blendfac || !dest->blendpos || + (pcount && (!dest->pblendcolor || !dest->pblendpos))) { GdipFree(dest->blendfac); GdipFree(dest->blendpos); + GdipFree(dest->pblendcolor); + GdipFree(dest->pblendpos); DeleteObject(dest->brush.gdibrush); GdipFree(dest); return OutOfMemory; @@ -170,6 +179,12 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL)); memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL)); + if (pcount) + { + memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB)); + memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL)); + } + *clone = &dest->brush; break; } @@ -189,19 +204,38 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) return Ok; } -static LONG HatchStyleToHatch(HatchStyle hatchstyle) -{ - switch (hatchstyle) - { - case HatchStyleHorizontal: return HS_HORIZONTAL; - case HatchStyleVertical: return HS_VERTICAL; - case HatchStyleForwardDiagonal: return HS_FDIAGONAL; - case HatchStyleBackwardDiagonal: return HS_BDIAGONAL; - case HatchStyleCross: return HS_CROSS; - case HatchStyleDiagonalCross: return HS_DIAGCROSS; - default: return 0; - } -} +static const char HatchBrushes[][8] = { + { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */ + { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */ + { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */ + { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */ + { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */ + { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */ + { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */ + { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */ + { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */ + { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */ + { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */ + { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */ + { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */ + { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */ + { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */ + { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */ + { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */ + { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */ + { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */ + { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */ + { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */ + { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */ + { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */ + { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */ + { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */ + { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */ + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */ + { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */ + { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */ + { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */ +}; /****************************************************************************** * GdipCreateHatchBrush [GDIPLUS.@] @@ -209,6 +243,7 @@ static LONG HatchStyleToHatch(HatchStyle hatchstyle) GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush) { COLORREF fgcol = ARGB2COLORREF(forecol); + GpStatus stat = Ok; TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush); @@ -217,37 +252,79 @@ GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, AR *brush = GdipAlloc(sizeof(GpHatch)); if (!*brush) return OutOfMemory; - switch (hatchstyle) + if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0])) { - case HatchStyleHorizontal: - case HatchStyleVertical: - case HatchStyleForwardDiagonal: - case HatchStyleBackwardDiagonal: - case HatchStyleCross: - case HatchStyleDiagonalCross: - /* Brushes that map to BS_HATCHED */ - (*brush)->brush.lb.lbStyle = BS_HATCHED; - (*brush)->brush.lb.lbColor = fgcol; - (*brush)->brush.lb.lbHatch = HatchStyleToHatch(hatchstyle); - break; + HBITMAP hbmp; + HDC hdc; + BITMAPINFOHEADER bmih; + DWORD* bits; + int x, y; - default: - FIXME("Unimplemented hatch style %d\n", hatchstyle); + hdc = CreateCompatibleDC(0); - (*brush)->brush.lb.lbStyle = BS_SOLID; - (*brush)->brush.lb.lbColor = fgcol; - (*brush)->brush.lb.lbHatch = 0; - break; + if (hdc) + { + bmih.biSize = sizeof(bmih); + bmih.biWidth = 8; + bmih.biHeight = 8; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = 0; + + hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + + if (hbmp) + { + for (y=0; y<8; y++) + for (x=0; x<8; x++) + if ((HatchBrushes[hatchstyle][y] & (0x80 >> x)) != 0) + bits[y*8+x] = forecol; + else + bits[y*8+x] = backcol; + } + else + stat = GenericError; + + DeleteDC(hdc); + } + else + stat = GenericError; + + if (stat == Ok) + { + (*brush)->brush.lb.lbStyle = BS_PATTERN; + (*brush)->brush.lb.lbColor = 0; + (*brush)->brush.lb.lbHatch = (ULONG_PTR)hbmp; + (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb); + + DeleteObject(hbmp); + } } + else + { + FIXME("Unimplemented hatch style %d\n", hatchstyle); + (*brush)->brush.lb.lbStyle = BS_SOLID; + (*brush)->brush.lb.lbColor = fgcol; + (*brush)->brush.lb.lbHatch = 0; + (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb); + } - (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb); - (*brush)->brush.bt = BrushTypeHatchFill; - (*brush)->forecol = forecol; - (*brush)->backcol = backcol; - (*brush)->hatchstyle = hatchstyle; + if (stat == Ok) + { + (*brush)->brush.bt = BrushTypeHatchFill; + (*brush)->forecol = forecol; + (*brush)->backcol = backcol; + (*brush)->hatchstyle = hatchstyle; + } + else + { + GdipFree(*brush); + *brush = NULL; + } - return Ok; + return stat; } /****************************************************************************** @@ -316,6 +393,10 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint, (*line)->blendfac[0] = 1.0f; (*line)->blendpos[0] = 1.0f; + (*line)->pblendcolor = NULL; + (*line)->pblendpos = NULL; + (*line)->pblendcount = 0; + return Ok; } @@ -762,7 +843,7 @@ GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image, /* image is flipped */ if(pbmi->bmiHeader.biHeight > 0){ - dibits += pbmi->bmiHeader.biSizeImage; + dibits += image_stride * (pbmi->bmiHeader.biHeight - 1); image_stride *= -1; textbits += stride * (n_height - 1); stride *= -1; @@ -893,6 +974,8 @@ GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush) case BrushTypeLinearGradient: GdipFree(((GpLineGradient*)brush)->blendfac); GdipFree(((GpLineGradient*)brush)->blendpos); + GdipFree(((GpLineGradient*)brush)->pblendcolor); + GdipFree(((GpLineGradient*)brush)->pblendpos); break; case BrushTypeTextureFill: GdipDeleteMatrix(((GpTexture*)brush)->transform); @@ -1600,6 +1683,69 @@ GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus, GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush, GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count) +{ + ARGB *new_color; + REAL *new_pos; + TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count); + + if (!brush || !blend || !positions || count < 2 || + positions[0] != 0.0f || positions[count-1] != 1.0f) + { + return InvalidParameter; + } + + new_color = GdipAlloc(count * sizeof(ARGB)); + new_pos = GdipAlloc(count * sizeof(REAL)); + if (!new_color || !new_pos) + { + GdipFree(new_color); + GdipFree(new_pos); + return OutOfMemory; + } + + memcpy(new_color, blend, sizeof(ARGB) * count); + memcpy(new_pos, positions, sizeof(REAL) * count); + + GdipFree(brush->pblendcolor); + GdipFree(brush->pblendpos); + + brush->pblendcolor = new_color; + brush->pblendpos = new_pos; + brush->pblendcount = count; + + return Ok; +} + +GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush, + ARGB *blend, REAL* positions, INT count) +{ + if (!brush || !blend || !positions || count < 2) + return InvalidParameter; + + if (brush->pblendcount == 0) + return GenericError; + + if (count < brush->pblendcount) + return InsufficientBuffer; + + memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount); + memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount); + + return Ok; +} + +GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush, + INT *count) +{ + if (!brush || !count) + return InvalidParameter; + + *count = brush->pblendcount; + + return Ok; +} + +GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush) { static int calls; @@ -1620,6 +1766,17 @@ GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush, return NotImplemented; } +GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy, + GpMatrixOrder order) +{ + static int calls; + + if(!(calls++)) + FIXME("not implemented\n"); + + return NotImplemented; +} + GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush, REAL dx, REAL dy, GpMatrixOrder order) { diff --git a/reactos/dll/win32/gdiplus/gdiplus.c b/reactos/dll/win32/gdiplus/gdiplus.c index ec956f34f57..9fe933280ab 100644 --- a/reactos/dll/win32/gdiplus/gdiplus.c +++ b/reactos/dll/win32/gdiplus/gdiplus.c @@ -86,7 +86,7 @@ Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput input->DebugEventCallback, input->SuppressBackgroundThread, input->SuppressExternalCodecs); - if(input->GdiplusVersion != 1) + if(input->GdiplusVersion < 1 || input->GdiplusVersion > 2) return UnsupportedGdiplusVersion; if(input->SuppressBackgroundThread){ @@ -211,38 +211,37 @@ static void unstretch_angle(REAL * angle, REAL rad_x, REAL rad_y) INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2, REAL startAngle, REAL sweepAngle) { - INT i, count; + INT i; REAL end_angle, start_angle, endAngle; endAngle = startAngle + sweepAngle; unstretch_angle(&startAngle, x2 / 2.0, y2 / 2.0); unstretch_angle(&endAngle, x2 / 2.0, y2 / 2.0); - count = ceilf(fabs(endAngle - startAngle) / M_PI_2) * 3 + 1; - /* don't make more than a full circle */ - count = min(MAX_ARC_PTS, count); - - if(count == 1) - return 0; - if(!points) - return count; - /* start_angle and end_angle are the iterative variables */ start_angle = startAngle; - for(i = 0; i < count - 1; i += 3){ + for(i = 0; i < MAX_ARC_PTS - 1; i += 3){ /* check if we've overshot the end angle */ if( sweepAngle > 0.0 ) + { + if (start_angle >= endAngle) break; end_angle = min(start_angle + M_PI_2, endAngle); + } else + { + if (start_angle <= endAngle) break; end_angle = max(start_angle - M_PI_2, endAngle); + } - add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0); + if (points) + add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0); start_angle += M_PI_2 * (sweepAngle < 0.0 ? -1.0 : 1.0); } - return count; + if (i == 0) return 0; + else return i+1; } COLORREF ARGB2COLORREF(ARGB color) @@ -419,7 +418,7 @@ void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height, } /* recursive deletion of GpRegion nodes */ -inline void delete_element(region_element* element) +void delete_element(region_element* element) { switch(element->type) { diff --git a/reactos/dll/win32/gdiplus/gdiplus.spec b/reactos/dll/win32/gdiplus/gdiplus.spec index bda241ed93b..aa64a3cb311 100644 --- a/reactos/dll/win32/gdiplus/gdiplus.spec +++ b/reactos/dll/win32/gdiplus/gdiplus.spec @@ -304,8 +304,8 @@ @ stdcall GdipGetLineBlendCount(ptr ptr) @ stdcall GdipGetLineColors(ptr ptr) @ stdcall GdipGetLineGammaCorrection(ptr ptr) -@ stub GdipGetLinePresetBlend -@ stub GdipGetLinePresetBlendCount +@ stdcall GdipGetLinePresetBlend(ptr ptr ptr long) +@ stdcall GdipGetLinePresetBlendCount(ptr ptr) @ stdcall GdipGetLineRect(ptr ptr) @ stdcall GdipGetLineRectI(ptr ptr) @ stdcall GdipGetLineSpacing(ptr long ptr) @@ -476,7 +476,7 @@ @ stdcall GdipRemovePropertyItem(ptr long) @ stdcall GdipResetClip(ptr) @ stub GdipResetImageAttributes -@ stub GdipResetLineTransform +@ stdcall GdipResetLineTransform(ptr) @ stub GdipResetPageTransform @ stdcall GdipResetPath(ptr) @ stub GdipResetPathGradientTransform @@ -496,7 +496,7 @@ @ stdcall GdipSaveGraphics(ptr ptr) @ stdcall GdipSaveImageToFile(ptr ptr ptr ptr) @ stdcall GdipSaveImageToStream(ptr ptr ptr ptr) -@ stub GdipScaleLineTransform +@ stdcall GdipScaleLineTransform(ptr long long long) @ stdcall GdipScaleMatrix(ptr long long long) @ stub GdipScalePathGradientTransform @ stdcall GdipScalePenTransform(ptr long long long) diff --git a/reactos/dll/win32/gdiplus/gdiplus_private.h b/reactos/dll/win32/gdiplus/gdiplus_private.h index e87176e3064..dfff66c0a3a 100644 --- a/reactos/dll/win32/gdiplus/gdiplus_private.h +++ b/reactos/dll/win32/gdiplus/gdiplus_private.h @@ -61,7 +61,7 @@ extern BOOL lengthen_path(GpPath *path, INT len); extern GpStatus trace_path(GpGraphics *graphics, GpPath *path); typedef struct region_element region_element; -extern inline void delete_element(region_element *element); +extern void delete_element(region_element *element); static inline INT roundr(REAL x) { @@ -166,6 +166,9 @@ struct GpLineGradient{ REAL* blendfac; /* blend factors */ REAL* blendpos; /* blend positions */ INT blendcount; + ARGB* pblendcolor; /* preset blend colors */ + REAL* pblendpos; /* preset blend positions */ + INT pblendcount; }; struct GpTexture{ @@ -208,6 +211,7 @@ struct GpAdustableArrowCap{ struct GpImage{ IPicture* picture; ImageType type; + GUID format; UINT flags; }; diff --git a/reactos/dll/win32/gdiplus/graphics.c b/reactos/dll/win32/gdiplus/graphics.c index 1df3eee4ba0..df107e42040 100644 --- a/reactos/dll/win32/gdiplus/graphics.c +++ b/reactos/dll/win32/gdiplus/graphics.c @@ -220,7 +220,27 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position) blendfac = (left_blendfac * (right_blendpos - position) + right_blendfac * (position - left_blendpos)) / range; } - return blend_colors(brush->startcolor, brush->endcolor, blendfac); + + if (brush->pblendcount == 0) + return blend_colors(brush->startcolor, brush->endcolor, blendfac); + else + { + int i=1; + ARGB left_blendcolor, right_blendcolor; + REAL left_blendpos, right_blendpos; + + /* locate the blend colors surrounding this position */ + while (blendfac > brush->pblendpos[i]) + i++; + + /* interpolate between the blend colors */ + left_blendpos = brush->pblendpos[i-1]; + left_blendcolor = brush->pblendcolor[i-1]; + right_blendpos = brush->pblendpos[i]; + right_blendcolor = brush->pblendcolor[i]; + blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos); + return blend_colors(left_blendcolor, right_blendcolor, blendfac); + } } static void brush_fill_path(GpGraphics *graphics, GpBrush* brush) @@ -1235,6 +1255,7 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, (*metafile)->image.type = ImageTypeMetafile; + memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID)); (*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch); (*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Right) / ((REAL) placeable->Inch); (*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right @@ -1795,16 +1816,25 @@ GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image, REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight, GpUnit srcUnit) { - FIXME("(%p, %p, %f, %f, %f, %f, %f, %f, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); - return NotImplemented; + GpPointF points[3]; + TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); + + points[0].X = points[2].X = x; + points[0].Y = points[1].Y = y; + + /* FIXME: convert image coordinates to Graphics coordinates? */ + points[1].X = x + srcwidth; + points[2].Y = y + srcheight; + + return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy, + srcwidth, srcheight, srcUnit, NULL, NULL, NULL); } GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image, INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight, GpUnit srcUnit) { - FIXME("(%p, %p, %d, %d, %d, %d, %d, %d, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); - return NotImplemented; + return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit); } GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image, @@ -1854,15 +1884,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image else return NotImplemented; - /* IPicture renders bitmaps with the y-axis reversed - * FIXME: flipping for unknown image type might not be correct. */ - if(image->type != ImageTypeMetafile){ - INT temp; - temp = pti[0].y; - pti[0].y = pti[2].y; - pti[2].y = temp; - } - if(IPicture_Render(image->picture, graphics->hdc, pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y, srcx * dx, srcy * dy, @@ -2362,7 +2383,7 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string HFONT gdifont; LOGFONTW lfw; TEXTMETRICW textmet; - GpPointF pt[2], rectcpy[4]; + GpPointF pt[3], rectcpy[4]; POINT corners[4]; WCHAR* stringdup; REAL angle, ang_cos, ang_sin, rel_width, rel_height; @@ -2409,6 +2430,21 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string SetBkMode(graphics->hdc, TRANSPARENT); SetTextColor(graphics->hdc, brush->lb.lbColor); + pt[0].X = 0.0; + pt[0].Y = 0.0; + pt[1].X = 1.0; + pt[1].Y = 0.0; + pt[2].X = 0.0; + pt[2].Y = 1.0; + GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3); + angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X)); + ang_cos = cos(angle); + ang_sin = sin(angle); + rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+ + (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X)); + rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+ + (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X)); + rectcpy[3].X = rectcpy[0].X = rect->X; rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety; rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width; @@ -2416,30 +2452,14 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string transform_and_round_points(graphics, corners, rectcpy, 4); if (roundr(rect->Width) == 0) - { - rel_width = 1.0; nwidth = INT_MAX; - } else - { - rel_width = sqrt((corners[1].x - corners[0].x) * (corners[1].x - corners[0].x) + - (corners[1].y - corners[0].y) * (corners[1].y - corners[0].y)) - / rect->Width; nwidth = roundr(rel_width * rect->Width); - } if (roundr(rect->Height) == 0) - { - rel_height = 1.0; nheight = INT_MAX; - } else - { - rel_height = sqrt((corners[2].x - corners[1].x) * (corners[2].x - corners[1].x) + - (corners[2].y - corners[1].y) * (corners[2].y - corners[1].y)) - / rect->Height; nheight = roundr(rel_height * rect->Height); - } if (roundr(rect->Width) != 0 && roundr(rect->Height) != 0) { @@ -2457,14 +2477,6 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height); lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width); - pt[0].X = 0.0; - pt[0].Y = 0.0; - pt[1].X = 1.0; - pt[1].Y = 0.0; - GdipTransformMatrixPoints(graphics->worldtrans, pt, 2); - angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X)); - ang_cos = cos(angle); - ang_sin = sin(angle); lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0); gdifont = CreateFontIndirectW(&lfw); diff --git a/reactos/dll/win32/gdiplus/image.c b/reactos/dll/win32/gdiplus/image.c index b1e831fdf99..5b70918aa07 100644 --- a/reactos/dll/win32/gdiplus/image.c +++ b/reactos/dll/win32/gdiplus/image.c @@ -94,36 +94,321 @@ GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps, return NotImplemented; } +static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *r = *g = *b = row[x*2+1]; + *a = 255; +} + +static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + WORD pixel = *((WORD*)(row)+x); + *r = (pixel>>7&0xf8)|(pixel>>12&0x7); + *g = (pixel>>2&0xf8)|(pixel>>6&0x7); + *b = (pixel<<3&0xf8)|(pixel>>2&0x7); + *a = 255; +} + +static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + WORD pixel = *((WORD*)(row)+x); + *r = (pixel>>8&0xf8)|(pixel>>13&0x7); + *g = (pixel>>3&0xfc)|(pixel>>9&0x3); + *b = (pixel<<3&0xf8)|(pixel>>2&0x7); + *a = 255; +} + +static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + WORD pixel = *((WORD*)(row)+x); + *r = (pixel>>7&0xf8)|(pixel>>12&0x7); + *g = (pixel>>2&0xf8)|(pixel>>6&0x7); + *b = (pixel<<3&0xf8)|(pixel>>2&0x7); + if ((pixel&0x8000) == 0x8000) + *a = 255; + else + *a = 0; +} + +static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *r = row[x*3+2]; + *g = row[x*3+1]; + *b = row[x*3]; + *a = 255; +} + +static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *r = row[x*4+2]; + *g = row[x*4+1]; + *b = row[x*4]; + *a = 255; +} + +static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *r = row[x*4+2]; + *g = row[x*4+1]; + *b = row[x*4]; + *a = row[x*4+3]; +} + +static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *a = row[x*4+3]; + if (*a == 0) + *r = *g = *b = 0; + else + { + *r = row[x*4+2] * 255 / *a; + *g = row[x*4+1] * 255 / *a; + *b = row[x*4] * 255 / *a; + } +} + +static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *r = row[x*6+5]; + *g = row[x*6+3]; + *b = row[x*6+1]; + *a = 255; +} + +static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *r = row[x*8+5]; + *g = row[x*8+3]; + *b = row[x*8+1]; + *a = row[x*8+7]; +} + +static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a, + const BYTE *row, UINT x) +{ + *a = row[x*8+7]; + if (*a == 0) + *r = *g = *b = 0; + else + { + *r = row[x*8+5] * 255 / *a; + *g = row[x*8+3] * 255 / *a; + *b = row[x*8+1] * 255 / *a; + } +} + GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y, ARGB *color) { - static int calls; + BYTE r, g, b, a; + BYTE *row; TRACE("%p %d %d %p\n", bitmap, x, y, color); - if(!bitmap || !color) + if(!bitmap || !color || + x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height) return InvalidParameter; - if(!(calls++)) - FIXME("not implemented\n"); + row = bitmap->bits+bitmap->stride*y; - *color = 0xdeadbeef; + switch (bitmap->format) + { + case PixelFormat16bppGrayScale: + getpixel_16bppGrayScale(&r,&g,&b,&a,row,x); + break; + case PixelFormat16bppRGB555: + getpixel_16bppRGB555(&r,&g,&b,&a,row,x); + break; + case PixelFormat16bppRGB565: + getpixel_16bppRGB565(&r,&g,&b,&a,row,x); + break; + case PixelFormat16bppARGB1555: + getpixel_16bppARGB1555(&r,&g,&b,&a,row,x); + break; + case PixelFormat24bppRGB: + getpixel_24bppRGB(&r,&g,&b,&a,row,x); + break; + case PixelFormat32bppRGB: + getpixel_32bppRGB(&r,&g,&b,&a,row,x); + break; + case PixelFormat32bppARGB: + getpixel_32bppARGB(&r,&g,&b,&a,row,x); + break; + case PixelFormat32bppPARGB: + getpixel_32bppPARGB(&r,&g,&b,&a,row,x); + break; + case PixelFormat48bppRGB: + getpixel_48bppRGB(&r,&g,&b,&a,row,x); + break; + case PixelFormat64bppARGB: + getpixel_64bppARGB(&r,&g,&b,&a,row,x); + break; + case PixelFormat64bppPARGB: + getpixel_64bppPARGB(&r,&g,&b,&a,row,x); + break; + default: + FIXME("not implemented for format 0x%x\n", bitmap->format); + return NotImplemented; + } - return NotImplemented; + *color = a<<24|r<<16|g<<8|b; + + return Ok; +} + +static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + *((WORD*)(row)+x) = (r+g+b)*85; +} + +static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + *((WORD*)(row)+x) = (r<<7&0x7c00)| + (g<<2&0x03e0)| + (b>>3&0x001f); +} + +static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + *((WORD*)(row)+x) = (r<<8&0xf800)| + (g<<3&0x07e0)| + (b>>3&0x001f); +} + +static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + *((WORD*)(row)+x) = (a<<8&0x8000)| + (r<<7&0x7c00)| + (g<<2&0x03e0)| + (b>>3&0x001f); +} + +static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + row[x*3+2] = r; + row[x*3+1] = g; + row[x*3] = b; +} + +static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b; +} + +static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b; +} + +static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + r = r * a / 255; + g = g * a / 255; + b = b * a / 255; + *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b; +} + +static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + row[x*6+5] = row[x*6+4] = r; + row[x*6+3] = row[x*6+2] = g; + row[x*6+1] = row[x*6] = b; +} + +static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + UINT64 a64=a, r64=r, g64=g, b64=b; + *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64; +} + +static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a, + BYTE *row, UINT x) +{ + UINT64 a64, r64, g64, b64; + a64 = a * 257; + r64 = r * a / 255; + g64 = g * a / 255; + b64 = b * a / 255; + *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64; } GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y, ARGB color) { - static int calls; + BYTE a, r, g, b; + BYTE *row; TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color); - if(!bitmap) + if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height) return InvalidParameter; - if(!(calls++)) - FIXME("not implemented\n"); + a = color>>24; + r = color>>16; + g = color>>8; + b = color; - return NotImplemented; + row = bitmap->bits + bitmap->stride * y; + + switch (bitmap->format) + { + case PixelFormat16bppGrayScale: + setpixel_16bppGrayScale(r,g,b,a,row,x); + break; + case PixelFormat16bppRGB555: + setpixel_16bppRGB555(r,g,b,a,row,x); + break; + case PixelFormat16bppRGB565: + setpixel_16bppRGB565(r,g,b,a,row,x); + break; + case PixelFormat16bppARGB1555: + setpixel_16bppARGB1555(r,g,b,a,row,x); + break; + case PixelFormat24bppRGB: + setpixel_24bppRGB(r,g,b,a,row,x); + break; + case PixelFormat32bppRGB: + setpixel_32bppRGB(r,g,b,a,row,x); + break; + case PixelFormat32bppARGB: + setpixel_32bppARGB(r,g,b,a,row,x); + break; + case PixelFormat32bppPARGB: + setpixel_32bppPARGB(r,g,b,a,row,x); + break; + case PixelFormat48bppRGB: + setpixel_48bppRGB(r,g,b,a,row,x); + break; + case PixelFormat64bppARGB: + setpixel_64bppARGB(r,g,b,a,row,x); + break; + case PixelFormat64bppPARGB: + setpixel_64bppPARGB(r,g,b,a,row,x); + break; + default: + FIXME("not implemented for format 0x%x\n", bitmap->format); + return NotImplemented; + } + + return Ok; } /* This function returns a pointer to an array of pixels that represents the @@ -413,6 +698,8 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage) GdipDisposeImage(*cloneImage); *cloneImage = NULL; } + else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID)); + return stat; } else @@ -645,11 +932,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap) TRACE("%p, %p\n", hicon, bitmap); if(!bitmap || !GetIconInfo(hicon, &iinfo)) - { - DeleteObject(iinfo.hbmColor); - DeleteObject(iinfo.hbmMask); return InvalidParameter; - } /* get the size of the icon */ ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm); @@ -858,6 +1141,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride, } (*bitmap)->image.type = ImageTypeBitmap; + memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID)); (*bitmap)->image.flags = ImageFlagsNone; (*bitmap)->width = width; (*bitmap)->height = height; @@ -1144,23 +1428,11 @@ GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format) GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format) { - static int calls; - if(!image || !format) return InvalidParameter; - if(!(calls++)) - FIXME("stub\n"); + memcpy(format, &image->format, sizeof(GUID)); - /* FIXME: should be detected from embedded picture or stored separately */ - switch (image->type) - { - case ImageTypeBitmap: *format = ImageFormatBMP; break; - case ImageTypeMetafile: *format = ImageFormatEMF; break; - default: - WARN("unknown type %u\n", image->type); - *format = ImageFormatUndefined; - } return Ok; } @@ -1507,105 +1779,37 @@ static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **ima return decode_image_wic(stream, &CLSID_WICIcoDecoder, image); } -static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image) +static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image) { - return decode_image_wic(stream, &CLSID_WICJpegDecoder, image); -} - -static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image) -{ - return decode_image_wic(stream, &CLSID_WICGifDecoder, image); -} - -static GpStatus decode_image_olepicture_bitmap(IStream* stream, REFCLSID clsid, GpImage **image) -{ - IPicture *pic; - BITMAPINFO *pbmi; - BITMAPCOREHEADER* bmch; - HBITMAP hbm; - HDC hdc; - - TRACE("%p %p\n", stream, image); - - if(!stream || !image) - return InvalidParameter; - - if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture, - (LPVOID*) &pic) != S_OK){ - TRACE("Could not load picture\n"); - return GenericError; - } - - pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - if (!pbmi) - return OutOfMemory; - *image = GdipAlloc(sizeof(GpBitmap)); - if(!*image){ - GdipFree(pbmi); - return OutOfMemory; - } - (*image)->type = ImageTypeBitmap; - - (*((GpBitmap**) image))->width = ipicture_pixel_width(pic); - (*((GpBitmap**) image))->height = ipicture_pixel_height(pic); + GpStatus status; + GpBitmap* bitmap; - /* get the pixel format */ - IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm); - IPicture_get_CurDC(pic, &hdc); + status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image); - (*((GpBitmap**) image))->hbitmap = hbm; - (*((GpBitmap**) image))->hdc = hdc; - (*((GpBitmap**) image))->bits = NULL; + bitmap = (GpBitmap*)*image; - bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader); - bmch->bcSize = sizeof(BITMAPCOREHEADER); - - if(!hdc){ - HBITMAP old; - hdc = CreateCompatibleDC(0); - old = SelectObject(hdc, hbm); - GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS); - SelectObject(hdc, old); - DeleteDC(hdc); - } - else - GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS); - - switch(bmch->bcBitCount) + if (status == Ok && bitmap->format == PixelFormat32bppARGB) { - case 1: - (*((GpBitmap**) image))->format = PixelFormat1bppIndexed; - break; - case 4: - (*((GpBitmap**) image))->format = PixelFormat4bppIndexed; - break; - case 8: - (*((GpBitmap**) image))->format = PixelFormat8bppIndexed; - break; - case 16: - (*((GpBitmap**) image))->format = PixelFormat16bppRGB565; - break; - case 24: - (*((GpBitmap**) image))->format = PixelFormat24bppRGB; - break; - case 32: - (*((GpBitmap**) image))->format = PixelFormat32bppRGB; - break; - case 48: - (*((GpBitmap**) image))->format = PixelFormat48bppRGB; - break; - default: - FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount); - (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI; - break; + /* WIC supports bmp files with alpha, but gdiplus does not */ + bitmap->format = PixelFormat32bppRGB; } - GdipFree(pbmi); + return status; +} - (*image)->picture = pic; - (*image)->flags = ImageFlagsNone; +static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image) +{ + return decode_image_wic(stream, &CLSID_WICJpegDecoder, image); +} - return Ok; +static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image) +{ + return decode_image_wic(stream, &CLSID_WICPngDecoder, image); +} + +static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image) +{ + return decode_image_wic(stream, &CLSID_WICGifDecoder, image); } static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image) @@ -1715,7 +1919,15 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image) if (FAILED(hr)) return hresult_to_status(hr); /* call on the image decoder to do the real work */ - return codec->decode_func(stream, &codec->info.Clsid, image); + stat = codec->decode_func(stream, &codec->info.Clsid, image); + + /* take note of the original data format */ + if (stat == Ok) + { + memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID)); + } + + return stat; } /* FIXME: no ICM */ @@ -1915,6 +2127,12 @@ static GpStatus encode_image_BMP(GpImage *image, IStream* stream, return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params); } +static GpStatus encode_image_png(GpImage *image, IStream* stream, + GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params) +{ + return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params); +} + /***************************************************************************** * GdipSaveImageToStream [GDIPLUS.@] */ @@ -2051,7 +2269,7 @@ static const struct image_codec codecs[NUM_CODECS] = { /* SigMask */ bmp_sig_mask, }, encode_image_BMP, - decode_image_olepicture_bitmap + decode_image_bmp }, { { /* JPEG */ @@ -2138,15 +2356,15 @@ static const struct image_codec codecs[NUM_CODECS] = { /* FormatDescription */ png_format, /* FilenameExtension */ png_extension, /* MimeType */ png_mimetype, - /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, + /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin, /* Version */ 1, /* SigCount */ 1, /* SigSize */ 8, /* SigPattern */ png_sig_pattern, /* SigMask */ png_sig_mask, }, - NULL, - decode_image_olepicture_bitmap + encode_image_png, + decode_image_png }, { { /* ICO */ -- 2.17.1