|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
gd_bmp.c
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Bitmap format support for libgd
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
* Written 2007, Scott MacVicar
|
|
Packit Service |
df60bb |
---------------------------------------------------------------------------
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Todo:
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Bitfield encoding
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
----------------------------------------------------------------------------
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/**
|
|
Packit Service |
df60bb |
* File: BMP IO
|
|
Packit Service |
df60bb |
*
|
|
Packit Service |
df60bb |
* Read and write BMP images.
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* $Id$ */
|
|
Packit Service |
df60bb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
df60bb |
#include "config.h"
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
#include <stdio.h>
|
|
Packit Service |
df60bb |
#include <math.h>
|
|
Packit Service |
df60bb |
#include <string.h>
|
|
Packit Service |
df60bb |
#include <stdlib.h>
|
|
Packit Service |
df60bb |
#include "gd.h"
|
|
Packit Service |
df60bb |
#include "gdhelpers.h"
|
|
Packit Service |
df60bb |
#include "bmp.h"
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int compress_row(unsigned char *uncompressed_row, int length);
|
|
Packit Service |
df60bb |
static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_header(gdIOCtxPtr infile, bmp_hdr_t *hdr);
|
|
Packit Service |
df60bb |
static int bmp_read_info(gdIOCtxPtr infile, bmp_info_t *info);
|
|
Packit Service |
df60bb |
static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info);
|
|
Packit Service |
df60bb |
static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info);
|
|
Packit Service |
df60bb |
static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
|
|
Packit Service |
df60bb |
static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
|
|
Packit Service |
df60bb |
static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
|
|
Packit Service |
df60bb |
static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header);
|
|
Packit Service |
df60bb |
static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
bc3754 |
static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression);
|
|
Packit Service |
bc3754 |
|
|
Packit Service |
df60bb |
#define BMP_DEBUG(s)
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int gdBMPPutWord(gdIOCtx *out, int w)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
/* Byte order is little-endian */
|
|
Packit Service |
df60bb |
gdPutC(w & 0xFF, out);
|
|
Packit Service |
df60bb |
gdPutC((w >> 8) & 0xFF, out);
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int gdBMPPutInt(gdIOCtx *out, int w)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
/* Byte order is little-endian */
|
|
Packit Service |
df60bb |
gdPutC(w & 0xFF, out);
|
|
Packit Service |
df60bb |
gdPutC((w >> 8) & 0xFF, out);
|
|
Packit Service |
df60bb |
gdPutC((w >> 16) & 0xFF, out);
|
|
Packit Service |
df60bb |
gdPutC((w >> 24) & 0xFF, out);
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
Function: gdImageBmpPtr
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Outputs the given image as BMP data, but using a <gdIOCtx> instead
|
|
Packit Service |
df60bb |
of a file. See <gdImageBmp>.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Parameters:
|
|
Packit Service |
df60bb |
im - the image to save.
|
|
Packit Service |
df60bb |
size - Output: size in bytes of the result.
|
|
Packit Service |
df60bb |
compression - whether to apply RLE or not.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Returns:
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
A pointer to memory containing the image data or NULL on error.
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
void *rv;
|
|
Packit Service |
df60bb |
gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
|
|
Packit Service |
df60bb |
if (out == NULL) return NULL;
|
|
Packit Service |
bc3754 |
if (!_gdImageBmpCtx(im, out, compression))
|
|
Packit Service |
bc3754 |
rv = gdDPExtractData(out, size);
|
|
Packit Service |
bc3754 |
else
|
|
Packit Service |
bc3754 |
rv = NULL;
|
|
Packit Service |
df60bb |
out->gd_free(out);
|
|
Packit Service |
df60bb |
return rv;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
Function: gdImageBmp
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
<gdImageBmp> outputs the specified image to the specified file in
|
|
Packit Service |
df60bb |
BMP format. The file must be open for writing. Under MSDOS and all
|
|
Packit Service |
df60bb |
versions of Windows, it is important to use "wb" as opposed to
|
|
Packit Service |
df60bb |
simply "w" as the mode when opening the file, and under Unix there
|
|
Packit Service |
df60bb |
is no penalty for doing so. <gdImageBmp> does not close the file;
|
|
Packit Service |
df60bb |
your code must do so.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
In addition, <gdImageBmp> allows to specify whether RLE compression
|
|
Packit Service |
df60bb |
should be applied.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Variants:
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
<gdImageBmpCtx> write via a <gdIOCtx> instead of a file handle.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
<gdImageBmpPtr> store the image file to memory.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Parameters:
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
im - the image to save.
|
|
Packit Service |
df60bb |
outFile - the output FILE* object.
|
|
Packit Service |
df60bb |
compression - whether to apply RLE or not.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Returns:
|
|
Packit Service |
df60bb |
nothing
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
gdIOCtx *out = gdNewFileCtx(outFile);
|
|
Packit Service |
df60bb |
if (out == NULL) return;
|
|
Packit Service |
df60bb |
gdImageBmpCtx(im, out, compression);
|
|
Packit Service |
df60bb |
out->gd_free(out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
Function: gdImageBmpCtx
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Outputs the given image as BMP data, but using a <gdIOCtx> instead
|
|
Packit Service |
df60bb |
of a file. See <gdImageBmp>.
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Parameters:
|
|
Packit Service |
df60bb |
im - the image to save.
|
|
Packit Service |
df60bb |
out - the <gdIOCtx> to write to.
|
|
Packit Service |
df60bb |
compression - whether to apply RLE or not.
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
bc3754 |
_gdImageBmpCtx(im, out, compression);
|
|
Packit Service |
bc3754 |
}
|
|
Packit Service |
bc3754 |
|
|
Packit Service |
bc3754 |
static int _gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression)
|
|
Packit Service |
bc3754 |
{
|
|
Packit Service |
df60bb |
int bitmap_size = 0, info_size, total_size, padding;
|
|
Packit Service |
df60bb |
int i, row, xpos, pixel;
|
|
Packit Service |
df60bb |
int error = 0;
|
|
Packit Service |
df60bb |
unsigned char *uncompressed_row = NULL, *uncompressed_row_start = NULL;
|
|
Packit Service |
df60bb |
FILE *tmpfile_for_compression = NULL;
|
|
Packit Service |
df60bb |
gdIOCtxPtr out_original = NULL;
|
|
Packit Service |
bc3754 |
int ret = 1;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* No compression if its true colour or we don't support seek */
|
|
Packit Service |
df60bb |
if (im->trueColor) {
|
|
Packit Service |
df60bb |
compression = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (compression && !out->seek) {
|
|
Packit Service |
df60bb |
/* Try to create a temp file where we can seek */
|
|
Packit Service |
df60bb |
if ((tmpfile_for_compression = tmpfile()) == NULL) {
|
|
Packit Service |
df60bb |
compression = 0;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
out_original = out;
|
|
Packit Service |
df60bb |
if ((out = (gdIOCtxPtr)gdNewFileCtx(tmpfile_for_compression)) == NULL) {
|
|
Packit Service |
df60bb |
out = out_original;
|
|
Packit Service |
df60bb |
out_original = NULL;
|
|
Packit Service |
df60bb |
compression = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
bitmap_size = ((im->sx * (im->trueColor ? 24 : 8)) / 8) * im->sy;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* 40 byte Windows v3 header */
|
|
Packit Service |
df60bb |
info_size = BMP_WINDOWS_V3;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* data for the palette */
|
|
Packit Service |
df60bb |
if (!im->trueColor) {
|
|
Packit Service |
df60bb |
info_size += im->colorsTotal * 4;
|
|
Packit Service |
df60bb |
if (compression) {
|
|
Packit Service |
df60bb |
bitmap_size = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* bitmap header + info header + data */
|
|
Packit Service |
df60bb |
total_size = 14 + info_size + bitmap_size;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* write bmp header info */
|
|
Packit Service |
df60bb |
gdPutBuf("BM", 2, out);
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, total_size);
|
|
Packit Service |
df60bb |
gdBMPPutWord(out, 0);
|
|
Packit Service |
df60bb |
gdBMPPutWord(out, 0);
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, 14 + info_size);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* write Windows v3 headers */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, BMP_WINDOWS_V3); /* header size */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, im->sx); /* width */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, im->sy); /* height */
|
|
Packit Service |
df60bb |
gdBMPPutWord(out, 1); /* colour planes */
|
|
Packit Service |
df60bb |
gdBMPPutWord(out, (im->trueColor ? 24 : 8)); /* bit count */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, (compression ? BMP_BI_RLE8 : BMP_BI_RGB)); /* compression */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, bitmap_size); /* image size */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, 0); /* H resolution */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, 0); /* V ressolution */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, im->colorsTotal); /* colours used */
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, 0); /* important colours */
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* The line must be divisible by 4, else its padded with NULLs */
|
|
Packit Service |
df60bb |
padding = ((int)(im->trueColor ? 3 : 1) * im->sx) % 4;
|
|
Packit Service |
df60bb |
if (padding) {
|
|
Packit Service |
df60bb |
padding = 4 - padding;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* 8-bit colours */
|
|
Packit Service |
df60bb |
if (!im->trueColor) {
|
|
Packit Service |
df60bb |
for(i = 0; i< im->colorsTotal; ++i) {
|
|
Packit Service |
df60bb |
Putchar(gdImageBlue(im, i), out);
|
|
Packit Service |
df60bb |
Putchar(gdImageGreen(im, i), out);
|
|
Packit Service |
df60bb |
Putchar(gdImageRed(im, i), out);
|
|
Packit Service |
df60bb |
Putchar(0, out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (compression) {
|
|
Packit Service |
df60bb |
/* Can potentially change this to X + ((X / 128) * 3) */
|
|
Packit Service |
df60bb |
uncompressed_row = uncompressed_row_start = (unsigned char *) gdCalloc(gdImageSX(im) * 2, sizeof(char));
|
|
Packit Service |
df60bb |
if (!uncompressed_row) {
|
|
Packit Service |
df60bb |
/* malloc failed */
|
|
Packit Service |
df60bb |
goto cleanup;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (row = (im->sy - 1); row >= 0; row--) {
|
|
Packit Service |
df60bb |
if (compression) {
|
|
Packit Service |
df60bb |
memset (uncompressed_row, 0, gdImageSX(im));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = 0; xpos < im->sx; xpos++) {
|
|
Packit Service |
df60bb |
if (compression) {
|
|
Packit Service |
df60bb |
*uncompressed_row++ = (unsigned char)gdImageGetPixel(im, xpos, row);
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
Putchar(gdImageGetPixel(im, xpos, row), out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!compression) {
|
|
Packit Service |
df60bb |
/* Add padding to make sure we have n mod 4 == 0 bytes per row */
|
|
Packit Service |
df60bb |
for (xpos = padding; xpos > 0; --xpos) {
|
|
Packit Service |
df60bb |
Putchar('\0', out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
int compressed_size = 0;
|
|
Packit Service |
df60bb |
uncompressed_row = uncompressed_row_start;
|
|
Packit Service |
df60bb |
if ((compressed_size = compress_row(uncompressed_row, gdImageSX(im))) < 0) {
|
|
Packit Service |
df60bb |
error = 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
bitmap_size += compressed_size;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
gdPutBuf(uncompressed_row, compressed_size, out);
|
|
Packit Service |
df60bb |
Putchar(BMP_RLE_COMMAND, out);
|
|
Packit Service |
df60bb |
Putchar(BMP_RLE_ENDOFLINE, out);
|
|
Packit Service |
df60bb |
bitmap_size += 2;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (compression && uncompressed_row) {
|
|
Packit Service |
df60bb |
gdFree(uncompressed_row);
|
|
Packit Service |
df60bb |
if (error != 0) {
|
|
Packit Service |
df60bb |
goto cleanup;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* Update filesize based on new values and set compression flag */
|
|
Packit Service |
df60bb |
Putchar(BMP_RLE_COMMAND, out);
|
|
Packit Service |
df60bb |
Putchar(BMP_RLE_ENDOFBITMAP, out);
|
|
Packit Service |
df60bb |
bitmap_size += 2;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Write new total bitmap size */
|
|
Packit Service |
df60bb |
gdSeek(out, 2);
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, total_size + bitmap_size);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Total length of image data */
|
|
Packit Service |
df60bb |
gdSeek(out, 34);
|
|
Packit Service |
df60bb |
gdBMPPutInt(out, bitmap_size);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
for (row = (im->sy - 1); row >= 0; row--) {
|
|
Packit Service |
df60bb |
for (xpos = 0; xpos < im->sx; xpos++) {
|
|
Packit Service |
df60bb |
pixel = gdImageGetPixel(im, xpos, row);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
Putchar(gdTrueColorGetBlue(pixel), out);
|
|
Packit Service |
df60bb |
Putchar(gdTrueColorGetGreen(pixel), out);
|
|
Packit Service |
df60bb |
Putchar(gdTrueColorGetRed(pixel), out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Add padding to make sure we have n mod 4 == 0 bytes per row */
|
|
Packit Service |
df60bb |
for (xpos = padding; xpos > 0; --xpos) {
|
|
Packit Service |
df60bb |
Putchar('\0', out);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* If we needed a tmpfile for compression copy it over to out_original */
|
|
Packit Service |
df60bb |
if (tmpfile_for_compression) {
|
|
Packit Service |
df60bb |
unsigned char* copy_buffer = NULL;
|
|
Packit Service |
df60bb |
int buffer_size = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
gdSeek(out, 0);
|
|
Packit Service |
df60bb |
copy_buffer = (unsigned char *) gdMalloc(1024 * sizeof(unsigned char));
|
|
Packit Service |
df60bb |
if (copy_buffer == NULL) {
|
|
Packit Service |
df60bb |
goto cleanup;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
while ((buffer_size = gdGetBuf(copy_buffer, 1024, out)) != EOF) {
|
|
Packit Service |
df60bb |
if (buffer_size == 0) {
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdPutBuf(copy_buffer , buffer_size, out_original);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdFree(copy_buffer);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Replace the temp with the original which now has data */
|
|
Packit Service |
df60bb |
out->gd_free(out);
|
|
Packit Service |
df60bb |
out = out_original;
|
|
Packit Service |
df60bb |
out_original = NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
bc3754 |
ret = 0;
|
|
Packit Service |
df60bb |
cleanup:
|
|
Packit Service |
df60bb |
if (tmpfile_for_compression) {
|
|
Packit Service |
df60bb |
#ifdef _WIN32
|
|
Packit Service |
df60bb |
_rmtmp();
|
|
Packit Service |
df60bb |
#else
|
|
Packit Service |
df60bb |
fclose(tmpfile_for_compression);
|
|
Packit Service |
df60bb |
#endif
|
|
Packit Service |
df60bb |
tmpfile_for_compression = NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (out_original) {
|
|
Packit Service |
df60bb |
out_original->gd_free(out_original);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
bc3754 |
return ret;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int compress_row(unsigned char *row, int length)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int rle_type = 0;
|
|
Packit Service |
df60bb |
int compressed_length = 0;
|
|
Packit Service |
df60bb |
int pixel = 0, compressed_run = 0, rle_compression = 0;
|
|
Packit Service |
df60bb |
unsigned char *uncompressed_row = NULL, *uncompressed_rowp = NULL, *uncompressed_start = NULL;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
uncompressed_row = (unsigned char *) gdMalloc(length);
|
|
Packit Service |
df60bb |
if (!uncompressed_row) {
|
|
Packit Service |
df60bb |
return -1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
memcpy(uncompressed_row, row, length);
|
|
Packit Service |
df60bb |
uncompressed_start = uncompressed_rowp = uncompressed_row;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (pixel = 0; pixel < length; pixel++) {
|
|
Packit Service |
df60bb |
if (compressed_run == 0) {
|
|
Packit Service |
df60bb |
uncompressed_row = uncompressed_rowp;
|
|
Packit Service |
df60bb |
compressed_run++;
|
|
Packit Service |
df60bb |
uncompressed_rowp++;
|
|
Packit Service |
df60bb |
rle_type = BMP_RLE_TYPE_RAW;
|
|
Packit Service |
df60bb |
continue;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (compressed_run == 1) {
|
|
Packit Service |
df60bb |
/* Compare next byte */
|
|
Packit Service |
df60bb |
if (memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
|
|
Packit Service |
df60bb |
rle_type = BMP_RLE_TYPE_RLE;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (rle_type == BMP_RLE_TYPE_RLE) {
|
|
Packit Service |
df60bb |
if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) != 0) {
|
|
Packit Service |
df60bb |
/* more than what we can store in a single run or run is over due to non match, force write */
|
|
Packit Service |
df60bb |
rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
|
|
Packit Service |
df60bb |
row += rle_compression;
|
|
Packit Service |
df60bb |
compressed_length += rle_compression;
|
|
Packit Service |
df60bb |
compressed_run = 0;
|
|
Packit Service |
df60bb |
pixel--;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
compressed_run++;
|
|
Packit Service |
df60bb |
uncompressed_rowp++;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
if (compressed_run >= 128 || memcmp(uncompressed_rowp, uncompressed_rowp - 1, 1) == 0) {
|
|
Packit Service |
df60bb |
/* more than what we can store in a single run or run is over due to match, force write */
|
|
Packit Service |
df60bb |
rle_compression = build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
|
|
Packit Service |
df60bb |
row += rle_compression;
|
|
Packit Service |
df60bb |
compressed_length += rle_compression;
|
|
Packit Service |
df60bb |
compressed_run = 0;
|
|
Packit Service |
df60bb |
pixel--;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
/* add this pixel to the row */
|
|
Packit Service |
df60bb |
compressed_run++;
|
|
Packit Service |
df60bb |
uncompressed_rowp++;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (compressed_run) {
|
|
Packit Service |
df60bb |
compressed_length += build_rle_packet(row, rle_type, compressed_run, uncompressed_row);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
gdFree(uncompressed_start);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return compressed_length;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int build_rle_packet(unsigned char *row, int packet_type, int length, unsigned char *data)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int compressed_size = 0;
|
|
Packit Service |
df60bb |
if (length < 1 || length > 128) {
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Bitmap specific cases is that we can't have uncompressed rows of length 1 or 2 */
|
|
Packit Service |
df60bb |
if (packet_type == BMP_RLE_TYPE_RAW && length < 3) {
|
|
Packit Service |
df60bb |
int i = 0;
|
|
Packit Service |
df60bb |
for (i = 0; i < length; i++) {
|
|
Packit Service |
df60bb |
compressed_size += 2;
|
|
Packit Service |
df60bb |
memset(row, 1, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
memcpy(row, data++, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else if (packet_type == BMP_RLE_TYPE_RLE) {
|
|
Packit Service |
df60bb |
compressed_size = 2;
|
|
Packit Service |
df60bb |
memset(row, length, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
memcpy(row, data, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
compressed_size = 2 + length;
|
|
Packit Service |
df60bb |
memset(row, BMP_RLE_COMMAND, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
memset(row, length, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
memcpy(row, data, length);
|
|
Packit Service |
df60bb |
row += length;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Must be an even number for an uncompressed run */
|
|
Packit Service |
df60bb |
if (length % 2) {
|
|
Packit Service |
df60bb |
memset(row, 0, 1);
|
|
Packit Service |
df60bb |
row++;
|
|
Packit Service |
df60bb |
compressed_size++;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return compressed_size;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
Function: gdImageCreateFromBmp
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp(FILE * inFile)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
gdImagePtr im = 0;
|
|
Packit Service |
df60bb |
gdIOCtx *in = gdNewFileCtx(inFile);
|
|
Packit Service |
df60bb |
if (in == NULL) return NULL;
|
|
Packit Service |
df60bb |
im = gdImageCreateFromBmpCtx(in);
|
|
Packit Service |
df60bb |
in->gd_free(in);
|
|
Packit Service |
df60bb |
return im;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
Function: gdImageCreateFromBmpPtr
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr(int size, void *data)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
gdImagePtr im;
|
|
Packit Service |
df60bb |
gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
|
|
Packit Service |
df60bb |
if (in == NULL) return NULL;
|
|
Packit Service |
df60bb |
im = gdImageCreateFromBmpCtx(in);
|
|
Packit Service |
df60bb |
in->gd_free(in);
|
|
Packit Service |
df60bb |
return im;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/*
|
|
Packit Service |
df60bb |
Function: gdImageCreateFromBmpCtx
|
|
Packit Service |
df60bb |
*/
|
|
Packit Service |
df60bb |
BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
bmp_hdr_t *hdr;
|
|
Packit Service |
df60bb |
bmp_info_t *info;
|
|
Packit Service |
df60bb |
gdImagePtr im = NULL;
|
|
Packit Service |
df60bb |
int error = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!(hdr= (bmp_hdr_t *)gdCalloc(1, sizeof(bmp_hdr_t)))) {
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (bmp_read_header(infile, hdr)) {
|
|
Packit Service |
df60bb |
gdFree(hdr);
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (hdr->magic != 0x4d42) {
|
|
Packit Service |
df60bb |
gdFree(hdr);
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!(info = (bmp_info_t *)gdCalloc(1, sizeof(bmp_info_t)))) {
|
|
Packit Service |
df60bb |
gdFree(hdr);
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (bmp_read_info(infile, info)) {
|
|
Packit Service |
df60bb |
gdFree(hdr);
|
|
Packit Service |
df60bb |
gdFree(info);
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Numcolours: %d\n", info->numcolors));
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Width: %d\n", info->width));
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Height: %d\n", info->height));
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Planes: %d\n", info->numplanes));
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Depth: %d\n", info->depth));
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Offset: %d\n", hdr->off));
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->depth >= 16) {
|
|
Packit Service |
df60bb |
im = gdImageCreateTrueColor(info->width, info->height);
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
im = gdImageCreate(info->width, info->height);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!im) {
|
|
Packit Service |
df60bb |
gdFree(hdr);
|
|
Packit Service |
df60bb |
gdFree(info);
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
switch (info->depth) {
|
|
Packit Service |
df60bb |
case 1:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("1-bit image\n"));
|
|
Packit Service |
df60bb |
error = bmp_read_1bit(im, infile, info, hdr);
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case 4:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("4-bit image\n"));
|
|
Packit Service |
df60bb |
error = bmp_read_4bit(im, infile, info, hdr);
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case 8:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("8-bit image\n"));
|
|
Packit Service |
df60bb |
error = bmp_read_8bit(im, infile, info, hdr);
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case 16:
|
|
Packit Service |
df60bb |
case 24:
|
|
Packit Service |
df60bb |
case 32:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Direct BMP image\n"));
|
|
Packit Service |
df60bb |
error = bmp_read_direct(im, infile, info, hdr);
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
default:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Unknown bit count\n"));
|
|
Packit Service |
df60bb |
error = 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
gdFree(hdr);
|
|
Packit Service |
df60bb |
gdFree(info);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (error) {
|
|
Packit Service |
df60bb |
gdImageDestroy(im);
|
|
Packit Service |
df60bb |
return NULL;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return im;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_header(gdIOCtx *infile, bmp_hdr_t *hdr)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
if(
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&hdr->magic, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&hdr->size, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&hdr->reserved1, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&hdr->reserved2 , infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&hdr->off , infile)
|
|
Packit Service |
df60bb |
) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_info(gdIOCtx *infile, bmp_info_t *info)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
/* read BMP length so we can work out the version */
|
|
Packit Service |
df60bb |
if (!gdGetIntLSB(&info->len, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
switch (info->len) {
|
|
Packit Service |
df60bb |
/* For now treat Windows v4 + v5 as v3 */
|
|
Packit Service |
df60bb |
case BMP_WINDOWS_V3:
|
|
Packit Service |
df60bb |
case BMP_WINDOWS_V4:
|
|
Packit Service |
df60bb |
case BMP_WINDOWS_V5:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Reading Windows Header\n"));
|
|
Packit Service |
df60bb |
if (bmp_read_windows_v3_info(infile, info)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case BMP_OS2_V1:
|
|
Packit Service |
df60bb |
if (bmp_read_os2_v1_info(infile, info)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case BMP_OS2_V2:
|
|
Packit Service |
df60bb |
if (bmp_read_os2_v2_info(infile, info)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
default:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Unhandled bitmap\n"));
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_windows_v3_info(gdIOCtxPtr infile, bmp_info_t *info)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
if (
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->width, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->height, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&info->numplanes, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&info->depth, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->enctype, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->size, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->hres, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->vres, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->numcolors, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->mincolors, infile)
|
|
Packit Service |
df60bb |
) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->height < 0) {
|
|
Packit Service |
df60bb |
info->topdown = 1;
|
|
Packit Service |
df60bb |
info->height = -info->height;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
info->topdown = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
info->type = BMP_PALETTE_4;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
|
|
Packit Service |
df60bb |
info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_os2_v1_info(gdIOCtxPtr infile, bmp_info_t *info)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
if (
|
|
Packit Service |
df60bb |
!gdGetWordLSB((signed short int *)&info->width, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB((signed short int *)&info->height, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&info->numplanes, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&info->depth, infile)
|
|
Packit Service |
df60bb |
) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* OS2 v1 doesn't support topdown */
|
|
Packit Service |
df60bb |
info->topdown = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
info->numcolors = 1 << info->depth;
|
|
Packit Service |
df60bb |
info->type = BMP_PALETTE_3;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
|
|
Packit Service |
df60bb |
info->depth <= 0 || info->numcolors < 0) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_os2_v2_info(gdIOCtxPtr infile, bmp_info_t *info)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
char useless_bytes[24];
|
|
Packit Service |
df60bb |
if (
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->width, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->height, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&info->numplanes, infile) ||
|
|
Packit Service |
df60bb |
!gdGetWordLSB(&info->depth, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->enctype, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->size, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->hres, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->vres, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->numcolors, infile) ||
|
|
Packit Service |
df60bb |
!gdGetIntLSB(&info->mincolors, infile)
|
|
Packit Service |
df60bb |
) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Lets seek the next 24 pointless bytes, we don't care too much about it */
|
|
Packit Service |
df60bb |
if (!gdGetBuf(useless_bytes, 24, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->height < 0) {
|
|
Packit Service |
df60bb |
info->topdown = 1;
|
|
Packit Service |
df60bb |
info->height = -info->height;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
info->topdown = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
info->type = BMP_PALETTE_4;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
|
|
Packit Service |
df60bb |
info->depth <= 0 || info->numcolors < 0 || info->mincolors < 0) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int ypos = 0, xpos = 0, row = 0;
|
|
Packit Service |
df60bb |
int padding = 0, alpha = 0, red = 0, green = 0, blue = 0;
|
|
Packit Service |
df60bb |
signed short int data = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
switch(info->enctype) {
|
|
Packit Service |
df60bb |
case BMP_BI_RGB:
|
|
Packit Service |
df60bb |
/* no-op */
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case BMP_BI_BITFIELDS:
|
|
Packit Service |
df60bb |
if (info->depth == 24) {
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Bitfield compression isn't supported for 24-bit\n"));
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Currently no bitfield support\n"));
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case BMP_BI_RLE8:
|
|
Packit Service |
df60bb |
if (info->depth != 8) {
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("RLE is only valid for 8-bit images\n"));
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case BMP_BI_RLE4:
|
|
Packit Service |
df60bb |
if (info->depth != 4) {
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("RLE is only valid for 4-bit images\n"));
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
case BMP_BI_JPEG:
|
|
Packit Service |
df60bb |
case BMP_BI_PNG:
|
|
Packit Service |
df60bb |
default:
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Unsupported BMP compression format\n"));
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* There is a chance the data isn't until later, would be wierd but it is possible */
|
|
Packit Service |
df60bb |
if (gdTell(infile) != header->off) {
|
|
Packit Service |
df60bb |
/* Should make sure we don't seek past the file size */
|
|
Packit Service |
df60bb |
if (!gdSeek(infile, header->off)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* The line must be divisible by 4, else its padded with NULLs */
|
|
Packit Service |
df60bb |
padding = ((int)(info->depth / 8) * info->width) % 4;
|
|
Packit Service |
df60bb |
if (padding) {
|
|
Packit Service |
df60bb |
padding = 4 - padding;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (ypos = 0; ypos < info->height; ++ypos) {
|
|
Packit Service |
df60bb |
if (info->topdown) {
|
|
Packit Service |
df60bb |
row = ypos;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
row = info->height - ypos - 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = 0; xpos < info->width; xpos++) {
|
|
Packit Service |
df60bb |
if (info->depth == 16) {
|
|
Packit Service |
df60bb |
if (!gdGetWordLSB(&data, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("Data: %X\n", data));
|
|
Packit Service |
df60bb |
red = ((data & 0x7C00) >> 10) << 3;
|
|
Packit Service |
df60bb |
green = ((data & 0x3E0) >> 5) << 3;
|
|
Packit Service |
df60bb |
blue = (data & 0x1F) << 3;
|
|
Packit Service |
df60bb |
BMP_DEBUG(printf("R: %d, G: %d, B: %d\n", red, green, blue));
|
|
Packit Service |
df60bb |
} else if (info->depth == 24) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&blue, infile) || !gdGetByte(&green, infile) || !gdGetByte(&red, infile) || !gdGetByte(&alpha, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/*alpha = gdAlphaMax - (alpha >> 1);*/
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos, row, gdTrueColor(red, green, blue));
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
for (xpos = padding; xpos > 0; --xpos) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&red, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_palette(gdImagePtr im, gdIOCtxPtr infile, int count, int read_four)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int i;
|
|
Packit Service |
df60bb |
int r, g, b, z;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (i = 0; i < count; i++) {
|
|
Packit Service |
df60bb |
if (
|
|
Packit Service |
df60bb |
!gdGetByte(&b, infile) ||
|
|
Packit Service |
df60bb |
!gdGetByte(&g, infile) ||
|
|
Packit Service |
df60bb |
!gdGetByte(&r, infile) ||
|
|
Packit Service |
df60bb |
(read_four && !gdGetByte(&z, infile))
|
|
Packit Service |
df60bb |
) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
im->red[i] = r;
|
|
Packit Service |
df60bb |
im->green[i] = g;
|
|
Packit Service |
df60bb |
im->blue[i] = b;
|
|
Packit Service |
df60bb |
im->open[i] = 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int ypos = 0, xpos = 0, row = 0, index = 0;
|
|
Packit Service |
df60bb |
int padding = 0, current_byte = 0, bit = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->enctype != BMP_BI_RGB) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!info->numcolors) {
|
|
Packit Service |
df60bb |
info->numcolors = 2;
|
|
Packit Service |
df60bb |
} else if (info->numcolors < 0 || info->numcolors > 2) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
im->colorsTotal = info->numcolors;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* There is a chance the data isn't until later, would be wierd but it is possible */
|
|
Packit Service |
df60bb |
if (gdTell(infile) != header->off) {
|
|
Packit Service |
df60bb |
/* Should make sure we don't seek past the file size */
|
|
Packit Service |
df60bb |
if (!gdSeek(infile, header->off)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* The line must be divisible by 4, else its padded with NULLs */
|
|
Packit Service |
df60bb |
padding = ((int)ceil(0.1 * info->width)) % 4;
|
|
Packit Service |
df60bb |
if (padding) {
|
|
Packit Service |
df60bb |
padding = 4 - padding;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (ypos = 0; ypos < info->height; ++ypos) {
|
|
Packit Service |
df60bb |
if (info->topdown) {
|
|
Packit Service |
df60bb |
row = ypos;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
row = info->height - ypos - 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = 0; xpos < info->width; xpos += 8) {
|
|
Packit Service |
df60bb |
/* Bitmaps are always aligned in bytes so we'll never overflow */
|
|
Packit Service |
df60bb |
if (!gdGetByte(¤t_byte, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (bit = 0; bit < 8; bit++) {
|
|
Packit Service |
df60bb |
index = ((current_byte & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
|
|
Packit Service |
df60bb |
if (im->open[index]) {
|
|
Packit Service |
df60bb |
im->open[index] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos + bit, row, index);
|
|
Packit Service |
df60bb |
/* No need to read anything extra */
|
|
Packit Service |
df60bb |
if ((xpos + bit) >= info->width) {
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = padding; xpos > 0; --xpos) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&index, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int ypos = 0, xpos = 0, row = 0, index = 0;
|
|
Packit Service |
df60bb |
int padding = 0, current_byte = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE4) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!info->numcolors) {
|
|
Packit Service |
df60bb |
info->numcolors = 16;
|
|
Packit Service |
df60bb |
} else if (info->numcolors < 0 || info->numcolors > 16) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
im->colorsTotal = info->numcolors;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* There is a chance the data isn't until later, would be wierd but it is possible */
|
|
Packit Service |
df60bb |
if (gdTell(infile) != header->off) {
|
|
Packit Service |
df60bb |
/* Should make sure we don't seek past the file size */
|
|
Packit Service |
df60bb |
if (!gdSeek(infile, header->off)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* The line must be divisible by 4, else its padded with NULLs */
|
|
Packit Service |
df60bb |
padding = ((int)ceil(0.5 * info->width)) % 4;
|
|
Packit Service |
df60bb |
if (padding) {
|
|
Packit Service |
df60bb |
padding = 4 - padding;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
switch (info->enctype) {
|
|
Packit Service |
df60bb |
case BMP_BI_RGB:
|
|
Packit Service |
df60bb |
for (ypos = 0; ypos < info->height; ++ypos) {
|
|
Packit Service |
df60bb |
if (info->topdown) {
|
|
Packit Service |
df60bb |
row = ypos;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
row = info->height - ypos - 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = 0; xpos < info->width; xpos += 2) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(¤t_byte, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
index = (current_byte >> 4) & 0x0f;
|
|
Packit Service |
df60bb |
if (im->open[index]) {
|
|
Packit Service |
df60bb |
im->open[index] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos, row, index);
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* This condition may get called often, potential optimsations */
|
|
Packit Service |
df60bb |
if (xpos >= info->width) {
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
index = current_byte & 0x0f;
|
|
Packit Service |
df60bb |
if (im->open[index]) {
|
|
Packit Service |
df60bb |
im->open[index] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos + 1, row, index);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = padding; xpos > 0; --xpos) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&index, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case BMP_BI_RLE4:
|
|
Packit Service |
df60bb |
if (bmp_read_rle(im, infile, info)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
default:
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp_hdr_t *header)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int ypos = 0, xpos = 0, row = 0, index = 0;
|
|
Packit Service |
df60bb |
int padding = 0;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (info->enctype != BMP_BI_RGB && info->enctype != BMP_BI_RLE8) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!info->numcolors) {
|
|
Packit Service |
df60bb |
info->numcolors = 256;
|
|
Packit Service |
df60bb |
} else if (info->numcolors < 0 || info->numcolors > 256) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (bmp_read_palette(im, infile, info->numcolors, (info->type == BMP_PALETTE_4))) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
im->colorsTotal = info->numcolors;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* There is a chance the data isn't until later, would be wierd but it is possible */
|
|
Packit Service |
df60bb |
if (gdTell(infile) != header->off) {
|
|
Packit Service |
df60bb |
/* Should make sure we don't seek past the file size */
|
|
Packit Service |
df60bb |
if (!gdSeek(infile, header->off)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* The line must be divisible by 4, else its padded with NULLs */
|
|
Packit Service |
df60bb |
padding = (1 * info->width) % 4;
|
|
Packit Service |
df60bb |
if (padding) {
|
|
Packit Service |
df60bb |
padding = 4 - padding;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
switch (info->enctype) {
|
|
Packit Service |
df60bb |
case BMP_BI_RGB:
|
|
Packit Service |
df60bb |
for (ypos = 0; ypos < info->height; ++ypos) {
|
|
Packit Service |
df60bb |
if (info->topdown) {
|
|
Packit Service |
df60bb |
row = ypos;
|
|
Packit Service |
df60bb |
} else {
|
|
Packit Service |
df60bb |
row = info->height - ypos - 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (xpos = 0; xpos < info->width; ++xpos) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&index, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (im->open[index]) {
|
|
Packit Service |
df60bb |
im->open[index] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos, row, index);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
/* Could create a new variable, but it isn't really worth it */
|
|
Packit Service |
df60bb |
for (xpos = padding; xpos > 0; --xpos) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&index, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
case BMP_BI_RLE8:
|
|
Packit Service |
df60bb |
if (bmp_read_rle(im, infile, info)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
default:
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
static int bmp_read_rle(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info)
|
|
Packit Service |
df60bb |
{
|
|
Packit Service |
df60bb |
int ypos = 0, xpos = 0, row = 0, index = 0;
|
|
Packit Service |
df60bb |
int rle_length = 0, rle_data = 0;
|
|
Packit Service |
df60bb |
int padding = 0;
|
|
Packit Service |
df60bb |
int i = 0, j = 0;
|
|
Packit Service |
df60bb |
int pixels_per_byte = 8 / info->depth;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (ypos = 0; ypos < info->height && xpos <= info->width;) {
|
|
Packit Service |
df60bb |
if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
row = info->height - ypos - 1;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (rle_length != BMP_RLE_COMMAND) {
|
|
Packit Service |
df60bb |
if (im->open[rle_data]) {
|
|
Packit Service |
df60bb |
im->open[rle_data] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (i = 0; (i < rle_length) && (xpos < info->width);) {
|
|
Packit Service |
df60bb |
for (j = 1; (j <= pixels_per_byte) && (xpos < info->width) && (i < rle_length); j++, xpos++, i++) {
|
|
Packit Service |
df60bb |
index = (rle_data & (((1 << info->depth) - 1) << (8 - (j * info->depth)))) >> (8 - (j * info->depth));
|
|
Packit Service |
df60bb |
if (im->open[index]) {
|
|
Packit Service |
df60bb |
im->open[index] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos, row, index);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else if (rle_length == BMP_RLE_COMMAND && rle_data > 2) {
|
|
Packit Service |
df60bb |
/* Uncompressed RLE needs to be even */
|
|
Packit Service |
df60bb |
padding = 0;
|
|
Packit Service |
df60bb |
for (i = 0; (i < rle_data) && (xpos < info->width); i += pixels_per_byte) {
|
|
Packit Service |
df60bb |
int max_pixels = pixels_per_byte;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (!gdGetByte(&index, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
padding++;
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
if (rle_data - i < max_pixels) {
|
|
Packit Service |
df60bb |
max_pixels = rle_data - i;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
for (j = 1; (j <= max_pixels) && (xpos < info->width); j++, xpos++) {
|
|
Packit Service |
df60bb |
int temp = (index >> (8 - (j * info->depth))) & ((1 << info->depth) - 1);
|
|
Packit Service |
df60bb |
if (im->open[temp]) {
|
|
Packit Service |
df60bb |
im->open[temp] = 0;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
gdImageSetPixel(im, xpos, row, temp);
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
|
|
Packit Service |
df60bb |
/* Make sure the bytes read are even */
|
|
Packit Service |
df60bb |
if (padding % 2 && !gdGetByte(&index, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFLINE) {
|
|
Packit Service |
df60bb |
/* Next Line */
|
|
Packit Service |
df60bb |
xpos = 0;
|
|
Packit Service |
df60bb |
ypos++;
|
|
Packit Service |
df60bb |
} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_DELTA) {
|
|
Packit Service |
df60bb |
/* Delta Record, used for bmp files that contain other data*/
|
|
Packit Service |
df60bb |
if (!gdGetByte(&rle_length, infile) || !gdGetByte(&rle_data, infile)) {
|
|
Packit Service |
df60bb |
return 1;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
xpos += rle_length;
|
|
Packit Service |
df60bb |
ypos += rle_data;
|
|
Packit Service |
df60bb |
} else if (rle_length == BMP_RLE_COMMAND && rle_data == BMP_RLE_ENDOFBITMAP) {
|
|
Packit Service |
df60bb |
/* End of bitmap */
|
|
Packit Service |
df60bb |
break;
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
}
|
|
Packit Service |
df60bb |
return 0;
|
|
Packit Service |
df60bb |
}
|