1
zero-epwing-go/bitmap.c
2021-01-09 15:22:43 -08:00

1363 lines
36 KiB
C

/*
* Copyright (c) 1997-2006 Motoyuki Kasahara
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "build-pre.h"
#include "eb.h"
#include "error.h"
#include "font.h"
#include "build-post.h"
#include <zlib.h>
/*
* Unexported functions.
*/
static unsigned long png_crc(const char *buf, size_t len);
static int png_compress(const char *src, int width, int height, char *dest,
size_t *dest_len);
/*
* Return required buffer size for a narrow font character converted
* to XBM image format.
*/
EB_Error_Code
eb_narrow_font_xbm_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_narrow_font_xbm_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_NARROW_FONT_16_XBM;
break;
case EB_FONT_24:
*size = EB_SIZE_NARROW_FONT_24_XBM;
break;
case EB_FONT_30:
*size = EB_SIZE_NARROW_FONT_30_XBM;
break;
case EB_FONT_48:
*size = EB_SIZE_NARROW_FONT_48_XBM;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_narrow_font_xbm_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_narrow_font_xbm_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a narrow font character converted
* to XPM image format.
*/
EB_Error_Code
eb_narrow_font_xpm_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_narrow_font_xpm_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_NARROW_FONT_16_XPM;
break;
case EB_FONT_24:
*size = EB_SIZE_NARROW_FONT_24_XPM;
break;
case EB_FONT_30:
*size = EB_SIZE_NARROW_FONT_30_XPM;
break;
case EB_FONT_48:
*size = EB_SIZE_NARROW_FONT_48_XPM;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_narrow_font_xpm_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_narrow_font_xpm_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a narrow font character converted
* to GIF image format.
*/
EB_Error_Code
eb_narrow_font_gif_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_narrow_font_gif_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_NARROW_FONT_16_GIF;
break;
case EB_FONT_24:
*size = EB_SIZE_NARROW_FONT_24_GIF;
break;
case EB_FONT_30:
*size = EB_SIZE_NARROW_FONT_30_GIF;
break;
case EB_FONT_48:
*size = EB_SIZE_NARROW_FONT_48_GIF;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_narrow_font_gif_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_narrow_font_gif_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a narrow font character converted
* to BMP image format.
*/
EB_Error_Code
eb_narrow_font_bmp_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_narrow_font_bmp_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_NARROW_FONT_16_BMP;
break;
case EB_FONT_24:
*size = EB_SIZE_NARROW_FONT_24_BMP;
break;
case EB_FONT_30:
*size = EB_SIZE_NARROW_FONT_30_BMP;
break;
case EB_FONT_48:
*size = EB_SIZE_NARROW_FONT_48_BMP;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_narrow_font_bmp_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_narrow_font_bmp_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a narrow font character converted
* to PNG image format.
*/
EB_Error_Code
eb_narrow_font_png_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_narrow_font_png_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_NARROW_FONT_16_PNG;
break;
case EB_FONT_24:
*size = EB_SIZE_NARROW_FONT_24_PNG;
break;
case EB_FONT_30:
*size = EB_SIZE_NARROW_FONT_30_PNG;
break;
case EB_FONT_48:
*size = EB_SIZE_NARROW_FONT_48_PNG;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_narrow_font_png_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_narrow_font_png_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a wide font character converted
* to XBM image format.
*/
EB_Error_Code
eb_wide_font_xbm_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_wide_font_xbm_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_WIDE_FONT_16_XBM;
break;
case EB_FONT_24:
*size = EB_SIZE_WIDE_FONT_24_XBM;
break;
case EB_FONT_30:
*size = EB_SIZE_WIDE_FONT_30_XBM;
break;
case EB_FONT_48:
*size = EB_SIZE_WIDE_FONT_48_XBM;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_wide_font_xbm_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_wide_font_xbm_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a wide font character converted
* to XPM image format.
*/
EB_Error_Code
eb_wide_font_xpm_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_wide_font_xpm_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_WIDE_FONT_16_XPM;
break;
case EB_FONT_24:
*size = EB_SIZE_WIDE_FONT_24_XPM;
break;
case EB_FONT_30:
*size = EB_SIZE_WIDE_FONT_30_XPM;
break;
case EB_FONT_48:
*size = EB_SIZE_WIDE_FONT_48_XPM;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_wide_font_xpm_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_wide_font_xpm_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a wide font character converted
* to GIF image format.
*/
EB_Error_Code
eb_wide_font_gif_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_wide_font_gif_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_WIDE_FONT_16_GIF;
break;
case EB_FONT_24:
*size = EB_SIZE_WIDE_FONT_24_GIF;
break;
case EB_FONT_30:
*size = EB_SIZE_WIDE_FONT_30_GIF;
break;
case EB_FONT_48:
*size = EB_SIZE_WIDE_FONT_48_GIF;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_wide_font_gif_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_wide_font_gif_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a wide font character converted
* to BMP image format.
*/
EB_Error_Code
eb_wide_font_bmp_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_wide_font_bmp_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_WIDE_FONT_16_BMP;
break;
case EB_FONT_24:
*size = EB_SIZE_WIDE_FONT_24_BMP;
break;
case EB_FONT_30:
*size = EB_SIZE_WIDE_FONT_30_BMP;
break;
case EB_FONT_48:
*size = EB_SIZE_WIDE_FONT_48_BMP;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_wide_font_bmp_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_wide_font_bmp_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* Return required buffer size for a wide font character converted
* to PNG image format.
*/
EB_Error_Code
eb_wide_font_png_size(EB_Font_Code height, size_t *size)
{
EB_Error_Code error_code;
LOG(("in: eb_wide_font_png_size(height=%d)", (int)height));
switch (height) {
case EB_FONT_16:
*size = EB_SIZE_WIDE_FONT_16_PNG;
break;
case EB_FONT_24:
*size = EB_SIZE_WIDE_FONT_24_PNG;
break;
case EB_FONT_30:
*size = EB_SIZE_WIDE_FONT_30_PNG;
break;
case EB_FONT_48:
*size = EB_SIZE_WIDE_FONT_48_PNG;
break;
default:
error_code = EB_ERR_NO_SUCH_FONT;
goto failed;
}
LOG(("out: eb_wide_font_png_size(size=%ld) = %s", (long)*size,
eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
*size = 0;
LOG(("out: eb_wide_font_png_size() = %s", eb_error_string(error_code)));
return error_code;
}
/*
* The maximum number of octets in a line in a XBM file.
*/
#define XBM_MAX_OCTETS_A_LINE 12
/*
* The base name of a XBM file.
*/
#define XBM_BASE_NAME "default"
/*
* Convert a bitmap image to XBM format.
*
* It requires four arguements. `xbm' is buffer to store the XBM
* image data. `bitmap', `width', and `height' are bitmap data,
* width, and height of the bitmap image.
*/
EB_Error_Code
eb_bitmap_to_xbm(const char *bitmap, int width, int height, char *xbm,
size_t *xbm_length)
{
char *xbm_p = xbm;
const unsigned char *bitmap_p = (const unsigned char *)bitmap;
int bitmap_size = (width + 7) / 8 * height;
int hex;
int i;
LOG(("in: eb_bitmap_to_xbm(width=%d, height=%d)", width, height));
/*
* Output a header.
*/
sprintf(xbm_p, "#define %s_width %4d\n", XBM_BASE_NAME, width);
xbm_p = strchr(xbm_p, '\n') + 1;
sprintf(xbm_p, "#define %s_height %4d\n", XBM_BASE_NAME, height);
xbm_p = strchr(xbm_p, '\n') + 1;
sprintf(xbm_p, "static unsigned char %s_bits[] = {\n", XBM_BASE_NAME);
xbm_p = strchr(xbm_p, '\n') + 1;
/*
* Output image data.
*/
for (i = 0; i < bitmap_size; i++) {
hex = 0;
hex |= (*bitmap_p & 0x80) ? 0x01 : 0x00;
hex |= (*bitmap_p & 0x40) ? 0x02 : 0x00;
hex |= (*bitmap_p & 0x20) ? 0x04 : 0x00;
hex |= (*bitmap_p & 0x10) ? 0x08 : 0x00;
hex |= (*bitmap_p & 0x08) ? 0x10 : 0x00;
hex |= (*bitmap_p & 0x04) ? 0x20 : 0x00;
hex |= (*bitmap_p & 0x02) ? 0x40 : 0x00;
hex |= (*bitmap_p & 0x01) ? 0x80 : 0x00;
bitmap_p++;
if (i % XBM_MAX_OCTETS_A_LINE != 0) {
sprintf(xbm_p, ", 0x%02x", hex);
xbm_p += 6;
} else if (i == 0) {
sprintf(xbm_p, " 0x%02x", hex);
xbm_p += 7;
} else {
sprintf(xbm_p, ",\n 0x%02x", hex);
xbm_p += 9;
}
}
/*
* Output a footer.
*/
memcpy(xbm_p, "};\n", 3);
xbm_p += 3;
*xbm_length = xbm_p - xbm;
LOG(("out: eb_bitmap_to_xbm(xbm_length=%ld) = %s",
(long)(xbm_p - xbm), eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
}
/*
* The base name of a XPM file.
*/
#define XPM_BASE_NAME "default"
/*
* The foreground and background colors of XPM image.
*/
#define XPM_FOREGROUND_COLOR "Black"
#define XPM_BACKGROUND_COLOR "None"
/*
* Convert a bitmap image to XPM format.
*
* It requires four arguements. `xpm' is buffer to store the XPM
* image data. `bitmap', `width', and `height' are bitmap data,
* width, and height of the bitmap image.
*/
EB_Error_Code
eb_bitmap_to_xpm(const char *bitmap, int width, int height, char *xpm,
size_t *xpm_length)
{
char *xpm_p = xpm;
const unsigned char *bitmap_p = (const unsigned char *)bitmap;
int i, j;
LOG(("in: eb_bitmap_to_xpm(width=%d, height=%d)", width, height));
/*
* Output a header.
*/
sprintf(xpm_p, "/* XPM */\n");
xpm_p = strchr(xpm_p, '\n') + 1;
sprintf(xpm_p, "static char * %s[] = {\n", XPM_BASE_NAME);
xpm_p = strchr(xpm_p, '\n') + 1;
sprintf(xpm_p, "\"%d %d 2 1\",\n", width, height);
xpm_p = strchr(xpm_p, '\n') + 1;
sprintf(xpm_p, "\" c %s\",\n", XPM_BACKGROUND_COLOR);
xpm_p = strchr(xpm_p, '\n') + 1;
sprintf(xpm_p, "\". c %s\",\n", XPM_FOREGROUND_COLOR);
xpm_p = strchr(xpm_p, '\n') + 1;
/*
* Output image data.
*/
for (i = 0; i < height; i++) {
if (0 < i) {
strcpy(xpm_p, "\",\n\"");
xpm_p += 4;
} else {
*xpm_p++ = '\"';
}
for (j = 0; j + 7 < width; j += 8, bitmap_p++) {
*xpm_p++ = (*bitmap_p & 0x80) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x40) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x20) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x10) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x08) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x04) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x02) ? '.' : ' ';
*xpm_p++ = (*bitmap_p & 0x01) ? '.' : ' ';
}
if (j < width) {
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x80) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x40) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x20) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x10) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x08) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x04) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x02) ? '.' : ' ';
if (j++ < width)
*xpm_p++ = (*bitmap_p & 0x01) ? '.' : ' ';
bitmap_p++;
}
}
/*
* Output a footer.
*/
memcpy(xpm_p, "\"};\n", 4);
xpm_p += 4;
if (xpm_length != NULL)
*xpm_length = xpm_p - xpm;
LOG(("out: eb_bitmap_to_xpm(xpm_length=%ld) = %s",
(long)(xpm_p - xpm), eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
}
/*
* The Foreground and background colors of GIF image.
*/
#define GIF_FOREGROUND_COLOR 0x000000
#define GIF_BACKGROUND_COLOR 0xffffff
/*
* The preamble of GIF image.
*/
#define GIF_PREAMBLE_LENGTH 38
static const unsigned char gif_preamble[GIF_PREAMBLE_LENGTH] = {
/*
* Header. (6 bytes)
*/
'G', 'I', 'F', '8', '9', 'a',
/*
* Logical Screen Descriptor. (7 bytes)
* global color table flag = 1.
* color resolution = 1 - 1 = 0.
* sort flag = 0.
* size of global color table = 1 - 1 = 0.
* background color index = 0.
* the pixel aspect ratio = 0 (unused)
* Logical screen width and height are set at run time.
*/
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
/*
* Global Color Table. (6 bytes)
* These are set at run time.
*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*
* Graphic Control Extension. (8 bytes)
* disposal method = 0.
* user input flag = 0.
* transparency flag = 1.
* delay time = 0.
* transparent color index = 0.
*/
0x21, 0xf9, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00,
/*
* Image Descriptor. (10 bytes)
* image left position = 0.
* image top position = 0.
* local color table flag = 0.
* interlace flag = 0.
* sort flag = 0.
* size of local color table = 0.
* Image width and height are set at run time.
*/
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/*
* Code size. (1byte)
*/
0x03
};
/*
* Convert a bitmap image to GIF format.
*
* It requires four arguements. `gif' is buffer to store the GIF
* image data. `bitmap', `width', and `height' are bitmap data,
* width, and height of the bitmap image.
*
* Note: This GIF image doesn't use LZW because of patent.
*/
EB_Error_Code
eb_bitmap_to_gif(const char *bitmap, int width, int height, char *gif,
size_t *gif_length)
{
unsigned char *gif_p = (unsigned char *)gif;
const unsigned char *bitmap_p = (const unsigned char *)bitmap;
int i, j;
LOG(("in: eb_bitmap_to_gif(width=%d, height=%d)", width, height));
/*
* Copy the default preamble.
*/
memcpy(gif_p, gif_preamble, GIF_PREAMBLE_LENGTH);
/*
* Set logical screen width and height.
*/
gif_p[6] = width & 0xff;
gif_p[7] = (width >> 8) & 0xff;
gif_p[8] = height & 0xff;
gif_p[9] = (height >> 8) & 0xff;
/*
* Set global colors.
*/
gif_p[13] = (GIF_BACKGROUND_COLOR >> 16) & 0xff;
gif_p[14] = (GIF_BACKGROUND_COLOR >> 8) & 0xff;
gif_p[15] = GIF_BACKGROUND_COLOR & 0xff;
gif_p[16] = (GIF_FOREGROUND_COLOR >> 16) & 0xff;
gif_p[17] = (GIF_FOREGROUND_COLOR >> 8) & 0xff;
gif_p[18] = GIF_FOREGROUND_COLOR & 0xff;
/*
* Set image width and height.
*/
gif_p[32] = width & 0xff;
gif_p[33] = (width >> 8) & 0xff;
gif_p[34] = height & 0xff;
gif_p[35] = (height >> 8) & 0xff;
gif_p += GIF_PREAMBLE_LENGTH;
/*
* Output image data.
*/
for (i = 0; i < height; i++) {
*gif_p++ = (unsigned char)width;
for (j = 0; j + 7 < width; j += 8, bitmap_p++) {
*gif_p++ = (*bitmap_p & 0x80) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x40) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x20) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x10) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x08) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x04) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x02) ? 0x81 : 0x80;
*gif_p++ = (*bitmap_p & 0x01) ? 0x81 : 0x80;
}
if (j < width) {
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x80) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x40) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x20) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x10) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x08) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x04) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x02) ? 0x81 : 0x80;
if (j++ < width)
*gif_p++ = (*bitmap_p & 0x01) ? 0x81 : 0x80;
bitmap_p++;
}
}
/*
* Output a trailer.
*/
memcpy(gif_p, "\001\011\000\073", 4);
gif_p += 4;
if (gif_length != NULL)
*gif_length = ((char *)gif_p - gif);
LOG(("out: eb_bitmap_to_gif(gif_length=%ld) = %s",
(long)((char *)gif_p - gif), eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
}
/*
* The preamble of BMP image.
*/
#define BMP_PREAMBLE_LENGTH 62
static const unsigned char bmp_preamble[] = {
/* Type. */
'B', 'M',
/* File size. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Reserved. */
0x00, 0x00, 0x00, 0x00,
/* Offset of bitmap bits part. */
0x3e, 0x00, 0x00, 0x00,
/* Size of bitmap info part. */
0x28, 0x00, 0x00, 0x00,
/* Width. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Height. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Planes. */
0x01, 0x00,
/* Bits per pixels. */
0x01, 0x00,
/* Compression mode. */
0x00, 0x00, 0x00, 0x00,
/* Size of bitmap bits part. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* X Pixels per meter. */
0x6d, 0x0b, 0x00, 0x00,
/* Y Pixels per meter. */
0x6d, 0x0b, 0x00, 0x00,
/* Colors */
0x02, 0x00, 0x00, 0x00,
/* Important colors */
0x02, 0x00, 0x00, 0x00,
/* RGB quad of color 0 RGB quad of color 1 */
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/*
* Convert a bitmap image to BMP format.
*
* It requires four arguements. `bmp' is buffer to store the BMP
* image data. `bitmap', `width', and `height' are bitmap data,
* width, and height of the bitmap image.
*/
EB_Error_Code
eb_bitmap_to_bmp(const char *bitmap, int width, int height, char *bmp,
size_t *bmp_length)
{
unsigned char *bmp_p = (unsigned char *)bmp;
size_t data_size;
size_t file_size;
size_t line_pad_length;
size_t bitmap_line_length;
int i, j;
LOG(("in: eb_bitmap_to_bmp(width=%d, height=%d)", width, height));
if (width % 32 == 0)
line_pad_length = 0;
else if (width % 32 <= 8)
line_pad_length = 3;
else if (width % 32 <= 16)
line_pad_length = 2;
else if (width % 32 <= 24)
line_pad_length = 1;
else
line_pad_length = 0;
data_size = (width / 2 + line_pad_length) * height;
file_size = data_size + BMP_PREAMBLE_LENGTH;
/*
* Set BMP preamble.
*/
memcpy(bmp_p, bmp_preamble, BMP_PREAMBLE_LENGTH);
bmp_p[2] = file_size & 0xff;
bmp_p[3] = (file_size >> 8) & 0xff;
bmp_p[4] = (file_size >> 16) & 0xff;
bmp_p[5] = (file_size >> 24) & 0xff;
bmp_p[18] = width & 0xff;
bmp_p[19] = (width >> 8) & 0xff;
bmp_p[20] = (width >> 16) & 0xff;
bmp_p[21] = (width >> 24) & 0xff;
bmp_p[22] = height & 0xff;
bmp_p[23] = (height >> 8) & 0xff;
bmp_p[24] = (height >> 16) & 0xff;
bmp_p[25] = (height >> 24) & 0xff;
bmp_p[34] = data_size & 0xff;
bmp_p[35] = (data_size >> 8) & 0xff;
bmp_p[36] = (data_size >> 16) & 0xff;
bmp_p[37] = (data_size >> 24) & 0xff;
bmp_p += BMP_PREAMBLE_LENGTH;
bitmap_line_length = (width + 7) / 8;
for (i = height - 1; 0 <= i; i--) {
memcpy(bmp_p, bitmap + bitmap_line_length * i, bitmap_line_length);
bmp_p += bitmap_line_length;
for (j = 0; j < line_pad_length; j++, bmp_p++)
*bmp_p = 0x00;
}
if (bmp_length != NULL)
*bmp_length = ((char *)bmp_p - bmp);
LOG(("out: eb_bitmap_to_bmp(bmp_length=%ld) = %s",
(long)((char *)bmp_p - bmp), eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
}
/*
* The Foreground and background colors of PNG image.
*/
#define PNG_FOREGROUND_COLOR 0x000000
#define PNG_BACKGROUND_COLOR 0xffffff
/*
* The preamble of PNG image.
*/
static const unsigned char png_preamble[] = {
/*
* PNG file signature (8 bytes)
*/
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
/*
* IHDR(Image Header) Chunk (25 bytes)
*/
/* Size of IHDR. */
0x00, 0x00, 0x00, 0x0d,
'I', 'H', 'D', 'R',
/* Width. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* Height. (set at run time) */
0x00, 0x00, 0x00, 0x00,
/* misc. */
0x01, 0x03, 0x00, 0x00, 0x00,
/* CRC (set at run time) */
0x00, 0x00, 0x00, 0x00,
/*
* PLTE(Palette) Chunk (18 bytes)
*/
/* Size of PLTE */
0x00, 0x00, 0x00, 0x06,
'P', 'L', 'T', 'E',
/* RGB for palette index 0 */
0xff, 0xff, 0xff,
/* RGB for palette index 1 */
0x00, 0x00, 0x00,
/* CRC (set at run time) */
0x00, 0x00, 0x00, 0x00,
/*
* tRNS(Transparency) Chunk (13 bytes)
*/
/* Size of tRNS */
0x00, 0x00, 0x00, 0x01,
't', 'R', 'N', 'S',
/* Alpha for palette index 0 */
0x00,
/* CRC */
0x40, 0xe6, 0xd8, 0x66,
/*
* IDAT(Image Data) Chunk (12+ bytes)
*/
/* Size of IDAT (set at run time) */
0x00, 0x00, 0x00, 0x00,
'I', 'D', 'A', 'T',
};
static const unsigned char png_trailer[] = {
/* CRC (set at run time) */
0x00, 0x00, 0x00, 0x00,
/*
* IEND(Image End) Chunk (12 bytes)
*/
/* Size of IEND */
0x00, 0x00, 0x00, 0x00,
'I', 'E', 'N', 'D',
/* CRC */
0xae, 0x42, 0x60, 0x82,
};
/*
* Table of CRCs of all 8-bit messages.
*/
static const unsigned long png_crc_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, /* 0x00 - 0x03 */
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, /* 0x04 - 0x07 */
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, /* 0x08 - 0x0b */
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, /* 0x0c - 0x0f */
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, /* 0x10 - 0x13 */
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, /* 0x14 - 0x17 */
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, /* 0x18 - 0x1b */
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, /* 0x1c - 0x1f */
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, /* 0x20 - 0x23 */
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, /* 0x24 - 0x27 */
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, /* 0x28 - 0x2b */
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, /* 0x2c - 0x2f */
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, /* 0x30 - 0x33 */
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, /* 0x34 - 0x37 */
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, /* 0x38 - 0x3b */
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, /* 0x3c - 0x3f */
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, /* 0x40 - 0x43 */
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, /* 0x44 - 0x47 */
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, /* 0x48 - 0x4b */
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, /* 0x4c - 0x4f */
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, /* 0x50 - 0x53 */
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, /* 0x54 - 0x57 */
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, /* 0x58 - 0x5b */
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, /* 0x5c - 0x5f */
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, /* 0x60 - 0x63 */
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, /* 0x64 - 0x67 */
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, /* 0x68 - 0x6b */
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, /* 0x6c - 0x6f */
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, /* 0x70 - 0x73 */
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, /* 0x74 - 0x77 */
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, /* 0x78 - 0x7b */
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, /* 0x7c - 0x7f */
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, /* 0x80 - 0x83 */
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, /* 0x84 - 0x87 */
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, /* 0x88 - 0x8b */
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, /* 0x8c - 0x8f */
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, /* 0x90 - 0x93 */
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, /* 0x94 - 0x97 */
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, /* 0x98 - 0x9b */
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, /* 0x9c - 0x9f */
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, /* 0xa0 - 0xa3 */
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, /* 0xa4 - 0xa7 */
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, /* 0xa8 - 0xab */
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, /* 0xac - 0xaf */
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, /* 0xb0 - 0xb3 */
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, /* 0xb4 - 0xb7 */
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, /* 0xb8 - 0xbb */
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, /* 0xbc - 0xbf */
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, /* 0xc0 - 0xc3 */
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, /* 0xc4 - 0xc7 */
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, /* 0xc8 - 0xcb */
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, /* 0xcc - 0xcf */
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, /* 0xd0 - 0xd3 */
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, /* 0xd4 - 0xd7 */
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, /* 0xd8 - 0xdb */
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, /* 0xdc - 0xdf */
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, /* 0xe0 - 0xe3 */
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, /* 0xe4 - 0xe7 */
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, /* 0xe8 - 0xeb */
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, /* 0xec - 0xef */
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, /* 0xf0 - 0xf3 */
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, /* 0xf4 - 0xf7 */
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, /* 0xf8 - 0xfb */
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d /* 0xfc - 0xff */
};
static unsigned long
png_crc(const char *buf, size_t len)
{
unsigned long c = 0xffffffffL;
int n;
for (n = 0; n < len; n++)
c = png_crc_table[(c ^ *((unsigned char *)buf + n)) & 0xff] ^ (c >> 8);
return c ^ 0xffffffffL;
}
static int
png_compress(const char *src, int width, int height, char *dest,
size_t *dest_len)
{
int line_size = (width + 7) / 8;
z_stream z;
int z_result;
unsigned char byte_zero = 0x00;
int i;
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
z_result = deflateInit(&z, Z_NO_COMPRESSION);
if (z_result != Z_OK)
return z_result;
/*
* Exactly to say, `z.avail_out' must be:
* avail_out > (sizeof(src) + 12) * 1.001
* but we use an approximation here.
*/
z.next_out = (unsigned char *)dest;
z.avail_out = (line_size + 1) * height + 12 + 256;
for (i = 0; i < height - 1; i++) {
z.next_in = &byte_zero;
z.avail_in = 1;
z_result = deflate(&z, Z_NO_FLUSH);
if (z_result != Z_OK || z.avail_in != 0)
goto failed;
z.next_in = (unsigned char *)src + (line_size * i);
z.avail_in = line_size;
z_result = deflate(&z, Z_NO_FLUSH);
if (z_result != Z_OK || z.avail_in != 0)
goto failed;
}
z.next_in = &byte_zero;
z.avail_in = 1;
z_result = deflate(&z, Z_NO_FLUSH);
if (z_result != Z_OK || z.avail_in != 0)
goto failed;
z.next_in = (unsigned char *)src + (line_size * i);
z.avail_in = line_size;
if (deflate(&z, Z_FINISH) != Z_STREAM_END)
goto failed;
z_result = deflateEnd(&z);
if (z_result != Z_OK)
return z_result;
*dest_len = (z.next_out - (unsigned char *)dest);
return Z_STREAM_END;
/*
* An error occurs...
*/
failed:
deflateEnd(&z);
return z_result;
}
#define INT2CHARS(p, i) do { \
*(unsigned char *)(p) = ((i) >> 24) & 0xff; \
*((unsigned char *)(p) + 1) = ((i) >> 16) & 0xff; \
*((unsigned char *)(p) + 2) = ((i) >> 8) & 0xff; \
*((unsigned char *)(p) + 3) = (i) & 0xff; \
} while (0);
#define RGB2CHARS(p, i) do { \
*(unsigned char *)(p) = ((i) >> 16) & 0xff; \
*((unsigned char *)(p) + 1) = ((i) >> 8) & 0xff; \
*((unsigned char *)(p) + 2) = (i) & 0xff; \
} while (0);
/*
* Convert a bitmap image to PNG format.
*
* It requires four arguements. `png' is buffer to store the PNG
* image data. `bitmap', `width', and `height' are bitmap data,
* width, and height of the bitmap image.
*/
EB_Error_Code
eb_bitmap_to_png(const char *bitmap, int width, int height, char *png,
size_t *png_length)
{
EB_Error_Code error_code;
char *png_p = png;
char *idat_start;
size_t idat_len;
unsigned long crc;
int z_result;
LOG(("in: eb_bitmap_to_png(width=%d, height=%d)", width, height));
/*
* Copy the default preamble.
*/
memcpy(png_p, png_preamble, sizeof(png_preamble));
/*
* Set image width and height.
*/
INT2CHARS(png_p + 16, width);
INT2CHARS(png_p + 20, height);
crc = png_crc(png_p + 12, 17);
INT2CHARS(png_p + 29, crc);
/*
* Set global colors.
*/
RGB2CHARS(png_p + 41, PNG_BACKGROUND_COLOR);
RGB2CHARS(png_p + 44, PNG_FOREGROUND_COLOR);
crc = png_crc(png_p + 37, 10);
INT2CHARS(png_p + 47, crc);
/*
* Output `bitmap'.
* We assume memory allocation error occurs if png_compress() doesn't
* return Z_STREAM_END.
*/
idat_start = png_p + sizeof(png_preamble);
z_result = png_compress(bitmap, width, height, idat_start, &idat_len);
if (z_result != Z_STREAM_END) {
error_code = EB_ERR_MEMORY_EXHAUSTED;
goto failed;
}
INT2CHARS(png_p + 64, idat_len);
crc = png_crc(idat_start - 4, idat_len + 4);
png_p = idat_start + idat_len;
/*
* Output a trailer.
*/
memcpy(png_p, png_trailer, sizeof(png_trailer));
INT2CHARS(png_p, crc);
png_p += sizeof(png_trailer);
if (png_length != NULL)
*png_length = ((char *)png_p - png);
LOG(("out: eb_bitmap_to_png(png_length=%ld) = %s",
(long)((char *)png_p - png), eb_error_string(EB_SUCCESS)));
return EB_SUCCESS;
/*
* An error occurs...
*/
failed:
LOG(("out: eb_bitmap_to_png(png_length=%ld) = %s",
(long)((char *)png_p - png), eb_error_string(error_code)));
return error_code;
}
#undef INT2CHARS
#undef RGB2CHARS
#ifdef TEST
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define test_width 32
#define test_height 16
static unsigned char test_bitmap[] = {
0xff, 0xff, 0xff, 0xff, 0x80, 0x81, 0x83, 0x01, 0x80, 0x81, 0x01, 0x01,
0x80, 0x81, 0x01, 0x01, 0xe3, 0x8f, 0x11, 0xc7, 0xe3, 0x8f, 0x0f, 0xc7,
0xe3, 0x81, 0x87, 0xc7, 0xe3, 0x81, 0xc3, 0xc7, 0xe3, 0x81, 0xe1, 0xc7,
0xe3, 0x8f, 0x11, 0xc7, 0xe3, 0x8f, 0x11, 0xc7, 0xe3, 0x81, 0x01, 0xc7,
0xe3, 0x81, 0x01, 0xc7, 0xe3, 0x81, 0x83, 0xc7, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
};
int
main(int argc, char *argv[])
{
char image[EB_SIZE_FONT_IMAGE];
size_t image_size;
int file;
eb_bitmap_to_xbm(test_bitmap, test_width, test_height, image, &image_size);
file = creat("test.xbm", 0644);
if (file < 0)
exit(1);
if (write(file, image, image_size) != image_size) {
close(file);
exit(1);
}
eb_bitmap_to_xpm(test_bitmap, test_width, test_height, image, &image_size);
file = creat("test.xpm", 0644);
if (file < 0)
exit(1);
if (write(file, image, image_size) != image_size) {
close(file);
exit(1);
}
eb_bitmap_to_gif(test_bitmap, test_width, test_height, image, &image_size);
file = creat("test.gif", 0644);
if (file < 0)
exit(1);
if (write(file, image, image_size) != image_size) {
close(file);
exit(1);
}
eb_bitmap_to_bmp(test_bitmap, test_width, test_height, image, &image_size);
file = creat("test.bmp", 0644);
if (file < 0)
exit(1);
if (write(file, image, image_size) != image_size) {
close(file);
exit(1);
}
eb_bitmap_to_png(test_bitmap, test_width, test_height, image, &image_size);
file = creat("test.png", 0644);
if (file < 0)
exit(1);
if (write(file, image, image_size) != image_size) {
close(file);
exit(1);
}
return 0;
}
#endif /* TEST */