From b186af90bf1c852065aeb703839cbba25423d8b0 Mon Sep 17 00:00:00 2001
From: sam <sam@92316355-f0b4-4df1-b90c-862c8a59935f>
Date: Wed, 22 Oct 2008 23:56:48 +0000
Subject: [PATCH] Full GDI+ load and save support.

git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@3070 92316355-f0b4-4df1-b90c-862c8a59935f
---
 pipi/codec.c           |  12 +-
 pipi/codec/gdiplus.cpp | 168 +++++++++++++++-------------
 pipi/libpipi.vcproj    | 248 +++++++++++++++++++++++------------------
 3 files changed, 238 insertions(+), 190 deletions(-)

diff --git a/pipi/codec.c b/pipi/codec.c
index 0d18eed..8e44618 100644
--- a/pipi/codec.c
+++ b/pipi/codec.c
@@ -50,6 +50,10 @@ pipi_image_t *pipi_load(char const *name)
     if(!ret)
         ret = pipi_load_sdl(name);
 #endif
+#if USE_GDIPLUS
+    if(!ret)
+        ret = pipi_load_gdiplus(name);
+#endif
 #if USE_GDI
     if(!ret)
         ret = pipi_load_gdi(name);
@@ -94,14 +98,14 @@ int pipi_save(pipi_image_t *img, const char *name)
     if(ret < 0)
         ret = pipi_save_sdl(img, name);
 #endif
-#if USE_GDI
-    if(ret < 0)
-        ret = pipi_save_gdi(img, name);
-#endif
 #if USE_GDIPLUS
     if(ret < 0)
         ret = pipi_save_gdiplus(img, name);
 #endif
+#if USE_GDI
+    if(ret < 0)
+        ret = pipi_save_gdi(img, name);
+#endif
 #if USE_COCOA
     if(ret < 0)
         ret = pipi_save_coreimage(img, name);
diff --git a/pipi/codec/gdiplus.cpp b/pipi/codec/gdiplus.cpp
index 2f80568..ad6fc37 100755
--- a/pipi/codec/gdiplus.cpp
+++ b/pipi/codec/gdiplus.cpp
@@ -23,117 +23,131 @@
 #include <string.h>
 
 #include <windows.h>
