git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@3070 92316355-f0b4-4df1-b90c-862c8a59935fremotes/tiles
@@ -50,6 +50,10 @@ pipi_image_t *pipi_load(char const *name) | |||||
if(!ret) | if(!ret) | ||||
ret = pipi_load_sdl(name); | ret = pipi_load_sdl(name); | ||||
#endif | #endif | ||||
#if USE_GDIPLUS | |||||
if(!ret) | |||||
ret = pipi_load_gdiplus(name); | |||||
#endif | |||||
#if USE_GDI | #if USE_GDI | ||||
if(!ret) | if(!ret) | ||||
ret = pipi_load_gdi(name); | ret = pipi_load_gdi(name); | ||||
@@ -94,14 +98,14 @@ int pipi_save(pipi_image_t *img, const char *name) | |||||
if(ret < 0) | if(ret < 0) | ||||
ret = pipi_save_sdl(img, name); | ret = pipi_save_sdl(img, name); | ||||
#endif | #endif | ||||
#if USE_GDI | |||||
if(ret < 0) | |||||
ret = pipi_save_gdi(img, name); | |||||
#endif | |||||
#if USE_GDIPLUS | #if USE_GDIPLUS | ||||
if(ret < 0) | if(ret < 0) | ||||
ret = pipi_save_gdiplus(img, name); | ret = pipi_save_gdiplus(img, name); | ||||
#endif | #endif | ||||
#if USE_GDI | |||||
if(ret < 0) | |||||
ret = pipi_save_gdi(img, name); | |||||
#endif | |||||
#if USE_COCOA | #if USE_COCOA | ||||
if(ret < 0) | if(ret < 0) | ||||
ret = pipi_save_coreimage(img, name); | ret = pipi_save_coreimage(img, name); | ||||
@@ -23,117 +23,131 @@ | |||||
#include <string.h> | #include <string.h> | ||||
#include <windows.h> | #include <windows.h> | ||||
#include <gdiplus.h> | |||||
#include "pipi.h" | #include "pipi.h" | ||||
#include "pipi_internals.h" | #include "pipi_internals.h" | ||||
extern "C" pipi_image_t *pipi_load_gdiplus(const char *name) | 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; | 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; | 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; | 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->codec_priv = NULL; | ||||
img->wrap = 0; | img->wrap = 0; | ||||
img->u8 = 1; | img->u8 = 1; | ||||
ReleaseDC(0, hdc); | |||||
DeleteObject(hbmap); | |||||
return img; | return img; | ||||
} | } | ||||
extern "C" int pipi_save_gdiplus(pipi_image_t *img, const char *name) | 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; | 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; | return 0; | ||||
} | } | ||||
@@ -1,7 +1,7 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<VisualStudioProject | <VisualStudioProject | ||||
ProjectType="Visual C++" | ProjectType="Visual C++" | ||||
Version="8.00" | |||||
Version="8,00" | |||||
Name="libpipi" | Name="libpipi" | ||||
ProjectGUID="{48A34C3A-1E36-49B7-92C4-E982FDCB90C0}" | ProjectGUID="{48A34C3A-1E36-49B7-92C4-E982FDCB90C0}" | ||||
RootNamespace="libpipi" | RootNamespace="libpipi" | ||||
@@ -60,6 +60,7 @@ | |||||
/> | /> | ||||
<Tool | <Tool | ||||
Name="VCLinkerTool" | Name="VCLinkerTool" | ||||
AdditionalDependencies="gdiplus.lib" | |||||
OutputFile="$(OutDir)\$(ProjectName)-0.dll" | OutputFile="$(OutDir)\$(ProjectName)-0.dll" | ||||
LinkIncremental="2" | LinkIncremental="2" | ||||
GenerateDebugInformation="true" | GenerateDebugInformation="true" | ||||
@@ -133,6 +134,7 @@ | |||||
/> | /> | ||||
<Tool | <Tool | ||||
Name="VCLinkerTool" | Name="VCLinkerTool" | ||||
AdditionalDependencies="gdiplus.lib" | |||||
OutputFile="$(OutDir)\$(ProjectName)-0.dll" | OutputFile="$(OutDir)\$(ProjectName)-0.dll" | ||||
LinkIncremental="2" | LinkIncremental="2" | ||||
GenerateDebugInformation="true" | GenerateDebugInformation="true" | ||||
@@ -215,26 +217,10 @@ | |||||
RelativePath=".\accessors.c" | RelativePath=".\accessors.c" | ||||
> | > | ||||
</File> | </File> | ||||
<File | |||||
RelativePath=".\filter\autocontrast.c" | |||||
> | |||||
</File> | |||||
<File | |||||
RelativePath=".\paint\bezier.c" | |||||
> | |||||
</File> | |||||
<File | |||||
RelativePath=".\filter\blur.c" | |||||
> | |||||
</File> | |||||
<File | <File | ||||
RelativePath=".\codec.c" | RelativePath=".\codec.c" | ||||
> | > | ||||
</File> | </File> | ||||
<File | |||||
RelativePath=".\filter\color.c" | |||||
> | |||||
</File> | |||||
<File | <File | ||||
RelativePath=".\colorstring.c" | RelativePath=".\colorstring.c" | ||||
> | > | ||||
@@ -243,82 +229,14 @@ | |||||
RelativePath=".\context.c" | RelativePath=".\context.c" | ||||
> | > | ||||
</File> | </File> | ||||
<File | |||||
RelativePath=".\filter\convolution.c" | |||||
> | |||||
</File> | |||||
<File | |||||
RelativePath=".\dither\dbs.c" | |||||
> | |||||
</File> | |||||
<File | |||||
RelativePath=".\filter\dilate.c" | |||||
> | |||||
</File> | |||||
<File | <File | ||||
RelativePath=".\dither.c" | RelativePath=".\dither.c" | ||||
> | > | ||||
</File> | </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 | <File | ||||
RelativePath=".\measure.c" | RelativePath=".\measure.c" | ||||
> | > | ||||
</File> | </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 | <File | ||||
RelativePath=".\pipi.c" | RelativePath=".\pipi.c" | ||||
> | > | ||||
@@ -327,10 +245,6 @@ | |||||
RelativePath=".\pixels.c" | RelativePath=".\pixels.c" | ||||
> | > | ||||
</File> | </File> | ||||
<File | |||||
RelativePath=".\dither\random.c" | |||||
> | |||||
</File> | |||||
<File | <File | ||||
RelativePath=".\quantize\reduce.c" | RelativePath=".\quantize\reduce.c" | ||||
> | > | ||||
@@ -339,30 +253,146 @@ | |||||
RelativePath=".\resize.c" | RelativePath=".\resize.c" | ||||
> | > | ||||
</File> | </File> | ||||
<File | |||||
RelativePath=".\combine\rgb.c" | |||||
> | |||||
</File> | |||||
<File | |||||
RelativePath=".\render\screen.c" | |||||
> | |||||
</File> | |||||
<File | <File | ||||
RelativePath=".\stock.c" | RelativePath=".\stock.c" | ||||
> | > | ||||
</File> | </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> | </Filter> | ||||
</Files> | </Files> | ||||
<Globals> | <Globals> | ||||