Browse Source

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
remotes/tiles
sam 16 years ago
parent
commit
b186af90bf
3 changed files with 238 additions and 190 deletions
  1. +8
    -4
      pipi/codec.c
  2. +91
    -77
      pipi/codec/gdiplus.cpp
  3. +139
    -109
      pipi/libpipi.vcproj

+ 8
- 4
pipi/codec.c View File

@@ -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);


+ 91
- 77
pipi/codec/gdiplus.cpp View File

@@ -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;
}


+ 139
- 109
pipi/libpipi.vcproj View File

@@ -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>


Loading…
Cancel
Save