| /* |
| * GraphApp - Cross-Platform Graphics Programming Library. |
| * |
| * File: bitmaps.c -- functions for creating a detroying bitmaps. |
| * Platform: Windows Version: 2.40 Date: 1998/05/05 |
| * |
| * Version: 1.00 Changes: Original version by Lachlan Patrick. |
| * Version: 2.00 Changes: New object class system implemented. |
| * Version: 2.15 Changes: Improved bitmap data formats. |
| * Version: 2.30 Changes: Now uses bitmap_base. |
| * Version: 2.40 Changes: Fast image to bitmap conversion. |
| */ |
| |
| /* Copyright (C) 1993-1998 Lachlan Patrick |
| |
| This file is part of GraphApp, a cross-platform C graphics library. |
| |
| GraphApp is free software; you can redistribute it and/or modify it |
| under the terms of the GNU Library General Public License. |
| GraphApp is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY. |
| |
| See the file COPYLIB.TXT for details. |
| */ |
| |
| #include "internal.h" |
| |
| /* |
| * Internal bitmap deletion function. |
| */ |
| static void private_delbitmap(bitmap obj) |
| { |
| if (obj->handle) |
| DeleteObject((HBITMAP) obj->handle); |
| } |
| |
| /* |
| * Create/return the base bitmap object. |
| */ |
| static object get_bitmap_base(void) |
| { |
| static object bitmap_base = NULL; |
| |
| if (! bitmap_base) |
| bitmap_base = new_object(BaseObject, 0, NULL); |
| return bitmap_base; |
| } |
| |
| /* |
| * Create a white bitmap. |
| */ |
| bitmap newbitmap(int width, int height, int depth) |
| { |
| BITMAP bm; |
| HBITMAP hb, old; |
| HDC dc, screendc; |
| |
| screendc = GetDC(0); /* get screen dc */ |
| |
| if (depth == 1) /* monochrome bitmap required */ |
| { |
| hb = CreateBitmap(width, height, 1, 1, 0); |
| } |
| else /* colour bitmap required */ |
| { |
| hb = CreateCompatibleBitmap(screendc, width, height); |
| } |
| |
| if (! hb) { |
| ReleaseDC(0, screendc); |
| return NULL; |
| } |
| |
| dc = CreateCompatibleDC(screendc); |
| old = SelectObject(dc, hb); |
| PatBlt(dc, 0, 0, width, height, WHITENESS); |
| SelectObject(dc, old); |
| DeleteDC(dc); |
| |
| ReleaseDC(0, screendc); |
| |
| GetObject(hb, sizeof(BITMAP), (LPSTR) &bm); |
| |
| bitmap obj = new_object(BitmapObject, hb, get_bitmap_base()); |
| if (! obj) { |
| DeleteObject(hb); |
| return NULL; |
| } |
| obj->rect = rect(0,0,width,height); |
| obj->depth = (bm.bmPlanes * bm.bmBitsPixel); |
| obj->die = private_delbitmap; |
| |
| return obj; |
| } |
| |
| /* |
| * Check an image to see if there are any transparent pixels. |
| * Return 1 as soon as a transparent pixel is found, 0 if none are. |
| */ |
| PROTECTED |
| int has_transparent_pixels(image img) |
| { |
| int i, width, height, total; |
| rgb *palette; |
| GAbyte *pixel8; |
| rgb *pixel32; |
| rgb col; |
| |
| if (! img) |
| return 0; |
| |
| width = getwidth(img); |
| height = getheight(img); |
| total = width * height; |
| |
| palette = getpalette(img); |
| |
| pixel8 = getpixels(img); |
| pixel32 = (rgb *) pixel8; |
| |
| if (getdepth(img) == 8) { |
| for (i=0; i < total; i++) { |
| col = pixel8[i]; |
| col = palette[col]; |
| if (getalpha(col) > 0x7F) |
| return 1; |
| } |
| } |
| else { |
| for (i=0; i < total; i++) { |
| col = pixel32[i]; |
| if (getalpha(col) > 0x7F) |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Create a bitmap version of an image. |
| */ |
| // See also http://msdn.microsoft.com/en-us/library/dd183353%28v=VS.85%29.aspx |
| bitmap imagetobitmap(image img) |
| { |
| unsigned row_bytes; |
| unsigned size; |
| |
| if (!img) return NULL; |
| |
| /* remember some facts about the image */ |
| int width = getwidth(img), height = getheight(img); |
| int depth = getdepth(img); |
| rgb *palette = getpalette(img); |
| int palsize = getpalettesize(img); |
| GAbyte *pixel8 = getpixels(img); |
| rgb *pixel32 = (rgb *) pixel8; |
| |
| /* create DIB info in memory */ |
| size = sizeof(BITMAPINFOHEADER) + 4; /* Why + 4 ? */ |
| size += (sizeof(RGBQUAD) * palsize); |
| /* rows need to be whole (4-byte) words */ |
| if (depth == 8) row_bytes = ((width + 3) / 4) * 4; |
| else if (depth == 24) row_bytes = (((width * 3) + 3) / 4) * 4; |
| else row_bytes = 4 * width; |
| size += (row_bytes * height); |
| |
| /* create the block, align on LONG boundary |
| malloc will have done the alignment, which needs to |
| be for pointers. |
| */ |
| GAbyte *block = array(size, GAbyte); |
| BITMAPINFO *bmi = (BITMAPINFO *) block; |
| |
| |
| /* assign header info */ |
| bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
| bmi->bmiHeader.biWidth = width; |
| bmi->bmiHeader.biHeight = -height; // use negative value to flip |
| bmi->bmiHeader.biPlanes = 1; |
| bmi->bmiHeader.biBitCount = depth; |
| bmi->bmiHeader.biCompression = BI_RGB; |
| bmi->bmiHeader.biClrUsed = palsize; |
| |
| /* assign colour table */ |
| for (int i = 0; i < palsize; i++) { |
| rgb colour = palette[i]; |
| GAbyte *data = (GAbyte *) (& bmi->bmiColors[i]); |
| data[0] = getblue(colour); |
| data[1] = getgreen(colour); |
| data[2] = getred(colour); |
| data[3] = 0; |
| } |
| |
| /* assign the bitmap data itself */ |
| GAbyte *data = (GAbyte *) (&bmi->bmiColors[palsize]); |
| |
| if (depth == 8) |
| for (unsigned y = 0; y < height; y++) { |
| // memcpy(data + y * row_bytes, pixel8 + y * width, width); |
| for (unsigned x = 0; x < width; x++) |
| data[y * row_bytes + x] = pixel8[y * width + x]; |
| } |
| else if (depth == 24) |
| for (unsigned y = 0; y < height; y++) { |
| for (unsigned x = 0; x < width; x++) { |
| rgb colour = pixel32[y * width + x]; |
| int i = y * row_bytes + 3*x; |
| data[i] = getblue(colour); |
| data[i+1] = getgreen(colour); |
| data[i+2] = getred(colour); |
| } |
| } |
| else memcpy(data, pixel32, 4*height*width); |
| |
| /* Create the bitmap from the DIB data. |
| Could also use CreateDIBsection */ |
| |
| HDC screendc = GetDC(0); |
| HBITMAP hb = CreateDIBitmap(screendc, &bmi->bmiHeader, CBM_INIT, |
| data, bmi, DIB_RGB_COLORS); |
| ReleaseDC(0, screendc); |
| |
| /* tidy up */ |
| discard(block); |
| |
| /* create the bitmap */ |
| bitmap obj = new_object(BitmapObject, hb, get_bitmap_base()); |
| if (!obj) { |
| DeleteObject(hb); |
| return NULL; |
| } |
| obj->rect = rect(0, 0, width, height); |
| obj->depth = depth; |
| obj->die = private_delbitmap; |
| |
| return obj; |
| } |
| |
| #ifdef UNUSED |
| /* |
| * The loadicon function returns a HBITMAP of an ICON from resources. |
| */ |
| static bitmap loadicon(const char *name) |
| { |
| HICON i; |
| HDC dc; |
| HBITMAP old; |
| bitmap obj; |
| |
| if (this_instance == 0) |
| return NULL; |
| if ((i = LoadIcon(this_instance, name)) == 0) |
| return NULL; |
| if ((obj = newbitmap(32, 32, 0)) == NULL) |
| return NULL; |
| |
| dc = CreateCompatibleDC(0); |
| old = SelectObject(dc, (HBITMAP)obj->handle); |
| DrawIcon(dc, 0, 0, i); |
| SelectObject(dc, old); |
| DeleteDC(dc); |
| DestroyIcon(i); |
| |
| return obj; |
| } |
| |
| /* |
| * The loadpict function returns BITMAP resources. |
| */ |
| static bitmap loadpict(const char *name) |
| { |
| BITMAP bm; |
| HBITMAP hb; |
| bitmap obj; |
| |
| if (this_instance == 0) |
| return NULL; |
| hb = LoadBitmap(this_instance, name); |
| GetObject(hb, sizeof(BITMAP), (LPSTR) &bm); |
| |
| obj = new_object(BitmapObject, hb, get_bitmap_base()); |
| if (obj) { |
| obj->rect = rect(0, 0, bm.bmWidth, bm.bmHeight); |
| obj->depth = (bm.bmPlanes * bm.bmBitsPixel); |
| obj->die = private_delbitmap; |
| } |
| return obj; |
| } |
| |
| /* |
| * The loadbitmap function finds and returns bitmaps from resources, |
| * or from an image file. |
| */ |
| bitmap loadbitmap(const char *name) |
| { |
| bitmap obj; |
| |
| if ((obj = loadpict(name)) != NULL) |
| return obj; |
| if ((obj = loadicon(name)) != NULL) |
| return obj; |
| if ((obj = imagetobitmap(loadimage(name))) != NULL) |
| return obj; |
| return NULL; |
| } |
| |
| /* |
| * The following functions are obsolete from version 2.4. |
| */ |
| |
| void setbitmapdata(bitmap obj, unsigned char *data) |
| { |
| rect r; |
| int depth, size, row_bytes; |
| int x, y; |
| unsigned char *newdata = NULL; |
| |
| r = obj->rect; |
| depth = obj->depth; |
| |
| /* Calculate source row bytes. */ |
| row_bytes = ((depth * r.width) + 7) / 8; |
| /* Each row must be a multiple of 16 bits wide. */ |
| if (row_bytes % 2) { |
| /* Odd number of bytes, must assign into new array. */ |
| size = (row_bytes+1) * r.height; |
| newdata = array (size, GAbyte); |
| if (! newdata) |
| return; |
| for (y=0; y<r.height; y++) { |
| for (x=0; x<row_bytes; x++) { |
| newdata[y*(row_bytes+1)+x] = |
| data[y*row_bytes+x]; |
| } |
| } |
| SetBitmapBits((HBITMAP)obj->handle, size, |
| (LPSTR)newdata); |
| discard(newdata); |
| } else { |
| /* Correct format already! */ |
| size = row_bytes * r.height; |
| SetBitmapBits((HBITMAP)obj->handle, size, (LPSTR)data); |
| } |
| } |
| |
| void getbitmapdata(bitmap obj, unsigned char *data) |
| { |
| rect r; |
| int depth, size, row_bytes; |
| int x, y; |
| unsigned char *newdata = NULL; |
| |
| r = obj->rect; |
| depth = obj->depth; |
| |
| /* Calculate destination row bytes. */ |
| row_bytes = ((depth * r.width) + 7) / 8; |
| /* Each row must be a multiple of 16 bits wide. */ |
| if (row_bytes % 2) { |
| /* Odd number of bytes, must assign into new array. */ |
| size = (row_bytes+1) * r.height; |
| newdata = array (size, GAbyte); |
| if (! newdata) |
| return; |
| GetBitmapBits((HBITMAP)obj->handle, size, |
| (LPSTR)newdata); |
| for (y=0; y<r.height; y++) { |
| for (x=0; x<row_bytes; x++) { |
| data[y*row_bytes+x] = |
| newdata[y*(row_bytes+1)+x]; |
| } |
| } |
| discard(newdata); |
| } else { |
| /* Correct format already! */ |
| size = row_bytes * r.height; |
| GetBitmapBits((HBITMAP)obj->handle, size, (LPSTR)data); |
| } |
| } |
| |
| bitmap createbitmap(int width, int height, int depth, unsigned char *data) |
| { |
| bitmap obj; |
| |
| if ((obj = newbitmap(width, height, depth)) == NULL) |
| return NULL; |
| if (data) |
| setbitmapdata(obj, data); |
| return obj; |
| } |
| #endif |
| |
| void getbitmapdata2(bitmap obj, unsigned char **data) |
| { |
| rect r = obj->rect; |
| int depth = 32, size, ret; |
| BITMAPINFO bmi; |
| |
| bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
| bmi.bmiHeader.biWidth = r.width; |
| bmi.bmiHeader.biHeight = -r.height; |
| bmi.bmiHeader.biPlanes = 1; |
| bmi.bmiHeader.biBitCount = depth; |
| bmi.bmiHeader.biCompression = BI_RGB; |
| bmi.bmiHeader.biClrUsed = 0; |
| |
| size = 4 * r.width * r.height; |
| *data = (unsigned char *) malloc(size); |
| if(*data) { |
| ret = GetDIBits(get_context(obj), (HBITMAP)obj->handle, |
| 0, r.height, (LPSTR)*data, &bmi, DIB_RGB_COLORS); |
| if(!ret) { |
| free(*data); |
| *data = NULL; |
| } |
| } |
| } |
| |