|
|
@@ -38,6 +38,7 @@ class GdiPlusImageCodec : public ImageCodec |
|
|
|
public: |
|
|
|
virtual bool Load(Image *image, char const *path); |
|
|
|
virtual bool Save(Image *image, char const *path); |
|
|
|
virtual bool Save(array<Image *> const &images, char const *path); |
|
|
|
}; |
|
|
|
|
|
|
|
DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) |
|
|
@@ -54,9 +55,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) |
|
|
|
status = Gdiplus::GdiplusStartup(&token, &input, nullptr); |
|
|
|
if (status != Gdiplus::Ok) |
|
|
|
{ |
|
|
|
#if !LOL_BUILD_RELEASE |
|
|
|
Log::Error("error %d while initialising GDI+\n", status); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
@@ -69,9 +68,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) |
|
|
|
wchar_t *wpath = new wchar_t[len + 1]; |
|
|
|
if (mbstowcs(wpath, fullpath.C(), len + 1) == (size_t)-1) |
|
|
|
{ |
|
|
|
#if !LOL_BUILD_RELEASE |
|
|
|
Log::Error("invalid image name %s\n", fullpath.C()); |
|
|
|
#endif |
|
|
|
delete[] wpath; |
|
|
|
continue; |
|
|
|
} |
|
|
@@ -84,11 +81,9 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) |
|
|
|
status = bitmap->GetLastStatus(); |
|
|
|
if (status != Gdiplus::Ok) |
|
|
|
{ |
|
|
|
#if !LOL_BUILD_RELEASE |
|
|
|
if (status != Gdiplus::InvalidParameter) |
|
|
|
Log::Error("error %d loading %s\n", |
|
|
|
status, fullpath.C()); |
|
|
|
#endif |
|
|
|
delete bitmap; |
|
|
|
bitmap = nullptr; |
|
|
|
} |
|
|
@@ -101,9 +96,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) |
|
|
|
|
|
|
|
if (!bitmap) |
|
|
|
{ |
|
|
|
#if !LOL_BUILD_RELEASE |
|
|
|
Log::Error("could not load %s\n", path); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
@@ -113,9 +106,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) |
|
|
|
if (bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, |
|
|
|
PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) |
|
|
|
{ |
|
|
|
#if !LOL_BUILD_RELEASE |
|
|
|
Log::Error("could not lock bits in %s\n", path); |
|
|
|
#endif |
|
|
|
delete bitmap; |
|
|
|
return false; |
|
|
|
} |
|
|
@@ -187,12 +178,8 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) |
|
|
|
|
|
|
|
ivec2 size = image->GetSize(); |
|
|
|
|
|
|
|
/* FIXME: we create a new image because there is no guarantee that |
|
|
|
* the image comes from GDI. But the engine architecture doesn't |
|
|
|
* allow us to save other images anyway. */ |
|
|
|
Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, |
|
|
|
PixelFormat32bppARGB); |
|
|
|
|
|
|
|
Gdiplus::BitmapData bdata; |
|
|
|
Gdiplus::Rect rect(0, 0, size.x, size.y); |
|
|
|
|
|
|
@@ -230,6 +217,116 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
bool GdiPlusImageCodec::Save(array<Image *> const &images, char const *path) |
|
|
|
{ |
|
|
|
ULONG_PTR token; |
|
|
|
Gdiplus::GdiplusStartupInput input; |
|
|
|
Gdiplus::GdiplusStartup(&token, &input, nullptr); |
|
|
|
|
|
|
|
wchar_t const *fmt = L"image/gif"; |
|
|
|
|
|
|
|
unsigned int num = 0, encoder_size = 0; |
|
|
|
Gdiplus::GetImageEncodersSize(&num, &encoder_size); |
|
|
|
if (num == 0) |
|
|
|
{ |
|
|
|
Log::Error("no GDI+ image encoders found\n"); |
|
|
|
return false; |
|
|
|
} |
|
|
|
Gdiplus::ImageCodecInfo *codecs |
|
|
|
= (Gdiplus::ImageCodecInfo *)new uint8_t[encoder_size]; |
|
|
|
Gdiplus::GetImageEncoders(num, encoder_size, codecs); |
|
|
|
CLSID clsid; |
|
|
|
for (unsigned int i = 0; i < num; i++) |
|
|
|
{ |
|
|
|
if (wcscmp(codecs[i].MimeType, fmt) == 0) |
|
|
|
{ |
|
|
|
clsid = codecs[i].Clsid; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// FIXME: clsid can be uninitialised |
|
|
|
|
|
|
|
size_t len; |
|
|
|
len = mbstowcs(nullptr, path, 0); |
|
|
|
wchar_t *wpath = new wchar_t[len + 1]; |
|
|
|
if (mbstowcs(wpath, path, len + 1) == (size_t)-1) |
|
|
|
{ |
|
|
|
Log::Error("could not convert GDI+ filename '%s' to widechar\n", path); |
|
|
|
delete[] wpath; |
|
|
|
delete[] codecs; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
Gdiplus::Image *root_image = nullptr; |
|
|
|
|
|
|
|
#if 0 |
|
|
|
Gdiplus::Bitmap *tmp = new Gdiplus::Bitmap(1, 1, PixelFormat32bppARGB); |
|
|
|
unsigned int param_count = tmp->GetEncoderParameterListSize(&clsid); |
|
|
|
printf("%d parameters\n", param_count); |
|
|
|
delete tmp; |
|
|
|
#endif |
|
|
|
|
|
|
|
for (int i = 0; i < images.Count(); ++i) |
|
|
|
{ |
|
|
|
ivec2 size = images[i]->GetSize(); |
|
|
|
|
|
|
|
Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, |
|
|
|
PixelFormat32bppARGB); |
|
|
|
Gdiplus::BitmapData bdata; |
|
|
|
Gdiplus::Rect rect(0, 0, size.x, size.y); |
|
|
|
|
|
|
|
if (b->LockBits(&rect, (unsigned int)Gdiplus::ImageLockModeWrite, |
|
|
|
PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) |
|
|
|
{ |
|
|
|
Log::Error("could not lock GDI+ image bits\n"); |
|
|
|
delete b; |
|
|
|
delete[] wpath; |
|
|
|
delete[] codecs; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
u8vec4 *psrc = images[i]->Lock<PixelFormat::RGBA_8>(); |
|
|
|
u8vec4 *psrc0 = psrc; |
|
|
|
u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0); |
|
|
|
for (int y = 0; y < size.y; y++) |
|
|
|
for (int x = 0; x < size.x; x++) |
|
|
|
*pdst++ = (*psrc++).bgra; |
|
|
|
images[i]->Unlock(psrc0); |
|
|
|
b->UnlockBits(&bdata); |
|
|
|
|
|
|
|
Gdiplus::Status ret; |
|
|
|
if (i == 0) |
|
|
|
{ |
|
|
|
root_image = b; |
|
|
|
b = nullptr; |
|
|
|
ret = root_image->Save(wpath, &clsid, nullptr); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
ret = root_image->SaveAdd(b, nullptr); |
|
|
|
} |
|
|
|
|
|
|
|
if (ret != Gdiplus::Ok) |
|
|
|
{ |
|
|
|
Log::Error("could not save GDI+ image '%s'\n", path); |
|
|
|
delete[] wpath; |
|
|
|
delete[] codecs; |
|
|
|
delete root_image; |
|
|
|
delete b; |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
delete b; |
|
|
|
} |
|
|
|
|
|
|
|
delete[] wpath; |
|
|
|
delete[] codecs; |
|
|
|
delete root_image; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
} /* namespace lol */ |
|
|
|
|
|
|
|
#endif /* defined USE_GDIPLUS */ |
|
|
|