+#include <gdiplus.h>
 
 #include "pipi.h"
 #include "pipi_internals.h"
 
 extern "C" pipi_image_t *pipi_load_gdiplus(const char *name)
 {
-    BITMAPINFO binfo;
-    pipi_image_t *img;
-    pipi_pixels_t *p;
-    uint8_t *data;
-    HBITMAP hbmap;
-    HDC hdc;
-
-    hbmap = (HBITMAP)LoadImage(NULL, name, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
-    if(!hbmap)
+    size_t len;
+    if(mbstowcs_s(&len, NULL, 0, name, _TRUNCATE) != 0)
         return NULL;
+    wchar_t *wname = new wchar_t[len];
+    if(mbstowcs_s(NULL, wname, len, name, _TRUNCATE) != 0)
+    {
+        delete[] wname;
+        return NULL;
+    }
 
-    hdc = CreateCompatibleDC(NULL);
-    SelectObject(hdc, hbmap);
+    ULONG_PTR token;
+    Gdiplus::GdiplusStartupInput input;
+    Gdiplus::GdiplusStartup(&token, &input, NULL);
 
-    memset(&binfo, 0, sizeof(binfo));
-    binfo.bmiHeader.biSize = sizeof(binfo.bmiHeader);
-    if(!GetDIBits(hdc, hbmap, 0, 0, 0, &binfo, DIB_RGB_COLORS))
+    Gdiplus::Bitmap *b = Gdiplus::Bitmap::FromFile(wname, 0);
+    if(!b)
     {
-        ReleaseDC(0, hdc);
-        DeleteObject(hbmap);
+        delete[] wname;
         return NULL;
     }
+    delete[] wname;
 
-    img = pipi_new(binfo.bmiHeader.biWidth, binfo.bmiHeader.biHeight);
-    p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C);
-    data = (uint8_t *)p->pixels;
+    Gdiplus::BitmapData bdata;
+    Gdiplus::Rect rect(0, 0, b->GetWidth(), b->GetHeight());
 
-    binfo.bmiHeader.biBitCount = 32;
-    binfo.bmiHeader.biCompression = BI_RGB;
-    binfo.bmiHeader.biHeight = - abs(binfo.bmiHeader.biHeight);
-    if(!GetDIBits(hdc, hbmap, 0, abs(binfo.bmiHeader.biHeight), data,
-                  &binfo, DIB_RGB_COLORS))
+    if(b->LockBits(&rect, Gdiplus::ImageLockModeRead,
+                   PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
     {
-        ReleaseDC(0, hdc);
-        DeleteObject(hbmap);
+        delete b;
         return NULL;
     }
 
-    /* FIXME: do we need to swap bytes? Apparently Vista doesn't need it,
-     * but we'd need a more thorough test. */
+    pipi_image_t *img = pipi_new(b->GetWidth(), b->GetHeight());
+    pipi_pixels_t *p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C);
+    memcpy(p->pixels, bdata.Scan0, bdata.Width * bdata.Height * 4);
+
+    b->UnlockBits(&bdata);
+    delete b;
 
     img->codec_priv = NULL;
 
     img->wrap = 0;
     img->u8 = 1;
 
-    ReleaseDC(0, hdc);
-    DeleteObject(hbmap);
-
     return img;
 }
 
 extern "C" int pipi_save_gdiplus(pipi_image_t *img, const char *name)
 {
-    BITMAPINFOHEADER binfo;
-    BITMAPFILEHEADER bfheader;
-    uint8_t dummy[4] = { 0 };
-    HANDLE hfile;
-    pipi_pixels_t *p;
-    DWORD ret = 0;
-    uint8_t *data;
-    int x, y, padding;
-
-    p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C);
-    data = (uint8_t *)p->pixels;
-
-    padding = ((img->w * 3) + 3) / 4 * 4 - img->w * 3;
-
-    memset(&binfo, 0, sizeof(binfo));
-    binfo.biSize = sizeof(binfo);
-    binfo.biWidth = img->w;
-    binfo.biHeight = img->h;
-    binfo.biPlanes = 1;
-    binfo.biBitCount = 24;
-    binfo.biCompression = BI_RGB;
-    binfo.biSizeImage = (img->w * 3 + padding) * img->h;
-
-    memset(&bfheader, 0, sizeof(bfheader));
-    bfheader.bfType = 0x4D42;
-    bfheader.bfOffBits = sizeof(bfheader) + sizeof(binfo);
-    bfheader.bfSize = bfheader.bfOffBits + binfo.biSizeImage;
-
-    /* We don’t even create the bitmap object, since we know exactly
-     * what kind of file we are saving. But later, when we support
-     * different depths and BMP options, we'll need to care about it. */
-    hfile = CreateFile(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
-                       FILE_ATTRIBUTE_ARCHIVE, NULL);
-    if(!hfile)
+    wchar_t const *fmt;
+    if(strstr(name, ".gif"))
+        fmt = L"image/gif";
+    else if(strstr(name, ".jpeg") || strstr(name, ".jpeg"))
+        fmt = L"image/jpeg";
+    else if(strstr(name, ".png"))
+        fmt = L"image/png";
+    else if(strstr(name, ".tiff"))
+        fmt = L"image/tiff";
+
+    unsigned int num = 0, size = 0;
+    Gdiplus::GetImageEncodersSize(&num, &size);
+    if(size == 0)
+        return -1;
+    Gdiplus::ImageCodecInfo *codecs
+        = (Gdiplus::ImageCodecInfo *)(malloc(size));
+    if(!codecs)
         return -1;
-    WriteFile(hfile, &bfheader, sizeof(bfheader), &ret, NULL);
-    WriteFile(hfile, &binfo, sizeof(binfo), &ret, NULL);
-    for(y = 0; y < img->h; y++)
+    Gdiplus::GetImageEncoders(num, size, codecs);
+    CLSID clsid;
+    for(unsigned int i = 0; i < num; i++)
     {
-        for(x = 0; x < img->w; x++)
+        if(wcscmp(codecs[i].MimeType, fmt) == 0)
         {
-            uint8_t tmp[3];
-            tmp[0] = data[4 * (img->w * (img->h - 1 - y) + x) + 0];
-            tmp[1] = data[4 * (img->w * (img->h - 1 - y) + x) + 1];
-            tmp[2] = data[4 * (img->w * (img->h - 1 - y) + x) + 2];
-            WriteFile(hfile, tmp, 3, &ret, NULL);
+            clsid = codecs[i].Clsid;
+            break;
         }
-        if(padding)
-            WriteFile(hfile, dummy, padding, &ret, NULL);
     }
-    CloseHandle(hfile);
+
+    size_t len;
+    if(mbstowcs_s(&len, NULL, 0, name, _TRUNCATE) != 0)
+        return NULL;
+    wchar_t *wname = new wchar_t[len];
+    if(mbstowcs_s(NULL, wname, len, name, _TRUNCATE) != 0)
+    {
+        delete[] wname;
+        return -1;
+    }
+
+    ULONG_PTR token;
+    Gdiplus::GdiplusStartupInput input;
+    Gdiplus::GdiplusStartup(&token, &input, NULL);
+
+    Gdiplus::Bitmap *b = new Gdiplus::Bitmap(img->w, img->h,
+                                             PixelFormat32bppARGB);
+
+    Gdiplus::BitmapData bdata;
+    Gdiplus::Rect rect(0, 0, img->w, img->h);
+
+    if(b->LockBits(&rect, Gdiplus::ImageLockModeWrite,
+                   PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
+    {
+        delete b;
+        return -1;
+    }
+
+    pipi_pixels_t *p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C);
+    memcpy(bdata.Scan0, p->pixels, bdata.Width * bdata.Height * 4);
+
+    b->UnlockBits(&bdata);
+
+    if(b->Save(wname, &clsid, NULL) != Gdiplus::Ok)
+    {
+        delete[] wname;
+        delete b;
+        return -1;
+    }
+    delete[] wname;
+    delete b;
 
     return 0;
 }
diff --git a/pipi/libpipi.vcproj b/pipi/libpipi.vcproj
index 8f9665f..c79d853 100644
--- a/pipi/libpipi.vcproj
+++ b/pipi/libpipi.vcproj
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="8.00"
+	Version="8,00"
 	Name="libpipi"
 	ProjectGUID="{48A34C3A-1E36-49B7-92C4-E982FDCB90C0}"
 	RootNamespace="libpipi"
@@ -60,6 +60,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
+				AdditionalDependencies="gdiplus.lib"
 				OutputFile="$(OutDir)\$(ProjectName)-0.dll"
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
@@ -133,6 +134,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
+				AdditionalDependencies="gdiplus.lib"
 				OutputFile="$(OutDir)\$(ProjectName)-0.dll"
 				LinkIncremental="2"
 				GenerateDebugInformation="true"
@@ -215,26 +217,10 @@
 				RelativePath=".\accessors.c"
 				>
 			</File>
-			<File
-				RelativePath=".\filter\autocontrast.c"
-				>
-			</File>
-			<File
-				RelativePath=".\paint\bezier.c"
-				>
-			</File>
-			<File
-				RelativePath=".\filter\blur.c"
-				>
-			</File>
 			<File
 				RelativePath=".\codec.c"
 				>
 			</File>
-			<File
-				RelativePath=".\filter\color.c"
-				>
-			</File>
 			<File
 				RelativePath=".\colorstring.c"
 				>
@@ -243,82 +229,14 @@
 				RelativePath=".\context.c"
 				>
 			</File>
-			<File
-				RelativePath=".\filter\convolution.c"
-				>
-			</File>
-			<File
-				RelativePath=".\dither\dbs.c"
-				>
-			</File>
-			<File
-				RelativePath=".\filter\dilate.c"
-				>
-			</File>
 			<File
 				RelativePath=".\dither.c"
 				>
 			</File>
-			<File
-				RelativePath=".\dither\ediff.c"
-				>
-			</File>
-			<File
-				RelativePath=".\paint\floodfill.c"
-				>
-			</File>
-			<File
-				RelativePath=".\codec\gdi.c"
-				>
-			</File>
-			<File
-				RelativePath=".\codec\gdiplus.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\histogram\histogram.c"
-				>
-			</File>
-			<File
-				RelativePath=".\paint\line.c"
-				>
-			</File>
-			<File
-				RelativePath=".\combine\mean.c"
-				>
-			</File>
 			<File
 				RelativePath=".\measure.c"
 				>
 			</File>
-			<File
-				RelativePath=".\filter\median.c"
-				>
-			</File>
-			<File
-				RelativePath=".\combine\minmax.c"
-				>
-			</File>
-			<File
-				RelativePath=".\combine\mulscreen.c"
-				>
-			</File>
-			<File
-				RelativePath=".\render\noise.c"
-				>
-			</File>
-			<File
-				RelativePath=".\dither\ordered.c"
-				>
-			</File>
-			<File
-				RelativePath=".\codec\oric.c"
-				>
-			</File>
-			<File
-				RelativePath=".\dither\ostromoukhov.c"
-				>
-			</File>
 			<File
 				RelativePath=".\pipi.c"
 				>
@@ -327,10 +245,6 @@
 				RelativePath=".\pixels.c"
 				>
 			</File>
-			<File
-				RelativePath=".\dither\random.c"
-				>
-			</File>
 			<File
 				RelativePath=".\quantize\reduce.c"
 				>
@@ -339,30 +253,146 @@
 				RelativePath=".\resize.c"
 				>
 			</File>
-			<File
-				RelativePath=".\combine\rgb.c"
-				>
-			</File>
-			<File
-				RelativePath=".\render\screen.c"
-				>
-			</File>
 			<File
 				RelativePath=".\stock.c"
 				>
 			</File>
-			<File
-				RelativePath=".\combine\subadd.c"
-				>
-			</File>
-			<File
-				RelativePath=".\paint\tile.c"
-				>
-			</File>
-			<File
-				RelativePath=".\filter\transform.c"
-				>
-			</File>
+			<Filter
+				Name="codec"
+				>
+				<File
+					RelativePath=".\codec\gdi.c"
+					>
+				</File>
+				<File
+					RelativePath=".\codec\gdiplus.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\codec\oric.c"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="combine"
+				>
+				<File
+					RelativePath=".\combine\mean.c"
+					>
+				</File>
+				<File
+					RelativePath=".\combine\minmax.c"
+					>
+				</File>
+				<File
+					RelativePath=".\combine\mulscreen.c"
+					>
+				</File>
+				<File
+					RelativePath=".\combine\rgb.c"
+					>
+				</File>
+				<File
+					RelativePath=".\combine\subadd.c"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="dither"
+				>
+				<File
+					RelativePath=".\dither\dbs.c"
+					>
+				</File>
+				<File
+					RelativePath=".\dither\ediff.c"
+					>
+				</File>
+				<File
+					RelativePath=".\dither\ordered.c"
+					>
+				</File>
+				<File
+					RelativePath=".\dither\ostromoukhov.c"
+					>
+				</File>
+				<File
+					RelativePath=".\dither\random.c"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="filter"
+				>
+				<File
+					RelativePath=".\filter\autocontrast.c"
+					>
+				</File>
+				<File
+					RelativePath=".\filter\blur.c"
+					>
+				</File>
+				<File
+					RelativePath=".\filter\color.c"
+					>
+				</File>
+				<File
+					RelativePath=".\filter\convolution.c"
+					>
+				</File>
+				<File
+					RelativePath=".\filter\dilate.c"
+					>
+				</File>
+				<File
+					RelativePath=".\filter\median.c"
+					>
+				</File>
+				<File
+					RelativePath=".\filter\transform.c"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="histogram"
+				>
+				<File
+					RelativePath=".\histogram\histogram.c"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="paint"
+				>
+				<File
+					RelativePath=".\paint\bezier.c"
+					>
+				</File>
+				<File
+					RelativePath=".\paint\floodfill.c"
+					>
+				</File>
+				<File
+					RelativePath=".\paint\line.c"
+					>
+				</File>
+				<File
+					RelativePath=".\paint\tile.c"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="render"
+				>
+				<File
+					RelativePath=".\render\noise.c"
+					>
+				</File>
+				<File
+					RelativePath=".\render\screen.c"
+					>
+				</File>
+			</Filter>
 		</Filter>
 	</Files>
 	<Globals>