/* * bmp.c -- enfle bmp handler * (C)Copyright 1998, 99 by Hiroshi Takekawa * This file is part of Enfle. * * Last Modified: Thu Jun 15 03:43:09 2000. * $Id: bmp.c,v 1.14 2000/06/14 19:45:03 sian Exp $ * * Now supported mono, 8bits/pixel, RLE4, RLE8, and full-color(24/32). * RLE4 support fix by rururu@eastmail.com (SAWAI Masahiko) * * Enfle is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Enfle is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "enfle.h" #include "bmp.h" #include "utils.h" #include "archive.h" #include "plugin.h" int #ifdef PIC get_plugininfo(PluginInfo *p) #else loader_bmp_get_plugininfo(PluginInfo *p) #endif { p->version = 1; p->type = _Loader; p->pluginname = "BMP Format Loader Plugin version 0.2.3"; p->pluginshortname = FORMAT_NAME; p->author = "Hiroshi Takekawa"; p->dlhandle = NULL; /* set by plugin_load */ p->functions.loader.load_image = bmp_load_image; return 1; } /* read bmp header */ static int bmp_read_header(Info *info, Image *p, BITMAPINFOHEADER *ih) { unsigned char buf[2]; Archive *ar = info->ar; int strict; if (archive_read(ar, buf, 2) != 2) return 0; strict = ((buf[0] == 'B' && buf[1] == 'M') || (buf[0] == 'M' && buf[1] == 'B')) ? 1 : 0; memset(ih, 0, sizeof(BITMAPINFOHEADER)); ih->bfSize = read_little_dword(ar); archive_seek(ar, 4, SEEK_CUR); ih->bfOffBits = read_little_dword(ar); ih->biSize = read_little_dword(ar); if (!strict && ih->biSize != 0x28) return 0; if (ih->biSize != WIN_OS2_OLD) { ih->biWidth = read_little_dword(ar); ih->biHeight = read_little_dword(ar); ih->biPlanes = read_little_word(ar); ih->biBitCount = read_little_word(ar); ih->biCompression = read_little_dword(ar); ih->biSizeImage = read_little_dword(ar); ih->biXPixPerMeter = read_little_dword(ar); ih->biYPixPerMeter = read_little_dword(ar); ih->biClrUsed = read_little_dword(ar); ih->biClrImportant = read_little_dword(ar); if (ih->biSize > WIN_NEW) archive_seek(ar, ih->biSize - WIN_NEW, SEEK_CUR); } else { ih->biWidth = read_little_word(ar); ih->biHeight = read_little_word(ar); ih->biPlanes = read_little_word(ar); ih->biBitCount = read_little_word(ar); } if (!strict && (ih->biWidth > 65535 || ih->biHeight > 65535 || ih->biPlanes != 1)) return 0; #ifdef DEBUG fprintf(stderr, "bmp_read_header: depth %d\n", ih->biBitCount); #endif switch (ih->biBitCount) { case 1: case 4: case 8: p->type = _INDEX; break; case 16: fprintf(stderr, "bmp_read_header: depth 16 detected.\n"); case 24: p->type = _RGB24; break; case 32: #ifdef DEBUG fprintf(stderr, "bmp_read_header: depth 32 detected. ** hack enabled. **\n"); #endif ih->biBitCount = 24; ih->depth32 = 1; p->type = _RGB24; break; default: return 0; } p->width = ih->biWidth; p->height = ih->biHeight; p->ncolors = ih->biClrUsed ? ih->biClrUsed : (1 << ih->biBitCount); info->format = FORMAT_NAME; return 1; } /* read bmp color index */ static int bmp_read_colormap(Info *info, Image *p, BITMAPINFOHEADER *ih) { Archive *ar = info->ar; int i; /* read color index */ if (IS_OS2(ih)) { unsigned char buf[256][3]; #ifdef DEBUG fprintf(stderr, "OS/2 color index\n"); #endif archive_read(ar, (unsigned char *)buf, 3 * p->ncolors); for (i = 0; i < p->ncolors; i++) { p->colormap[i][0] = buf[i][2]; p->colormap[i][1] = buf[i][1]; p->colormap[i][2] = buf[i][0]; } } else { unsigned char buf[256][4]; #ifdef DEBUG fprintf(stderr, "Windows color index: %d\n", p->ncolors); #endif archive_read(ar, (unsigned char *)buf, 4 * p->ncolors); for (i = 0; i < p->ncolors; i++) { p->colormap[i][0] = buf[i][2]; p->colormap[i][1] = buf[i][1]; p->colormap[i][2] = buf[i][0]; } } return 1; } static int bmp_load_mono(Info *info, Image *p, BITMAPINFOHEADER *ih) { int i, j, bpl; unsigned char *ptr, *line, *t, c = 0; int width = ih->biWidth; int height = ih->biHeight; unsigned char dummy[4]; Archive *ar = info->ar; p->bytes_per_line = width; bpl = (width + 7) >> 3; bmp_read_colormap(info, p, ih); /* seek to image data */ archive_seek(ar, ih->bfOffBits, SEEK_SET); /* allocate memory for image */ p->image_size = p->bytes_per_line * height; if ((p->image = ptr = malloc(p->image_size)) == NULL) return 0; if ((line = malloc(bpl)) == NULL) return 0; /* loading loop */ for (i = 0; i < height; i++) { t = ptr + (height - i - 1) * p->bytes_per_line; /* read one line */ archive_read(ar, line, bpl); if (bpl % 4) archive_read(ar, dummy, 4 - (bpl % 4)); /* expand pixels */ for (j = 0; j < width; j++) { if (j % 8 == 0) c = line[j >> 3]; t[j] = (c & 0x80) ? 1 : 0; c <<= 1; } } #ifdef DEBUG fprintf(stderr, "loaded.\n"); #endif free(line); return 1; } static int bmp_load_16(Info *info, Image *p, BITMAPINFOHEADER *ih) { int i; unsigned char *data; int width = ih->biWidth; int height = ih->biHeight; Archive *ar = info->ar; p->bytes_per_line = width; bmp_read_colormap(info, p, ih); /* seek to image data */ archive_seek(ar, ih->bfOffBits, SEEK_SET); /* allocate memory for image */ p->image_size = p->bytes_per_line * height; if ((p->image = data = malloc(p->image_size)) == NULL) return 0; if (ih->biCompression == BI_RGB) { unsigned char dummy[4]; unsigned int x, c; unsigned int d; d = (width + 1) >> 1; d %= 4; #ifdef DEBUG fprintf(stderr, "BI_RGB(16) "); #endif /* loading loop */ for (i = 0; i < height; i++) { /* read one line */ for (x = 0; x < width; x += 2) { c = archive_getc(ar); *(data + (height - i - 1) * width + x ) = c >> 4; *(data + (height - i - 1) * width + x + 1) = c & 15; } if (d) archive_read(ar, dummy, 4 - d); } } else if (ih->biCompression != BI_RLE4) { fprintf(stderr, "Illegal compress method\n"); free(data); return 0; } else { unsigned int c, d, x, y; unsigned char *p = data + (height - 1) * width; y = height; x = width; #ifdef DEBUG fprintf(stderr, "BI_RLE4 "); #endif /* RLE compressed data */ while ((c = archive_getc(ar)) != EOF) { if (c != 0) { /* code mode */ d = archive_getc(ar); for (i = 0; i < c; i++) { if(i % 2 == 0) { *p++ = (unsigned char)(d >> 4 & 0x0f); } else { *p++ = (unsigned char)(d & 0x0f); } x--; } } else { if ((c = archive_getc(ar)) == 0) { /* line end */ p += (x - 2 * width); y--; x = width; } else if (c == 1) { /* image end */ break; } else if (c == 2) { /* offset */ p += (archive_getc(ar) + archive_getc(ar) * width); } else { /* absolute mode */ for (i = 0; i < c; i++) { *p++ = (unsigned char)archive_getc(ar); x--; } if (c % 2 != 0) /* read dummy */ c = archive_getc(ar); } } } } #ifdef DEBUG fprintf(stderr, "loaded.\n"); #endif return 1; } static int bmp_load_256(Info *info, Image *p, BITMAPINFOHEADER *ih) { int i; unsigned char *data; int width = ih->biWidth; int height = ih->biHeight; Archive *ar = info->ar; p->bytes_per_line = width; bmp_read_colormap(info, p, ih); /* seek to image data */ archive_seek(ar, ih->bfOffBits, SEEK_SET); /* allocate memory for image */ p->image_size = p->bytes_per_line * height; if ((p->image = data = malloc(p->image_size)) == NULL) return 0; if (ih->biCompression == BI_RGB) { unsigned char dummy[4]; #ifdef DEBUG fprintf(stderr, "BI_RGB(256) "); #endif /* loading loop */ for (i = 0; i < height; i++) { /* read one line */ archive_read(ar, data + (height - i - 1) * width, width); if (width % 4) archive_read(ar, dummy, 4 - (width % 4)); } } else if (ih->biCompression != BI_RLE8) { fprintf(stderr, "Illegal compress method\n"); free(data); return 0; } else { unsigned int c, d, x, y; unsigned char *p = data + (height - 1) * width; y = height; x = width; #ifdef DEBUG fprintf(stderr, "BI_RLE8 "); #endif /* RLE compressed data */ while ((c = archive_getc(ar)) != EOF) { if (c != 0) { /* code mode */ d = archive_getc(ar); for (i = 0; i < c; i++) { *p++ = (unsigned char)d; x--; } } else { if ((c = archive_getc(ar)) == 0) { /* line end */ p += (x - 2 * width); y--; x = width; } else if (c == 1) { /* image end */ break; } else if (c == 2) { /* offset */ p += (archive_getc(ar) + archive_getc(ar) * width); } else { /* absolute mode */ for (i = 0; i < c; i++) { *p++ = (unsigned char)archive_getc(ar); x--; } if (c % 2 != 0) /* read dummy */ c = archive_getc(ar); } } } } #ifdef DEBUG fprintf(stderr, "loaded.\n"); #endif return 1; } static int bmp_load_full(Info *info, Image *p, BITMAPINFOHEADER *ih) { int i, j; unsigned char *ptr, *t, tv; int width = ih->biWidth; int height = ih->biHeight; unsigned char dummy[4]; Archive *ar = info->ar; p->bytes_per_line = width * 3; /* allocate memory for image */ p->image_size = p->bytes_per_line * height; if ((p->image = ptr = malloc(p->image_size)) == NULL) return 0; /* loading loop */ for (i = 0; i < height; i++) { t = ptr + (height - i - 1) * p->bytes_per_line; /* read one line */ archive_read(ar, t, p->bytes_per_line); if (p->bytes_per_line % 4) archive_read(ar, dummy, 4 - (p->bytes_per_line % 4)); /* BMP holds pixel BGR order... so now swap */ for (j = 0; j < width; j++) { tv = *t; *t = *(t + 2); *(t + 2) = tv; t += 3; } } #ifdef DEBUG fprintf(stderr, "loaded.\n"); #endif return 1; } /* Wow... this type picture has no dummy padding..... */ static int bmp_load_full32(Info *info, Image *p, BITMAPINFOHEADER *ih) { int i, j; unsigned char *ptr, *t, tv, dummy; int width = ih->biWidth; int height = ih->biHeight; Archive *ar = info->ar; p->bytes_per_line = width * 3; /* allocate memory for image */ p->image_size = p->bytes_per_line * height; if ((p->image = ptr = malloc(p->image_size)) == NULL) return 0; /* loading loop */ for (i = 0; i < height; i++) { t = ptr + (height - i - 1) * p->bytes_per_line; for (j = 0; j < width; j++) { archive_read(ar, t, 3); archive_read(ar, &dummy, 1); tv = *t; *t = *(t + 2); *(t + 2) = tv; t += 3; } } #ifdef DEBUG fprintf(stderr, "loaded.\n"); #endif return 1; } static int bmp_decode_image(Info *info, Image *p) { BITMAPINFOHEADER ih; int f; #ifdef DEBUG fprintf(stderr, "bmp_decode_image() called\n"); #endif if (!bmp_read_header(info, p, &ih)) return 0; switch (ih.biBitCount) { case 1: f = bmp_load_mono(info, p, &ih); break; case 4: f = bmp_load_16(info, p, &ih); break; case 8: f = bmp_load_256(info, p, &ih); break; case 24: if (ih.depth32) f = bmp_load_full32(info, p, &ih); else f = bmp_load_full(info, p, &ih); break; default: fprintf(stderr, "bmp_decode_image: Unsupported pixel %d\n", ih.biBitCount); return 0; } return f; } int bmp_load_image(Info *info, Image *p) { if (!bmp_decode_image(info, p)) return info->format == NULL ? PROC_NOT : PROC_ERROR; info->npics = 1; /* set handler */ info->handler.destroy = NULL; info->handler.alarmset = NULL; info->handler.alarm = NULL; info->handler.alarmoff = NULL; return PROC_OK; }