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 #include +#include #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 @@  - - - - - - - - @@ -243,82 +229,14 @@ RelativePath=".\context.c" > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -327,10 +245,6 @@ RelativePath=".\pixels.c" > - - @@ -339,30 +253,146 @@ RelativePath=".\resize.c" > - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +