From 9f10fdd2b9e52ba6db292b68fffb162cbaf0381a Mon Sep 17 00:00:00 2001 From: sam Date: Sun, 28 Sep 2008 05:08:11 +0000 Subject: [PATCH] gdi.c: the GDI codec can now open and save BMP files. git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2840 92316355-f0b4-4df1-b90c-862c8a59935f --- pipi/Makefile.am | 1 + pipi/codec.c | 8 +++ pipi/codec/gdi.c | 153 ++++++++++++++++++++++++++++++++++++++++++ pipi/pipi_internals.h | 5 ++ 4 files changed, 167 insertions(+) diff --git a/pipi/Makefile.am b/pipi/Makefile.am index 3c58575..9043d77 100644 --- a/pipi/Makefile.am +++ b/pipi/Makefile.am @@ -103,6 +103,7 @@ codec_sources += codec/opencv.c endif if USE_GDI +codec_libs += -lgdi32 codec_sources += codec/gdi.c endif diff --git a/pipi/codec.c b/pipi/codec.c index 81e6570..b08e73a 100644 --- a/pipi/codec.c +++ b/pipi/codec.c @@ -48,6 +48,10 @@ pipi_image_t *pipi_load(char const *name) if(!ret) ret = pipi_load_sdl(name); #endif +#if USE_GDI + if(!ret) + ret = pipi_load_gdi(name); +#endif return ret; } @@ -82,6 +86,10 @@ 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 return ret; } diff --git a/pipi/codec/gdi.c b/pipi/codec/gdi.c index e69de29..ad1ad7b 100644 --- a/pipi/codec/gdi.c +++ b/pipi/codec/gdi.c @@ -0,0 +1,153 @@ +/* + * libpipi Proper image processing implementation library + * Copyright (c) 2004-2008 Sam Hocevar + * All Rights Reserved + * + * $Id$ + * + * This library is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. + */ + +/* + * gdi.c: Windows GDI I/O functions (BMP only) + */ + +#include "config.h" +#include "common.h" + +#include +#include +#include + +#include + +#include "pipi.h" +#include "pipi_internals.h" + +pipi_image_t *pipi_load_gdi(const char *name) +{ + BITMAPINFO binfo; + pipi_image_t *img; + pipi_pixels_t *p; + uint8_t *data; + HBITMAP hbmap; + HDC hdc; + int x, y; + + hbmap = (HBITMAP)LoadImage(NULL, name, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + if(!hbmap) + return NULL; + + hdc = CreateCompatibleDC(NULL); + SelectObject(hdc, hbmap); + + memset(&binfo, 0, sizeof(binfo)); + binfo.bmiHeader.biSize = sizeof(binfo.bmiHeader); + if(!GetDIBits(hdc, hbmap, 0, 0, 0, &binfo, DIB_RGB_COLORS)) + { + ReleaseDC(0, hdc); + DeleteObject(hbmap); + return NULL; + } + + img = pipi_new(binfo.bmiHeader.biWidth, binfo.bmiHeader.biHeight); + p = pipi_getpixels(img, PIPI_PIXELS_RGBA_C); + data = p->pixels; + + binfo.bmiHeader.biBitCount = 32; + binfo.bmiHeader.biCompression = BI_RGB; + binfo.bmiHeader.biHeight = - abs(binfo.bmiHeader.biHeight); + if(!GetDIBits(hdc, hbmap, 0, binfo.bmiHeader.biHeight, data, + &binfo, DIB_RGB_COLORS)) + { + ReleaseDC(0, hdc); + DeleteObject(hbmap); + return NULL; + } + + /* FIXME: get rid of this loop, maybe by using BITMAPV4HEADER above + * so that GDI reorders the pixels for us. */ + for(y = 0; y < img->h; y++) + for(x = 0; x < img->w; x++) + { + /* Swap B and R, don't touch G and A. */ + uint8_t tmp = data[0]; data[0] = data[2]; data[2] = tmp; + data += 4; + } + + img->codec_priv = NULL; + + img->wrap = 0; + img->u8 = 1; + + ReleaseDC(0, hdc); + DeleteObject(hbmap); + + return img; +} + +int pipi_save_gdi(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 = 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) + return -1; + WriteFile(hfile, &bfheader, sizeof(bfheader), &ret, NULL); + WriteFile(hfile, &binfo, sizeof(binfo), &ret, NULL); + for(y = 0; y < img->h; y++) + { + for(x = 0; x < img->w; x++) + { + uint8_t tmp[3]; + tmp[0] = data[4 * (img->w * (img->h - 1 - y) + x) + 2]; + tmp[1] = data[4 * (img->w * (img->h - 1 - y) + x) + 1]; + tmp[2] = data[4 * (img->w * (img->h - 1 - y) + x) + 0]; + WriteFile(hfile, tmp, 3, &ret, NULL); + } + if(padding) + WriteFile(hfile, dummy, padding, &ret, NULL); + } + CloseHandle(hfile); + + return 0; +} + +/* + * XXX: The following functions are local. + */ + diff --git a/pipi/pipi_internals.h b/pipi/pipi_internals.h index ec15e21..b36a845 100644 --- a/pipi/pipi_internals.h +++ b/pipi/pipi_internals.h @@ -80,5 +80,10 @@ pipi_image_t *pipi_load_sdl(const char *name); int pipi_save_sdl(pipi_image_t *img, const char *name); #endif +#ifdef USE_GDI +pipi_image_t *pipi_load_gdi(const char *name); +int pipi_save_gdi(pipi_image_t *img, const char *name); +#endif + #endif /* __PIPI_INTERNALS_H__ */