cvs: gd /playground/gdbmp bmp.h gd_bmp.c
[email protected] ("Scott MacVicar") Fri, 14 Mar 2008 16:46:34 -0000
| Newsgroups | php.gd.cvs |
|---|---|
| Message-ID | <cvsscottmac1205513194@cvsserver> |
scottmac Fri Mar 14 16:46:34 2008 UTC
Modified files:
/gd/playground/gdbmp bmp.h gd_bmp.c
Log:
Support for RLE, at the moment the option to enable it is not exposed until further cleanup and testing.
scottmac-20080314164634.txt
(text/plain, 8.8 KB)
http://cvs.php.net/viewvc.cgi/gd/playground/gdbmp/bmp.h?r1=1.4&r2=1.5&diff_format=u
Index: gd/playground/gdbmp/bmp.h
diff -u gd/playground/gdbmp/bmp.h:1.4 gd/playground/gdbmp/bmp.h:1.5
--- gd/playground/gdbmp/bmp.h:1.4 Fri Feb 29 21:46:32 2008
+++ gd/playground/gdbmp/bmp.h Fri Mar 14 16:46:34 2008
@@ -1,4 +1,4 @@
-/* $Id: bmp.h,v 1.4 2008/02/29 21:46:32 pajoye Exp $ */
+/* $Id: bmp.h,v 1.5 2008/03/14 16:46:34 scottmac Exp $ */
#ifdef __cplusplus
extern "C" {
#endif
@@ -43,6 +43,9 @@
#define BMP_RLE_ENDOFBITMAP 1
#define BMP_RLE_DELTA 2
+#define BMP_RLE_TYPE_RAW 0
+#define BMP_RLE_TYPE_RLE 1
+
/* BMP header. */
typedef struct
{
http://cvs.php.net/viewvc.cgi/gd/playground/gdbmp/gd_bmp.c?r1=1.8&r2=1.9&diff_format=u
Index: gd/playground/gdbmp/gd_bmp.c
diff -u gd/playground/gdbmp/gd_bmp.c:1.8 gd/playground/gdbmp/gd_bmp.c:1.9
--- gd/playground/gdbmp/gd_bmp.c:1.8 Tue Mar 11 19:49:27 2008
+++ gd/playground/gdbmp/gd_bmp.c Fri Mar 14 16:46:34 2008
@@ -12,7 +12,7 @@
----------------------------------------------------------------------------
*/
-/* $Id: gd_bmp.c,v 1.8 2008/03/11 19:49:27 scottmac Exp $ */
+/* $Id: gd_bmp.c,v 1.9 2008/03/14 16:46:34 scottmac Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -25,6 +25,9 @@
#include "gdhelpers.h"
#include "bmp.h"
+static int compress_row(unsigned char *uncompressed_row, int length);
+static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
+
static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
@@ -82,36 +85,46 @@
BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out)
{
- int bitmap_size, info_size, total_size, padding;
+ int bitmap_size = 0, info_size, total_size, padding;
int i, row, xpos, pixel;
+ int compression = 0;
+ unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
+
/* 40 byte Windows v3 header */
info_size = BMP_WINDOWS_V3;
/* data for the palette */
- if (!im->trueColor)
- {
+ if (!im->trueColor) {
info_size += im->colorsTotal * 4;
+ if (compression) {
+ bitmap_size = 0;
+ }
}
/* bitmap header + info header + data */
total_size = 14 + info_size + bitmap_size;
+ /* we need seek support at this moment in time */
+ if (!out->seek) {
+ return;
+ }
+
/* write bmp header info */
gdPutBuf("BM", 2, out);
gdBMPPutInt(out, total_size);
gdBMPPutWord(out, 0);
gdBMPPutWord(out, 0);
gdBMPPutInt(out, 14 + info_size);
-
+
/* write Windows v3 headers */
gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
gdBMPPutInt(out, im->sx); /* width */
gdBMPPutInt(out, im->sy); /* height */
gdBMPPutWord(out, 1); /* colour planes */
gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
- gdBMPPutInt(out, BMP_BI_RGB); /* compression */
+ gdBMPPutInt(out, ((!compression || im->trueColor) ? BMP_BI_RGB : BMP_BI_RLE8)); /* compression */
gdBMPPutInt(out, bitmap_size); /* image size */
gdBMPPutInt(out, 0); /* H resolution */
gdBMPPutInt(out, 0); /* V ressolution */
@@ -126,26 +139,76 @@
/* 8-bit colours */
if (!im->trueColor) {
- for(i = 0; i< im->colorsTotal; ++i) {
+ for(i = 0; i< im->colorsTotal; ++i) {
Putchar(gdImageBlue(im, i), out);
Putchar(gdImageGreen(im, i), out);
Putchar(gdImageRed(im, i), out);
Putchar(0, out);
}
+
+ if (compression) {
+ /* Can potentially change this to X + ((X / 128) * 3) */
+ uncompressed_row = uncompressed_row_start = (unsigned char *) gdMalloc(gdImageSX(im) * 2);
+ if (!uncompressed_row) {
+ /* malloc failed */
+ return;
+ }
+ memset (uncompressed_row, 0, gdImageSX(im) * 2);
+ }
+
for (row = (im->sy - 1); row >= 0; row--) {
+ if (compression) {
+ memset (uncompressed_row, 0, gdImageSX(im));
+ }
+
for (xpos = 0; xpos < im->sx; xpos++) {
- Putchar(gdImageGetPixel(im, xpos, row), out);
+ if (compression) {
+ *uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
+ } else {
+ Putchar(gdImageGetPixel(im, xpos, row), out);
+ }
}
- /* Add padding to make sure we have n mod 4 == 0 bytes per row */
- for (xpos = padding; xpos > 0; --xpos) {
- Putchar('\0', out);
+
+ if (!compression) {
+ /* Add padding to make sure we have n mod 4 == 0 bytes per row */
+ for (xpos = padding; xpos > 0; --xpos) {
+ Putchar('\0', out);
+ }
+ } else {
+ int compressed_size = 0;
+ uncompressed_row = uncompressed_row_start;
+ compressed_size = compress_row(uncompressed_row, gdImageSX(im));
+ bitmap_size += compressed_size;
+
+
+ gdPutBuf(uncompressed_row, compressed_size, out);
+ Putchar(BMP_RLE_COMMAND, out);
+ Putchar(BMP_RLE_ENDOFLINE, out);
+ bitmap_size += 2;
}
}
+
+ if (compression && uncompressed_row) {
+ gdFree(uncompressed_row);
+ /* Update filesize based on new values and set compression flag */
+ Putchar(BMP_RLE_COMMAND, out);
+ Putchar(BMP_RLE_ENDOFBITMAP, out);
+ bitmap_size += 2;
+
+ /* Write new total bitmap size */
+ gdSeek(out, 2);
+ gdBMPPutInt(out, total_size + bitmap_size);
+
+ /* Total length of image data */
+ gdSeek(out, 34);
+ gdBMPPutInt(out, bitmap_size);
+ }
+
} else {
for (row = (im->sy - 1); row >= 0; row--) {
for (xpos = 0; xpos < im->sx; xpos++) {
pixel = gdImageGetPixel(im, xpos, row);
-
+
Putchar(gdTrueColorGetBlue(pixel), out);
Putchar(gdTrueColorGetGreen(pixel), out);
Putchar(gdTrueColorGetRed(pixel), out);
@@ -159,6 +222,119 @@
}
}
+static int compress_row(unsigned char *row, int length)
+{
+ int i = 0, rle_type = 0;
+ int compressed_length = 0;
+ int pixel = 0, compressed_run = 0, rle_compression = 0;
+ unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL;
+ uncompressed_row = (unsigned char *) gdMalloc(length);
+ memcpy(uncompressed_row, row, length);
+ uncompressed_rowp = uncompressed_row;
+
+ for (pixel = 0; pixel < length; pixel++)
+ {
+ if (compressed_run == 0) {
+ uncompressed_row = uncompressed_rowp;
+ compressed_run++;
+ uncompressed_rowp++;
+ rle_type = BMP_RLE_TYPE_RAW;
+ continue;
+ }
+
+ if (compressed_run == 1) {
+ /* Compare next byte */
+ if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
+ rle_type = BMP_RLE_TYPE_RLE;
+ }
+ }
+
+ if (rle_type == BMP_RLE_TYPE_RLE) {
+ if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
+ /* more than what we can store in a single run or run is over due to non match, force write */
+ rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
+ row += rle_compression;
+ compressed_length += rle_compression;
+ compressed_run = 0;
+ pixel--;
+ } else {
+ compressed_run++;
+ uncompressed_rowp++;
+ }
+ } else {
+ if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
+ /* more than what we can store in a single run or run is over due to match, force write */
+ rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
+ row += rle_compression;
+ compressed_length += rle_compression;
+ compressed_run = 0;
+ pixel--;
+ } else {
+ /* add this pixel to the row */
+ compressed_run++;
+ uncompressed_rowp++;
+ }
+
+ }
+ }
+
+ if (compressed_run) {
+ if (rle_type == BMP_RLE_TYPE_RLE) {
+ compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
+ } else {
+ compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
+ }
+ }
+
+ return compressed_length;
+}
+
+static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
+{
+ int compressed_size = 0;
+ if (length < 1 || length > 128) {
+ return 0;
+ }
+
+ /* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
+ if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
+ int i = 0;
+ for (i = 0; i < length; i++) {
+ compressed_size += 2;
+ memset(row, 1, 1);
+ row++;
+
+ memcpy(row, data++, 1);
+ row++;
+ }
+ } else if (packet_type == BMP_RLE_TYPE_RLE) {
+ compressed_size = 2;
+ memset(row, length, 1);
+ row++;
+
+ memcpy(row, data, 1);
+ row++;
+ } else {
+ compressed_size = 2 + length;
+ memset(row, BMP_RLE_COMMAND, 1);
+ row++;
+
+ memset(row, length, 1);
+ row++;
+
+ memcpy(row, data, length);
+ row += length;
+
+ /* Must be an even number for an uncompressed run */
+ if (length % 2) {
+ memset(row, 0, 1);
+ row++;
+ compressed_size++;
+ }
+ }
+ return compressed_size;
+}
+
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
{
gdImagePtr im = 0;
@@ -648,7 +824,7 @@
if (xpos >= info->width) {
break;
}
-
+
index = current_byte & 0x0f;
if (im->open[index]) {
im->open[index] = 0;