mirror of
https://github.com/VincentWei/MiniGUI.git
synced 2026-09-25 02:33:59 +08:00
575 lines
16 KiB
C
575 lines
16 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IMPORTANT NOTICE
|
|
//
|
|
// The following open source license statement does not apply to any
|
|
// entity in the Exception List published by FMSoft.
|
|
//
|
|
// For more information, please visit:
|
|
//
|
|
// https://www.fmsoft.cn/exception-list
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/*
|
|
* This file is part of MiniGUI, a mature cross-platform windowing
|
|
* and Graphics User Interface (GUI) support system for embedded systems
|
|
* and smart IoT devices.
|
|
*
|
|
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
|
|
* Copyright (C) 1998~2002, WEI Yongming
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Or,
|
|
*
|
|
* As this program is a library, any link to this program must follow
|
|
* GNU General Public License version 3 (GPLv3). If you cannot accept
|
|
* GPLv3, you need to be licensed from FMSoft.
|
|
*
|
|
* If you have got a commercial license of this program, please use it
|
|
* under the terms and conditions of the commercial license.
|
|
*
|
|
* For more information about the commercial license, please refer to
|
|
* <http://www.minigui.com/blog/minigui-licensing-policy/>.
|
|
*/
|
|
/*
|
|
** Low-level TGA bitmap file read/save function.
|
|
**
|
|
** Create date: 2000/08/27, derived from original bitmap.c
|
|
**
|
|
** Current maintainer: Wei Yongming.
|
|
**
|
|
** FIXME: Some errors occurred when RLE used.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "common.h"
|
|
#include "gdi.h"
|
|
#include "readbmp.h"
|
|
|
|
#ifdef _MGIMAGE_TGA
|
|
|
|
/* rle_tga_read:
|
|
* Helper for reading 256 color RLE data from TGA files.
|
|
*/
|
|
static void rle_tga_read(unsigned char *b, int len, MG_RWops *f)
|
|
{
|
|
unsigned char value;
|
|
int count;
|
|
int c = 0;
|
|
|
|
do {
|
|
count = fp_getc(f);
|
|
if (count & 0x80) {
|
|
count = (count & 0x7F) + 1;
|
|
c += count;
|
|
value = fp_getc(f);
|
|
while (count--)
|
|
*(b++) = value;
|
|
}
|
|
else {
|
|
count++;
|
|
c += count;
|
|
MGUI_RWread (f, b, 1, count);
|
|
b += count;
|
|
}
|
|
} while (!MGUI_RWeof (f) && c < len);
|
|
}
|
|
|
|
|
|
|
|
/* rle_tga_read32:
|
|
* Helper for reading 32 bit RLE data from TGA files.
|
|
*/
|
|
static void rle_tga_read32(unsigned char *b, int len, MG_RWops *f)
|
|
{
|
|
unsigned char value[4];
|
|
int count;
|
|
int c = 0;
|
|
|
|
do {
|
|
count = fp_getc(f);
|
|
if (count & 0x80) {
|
|
count = (count & 0x7F) + 1;
|
|
c += count;
|
|
MGUI_RWread (f, value, 1, 4);
|
|
while (count--) {
|
|
b[3] = value[3];
|
|
b[2] = value[2];
|
|
b[1] = value[1];
|
|
b[0] = value[0];
|
|
b += 4;
|
|
}
|
|
}
|
|
else {
|
|
count++;
|
|
c += count;
|
|
while (count--) {
|
|
MGUI_RWread (f, value, 1, 4);
|
|
b[3] = value[3];
|
|
b[2] = value[2];
|
|
b[1] = value[1];
|
|
b[0] = value[0];
|
|
b += 4;
|
|
}
|
|
}
|
|
} while (!MGUI_RWeof (f) && c < len);
|
|
}
|
|
|
|
/* rle_tga_read24:
|
|
* Helper for reading 24 bit RLE data from TGA files.
|
|
*/
|
|
static void rle_tga_read24(unsigned char *b, int len, MG_RWops *f)
|
|
{
|
|
unsigned char value[4];
|
|
int count;
|
|
int c = 0;
|
|
|
|
do {
|
|
count = fp_getc(f);
|
|
if (count & 0x80) {
|
|
count = (count & 0x7F) + 1;
|
|
c += count;
|
|
MGUI_RWread (f, value, 1, 3);
|
|
while (count--) {
|
|
b[2] = value[0];
|
|
b[1] = value[1];
|
|
b[0] = value[2];
|
|
b += 3;
|
|
}
|
|
}
|
|
else {
|
|
count++;
|
|
c += count;
|
|
while (count--) {
|
|
MGUI_RWread (f, value, 1, 3);
|
|
b[2] = value[0];
|
|
b[1] = value[1];
|
|
b[0] = value[2];
|
|
b += 3;
|
|
}
|
|
}
|
|
} while (!MGUI_RWeof (f) && c < len);
|
|
}
|
|
|
|
|
|
|
|
/* rle_tga_read16:
|
|
* Helper for reading 16 bit RLE data from TGA files.
|
|
*/
|
|
static void rle_tga_read16(unsigned short *b, int len, MG_RWops *f)
|
|
{
|
|
unsigned int value;
|
|
unsigned short color;
|
|
int count;
|
|
int c = 0;
|
|
|
|
do {
|
|
count = fp_getc(f);
|
|
if (count & 0x80) {
|
|
count = (count & 0x7F) + 1;
|
|
c += count;
|
|
value = fp_igetw(f);
|
|
color = value;
|
|
while (count--)
|
|
*(b++) = color;
|
|
}
|
|
else {
|
|
count++;
|
|
c += count;
|
|
while (count--) {
|
|
value = fp_igetw(f);
|
|
color = value;
|
|
*(b++) = color;
|
|
}
|
|
}
|
|
} while (!MGUI_RWeof (f) && c < len);
|
|
}
|
|
|
|
|
|
|
|
/* __mg_init_tga:
|
|
* inits a 256 color or 24 bit uncompressed TGA file, returning a bitmap
|
|
* structure and storing the palette data in the specified palette (this
|
|
* should be an array of at least 256 RGB structures).
|
|
*/
|
|
typedef struct {
|
|
int compressed;
|
|
unsigned char image_type;
|
|
} tga_init_info_t;
|
|
|
|
void * __mg_init_tga (MG_RWops* f, MYBITMAP* bmp, RGB *pal)
|
|
{
|
|
unsigned char image_id[256], image_palette[256][3];
|
|
unsigned char id_length, palette_type, image_type, palette_entry_size;
|
|
unsigned char bpp, descriptor_bits;
|
|
short unsigned int first_color, palette_colors;
|
|
short unsigned int left, top, image_width, image_height;
|
|
unsigned int i;//, x, y;
|
|
// unsigned short *s;
|
|
int compressed;
|
|
int pitch, bytes_per_pixel;
|
|
unsigned int size;
|
|
unsigned char* bits;
|
|
tga_init_info_t * tga_info=NULL;
|
|
tga_info=(tga_init_info_t *)malloc(sizeof(tga_init_info_t));
|
|
if(!tga_info)
|
|
return NULL;
|
|
id_length = fp_getc(f);
|
|
palette_type = fp_getc(f);
|
|
image_type = fp_getc(f);
|
|
first_color = fp_igetw(f);
|
|
palette_colors = fp_igetw(f);
|
|
palette_entry_size = fp_getc(f);
|
|
left = fp_igetw(f);
|
|
top = fp_igetw(f);
|
|
image_width = fp_igetw(f);
|
|
image_height = fp_igetw(f);
|
|
bpp = fp_getc(f);
|
|
descriptor_bits = fp_getc(f);
|
|
|
|
MGUI_RWread (f, image_id, 1, id_length);
|
|
image_id [id_length - 1] = '\0';
|
|
#if 0
|
|
fprintf (stderr, "TGA image id: %s, bpp: %d, colors: %d\n", image_id, bpp, palette_colors);
|
|
#endif
|
|
|
|
MGUI_RWread (f, image_palette, 1, palette_colors*3);
|
|
|
|
/* Image type:
|
|
* 0 = no image data
|
|
* 1 = uncompressed color mapped
|
|
* 2 = uncompressed true color
|
|
* 3 = grayscale
|
|
* 9 = RLE color mapped
|
|
* 10 = RLE true color
|
|
* 11 = RLE grayscale
|
|
*/
|
|
compressed = (image_type & 8);
|
|
tga_info->compressed=compressed;
|
|
image_type &= 7;
|
|
tga_info->image_type=image_type;
|
|
|
|
if ((image_type < 1) || (image_type > 3)) {
|
|
return NULL;//ERR_BMP_NOT_SUPPORTED;
|
|
}
|
|
|
|
switch (image_type) {
|
|
|
|
case 1:
|
|
/* paletted image */
|
|
if ((palette_type != 1) || (bpp != 8)) {
|
|
goto err;//ERR_BMP_NOT_SUPPORTED;
|
|
}
|
|
|
|
for(i=0; i<palette_colors; i++) {
|
|
pal[i].r = image_palette[i][2];
|
|
pal[i].g = image_palette[i][1];
|
|
pal[i].b = image_palette[i][0];
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
/* truecolor image */
|
|
if ((palette_type == 0)
|
|
&& ((bpp == 15) || (bpp == 16)
|
|
|| (bpp == 24) || (bpp == 32))) {
|
|
}
|
|
else {
|
|
goto err;//ERR_BMP_NOT_SUPPORTED;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
/* grayscale image */
|
|
if ((palette_type != 0) || (bpp != 8)) {
|
|
goto err;//ERR_BMP_NOT_SUPPORTED;
|
|
}
|
|
|
|
for (i=0; i<256; i++) {
|
|
pal[i].r = i;
|
|
pal[i].g = i;
|
|
pal[i].b = i;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
goto err;//ERR_BMP_NOT_SUPPORTED;
|
|
}
|
|
|
|
bytes_per_pixel = __mg_bmp_compute_pitch (bpp, image_width, &pitch, TRUE);
|
|
size = pitch * image_height;
|
|
// if( !(bits = malloc (size)) ) {
|
|
// goto err;
|
|
// }
|
|
|
|
bmp->flags = MYBMP_TYPE_RGB;
|
|
if (bpp == 24)
|
|
bmp->flags |= MYBMP_RGBSIZE_3;
|
|
else if (bpp == 32)
|
|
bmp->flags |= MYBMP_RGBSIZE_4;
|
|
|
|
if (descriptor_bits & 0x20)
|
|
bmp->flags |= MYBMP_FLOW_DOWN;
|
|
else
|
|
bmp->flags |= MYBMP_FLOW_UP;
|
|
|
|
bmp->depth = bpp;
|
|
bmp->w = image_width;
|
|
bmp->h = image_height;
|
|
bmp->pitch = (compressed) ? (image_width * bytes_per_pixel): pitch;
|
|
bmp->frames = 1;
|
|
bmp->size = size;
|
|
bmp->bits = bits;
|
|
return tga_info;
|
|
err:
|
|
free(tga_info);
|
|
return NULL;
|
|
}
|
|
void __mg_cleanup_tga (void * init_info)
|
|
{
|
|
if (init_info)
|
|
free(init_info);
|
|
init_info = NULL;
|
|
|
|
}
|
|
int __mg_load_tga (MG_RWops* f, void* init_info, MYBITMAP *bmp, CB_ONE_SCANLINE cb, void* context)
|
|
{
|
|
tga_init_info_t *info = (tga_init_info_t *)init_info;
|
|
int compressed,x,y;
|
|
unsigned char image_type,rgb[4];
|
|
BYTE * bits;
|
|
unsigned short *s;
|
|
// bmp->bits=malloc(bmp->size);
|
|
bits=bmp->bits;
|
|
compressed=info->compressed;
|
|
image_type=info->image_type;
|
|
// printf("compressed=%d image_type=%d bmp->depth=%d\n,bmp->w=%d bmp->h=%d\n",compressed,image_type,bmp->depth,bmp->w,bmp->h);
|
|
for (y=bmp->h;y;y--,bits +=bmp->pitch) {
|
|
switch (image_type) {
|
|
case 1:
|
|
case 3:
|
|
if (compressed) {
|
|
rle_tga_read(bmp->bits, bmp->w * bmp->h, f);
|
|
return ERR_BMP_OK;
|
|
}
|
|
else
|
|
MGUI_RWread (f, bmp->bits, 1, bmp->w);
|
|
break;
|
|
|
|
case 2:
|
|
if (bmp->depth == 32) {
|
|
if (compressed) {
|
|
rle_tga_read32(bmp->bits, bmp->w * bmp->h, f);
|
|
return ERR_BMP_OK;
|
|
}
|
|
else {
|
|
for (x=0; x<bmp->w; x++) {
|
|
MGUI_RWread (f, rgb, 1, 4);
|
|
bmp->bits[x*4+3] = rgb[3];
|
|
bmp->bits[x*4+2] = rgb[2];
|
|
bmp->bits[x*4+1] = rgb[1];
|
|
bmp->bits[x*4+0] = rgb[0];
|
|
}
|
|
}
|
|
}
|
|
else if (bmp->depth == 24) {
|
|
if (compressed) {
|
|
rle_tga_read24(bmp->bits, bmp->w * bmp->h, f);
|
|
return ERR_BMP_OK;
|
|
}
|
|
else {
|
|
for (x=0; x<bmp->w; x++) {
|
|
MGUI_RWread (f, rgb, 1, 3);
|
|
bmp->bits[x*3+2] = rgb[2];
|
|
bmp->bits[x*3+1] = rgb[1];
|
|
bmp->bits[x*3+0] = rgb[0];
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (compressed) {
|
|
rle_tga_read16((unsigned short *)bmp->bits, bmp->w * bmp->h, f);
|
|
return ERR_BMP_OK;
|
|
}
|
|
else {
|
|
s = (unsigned short *)bmp->bits;
|
|
for (x=0; x<bmp->w; x++) {
|
|
s [x] = fp_igetw(f);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// printf("y=%d\n",y);
|
|
if (cb ) cb(context, bmp, y);
|
|
}
|
|
|
|
#if 0
|
|
if (bpp == 8) { /* look for a 256 color palette */
|
|
while (!MGUI_RWeof(f)) {
|
|
if (fp_getc(f)==12) {
|
|
for (c=0; c<256; c++) {
|
|
pal[c].r = fp_getc(f);
|
|
pal[c].g = fp_getc(f);
|
|
pal[c].b = fp_getc(f);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
// free(bmp->bits);
|
|
return ERR_BMP_OK;
|
|
}
|
|
|
|
|
|
#if 0
|
|
/* save_tga:
|
|
* Writes a bitmap into a TGA file, using the specified palette (this
|
|
* should be an array of at least 256 RGB structures).
|
|
*/
|
|
int save_tga(char *filename, BITMAP *bmp, RGB *pal)
|
|
{
|
|
unsigned char image_palette[256][3];
|
|
int x, y, c, r, g, b;
|
|
int depth;
|
|
FILE *f;
|
|
PALETTE tmppal;
|
|
|
|
if (!pal) {
|
|
get_palette(tmppal);
|
|
pal = tmppal;
|
|
}
|
|
|
|
depth = bitmap_color_depth(bmp);
|
|
|
|
if (depth == 15)
|
|
depth = 16;
|
|
|
|
f = fp_fopen(filename, F_WRITE);
|
|
if (!f)
|
|
return *allegro_errno;
|
|
|
|
fp_putc(0, f); /* id length (no id saved) */
|
|
fp_putc((depth == 8) ? 1 : 0, f); /* palette type */
|
|
fp_putc((depth == 8) ? 1 : 2, f); /* image type */
|
|
fp_iputw(0, f); /* first colour */
|
|
fp_iputw((depth == 8) ? 256 : 0, f); /* number of colours */
|
|
fp_putc((depth == 8) ? 24 : 0, f); /* palette entry size */
|
|
fp_iputw(0, f); /* left */
|
|
fp_iputw(0, f); /* top */
|
|
fp_iputw(bmp->w, f); /* width */
|
|
fp_iputw(bmp->h, f); /* height */
|
|
fp_putc(depth, f); /* bits per pixel */
|
|
fp_putc(0, f); /* descriptor (bottom to top) */
|
|
|
|
if (depth == 8) {
|
|
for (y=0; y<256; y++) {
|
|
image_palette[y][2] = _rgb_scale_6[pal[y].r];
|
|
image_palette[y][1] = _rgb_scale_6[pal[y].g];
|
|
image_palette[y][0] = _rgb_scale_6[pal[y].b];
|
|
}
|
|
|
|
fp_fwrite(image_palette, 768, f);
|
|
}
|
|
|
|
switch (bitmap_color_depth(bmp)) {
|
|
|
|
#ifdef ALLEGRO_COLOR8
|
|
|
|
case 8:
|
|
for (y=bmp->h; y; y--)
|
|
for (x=0; x<bmp->w; x++)
|
|
fp_putc(getpixel(bmp, x, y-1), f);
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef ALLEGRO_COLOR16
|
|
|
|
case 15:
|
|
for (y=bmp->h; y; y--) {
|
|
for (x=0; x<bmp->w; x++) {
|
|
c = getpixel(bmp, x, y-1);
|
|
r = getr15(c);
|
|
g = getg15(c);
|
|
b = getb15(c);
|
|
c = ((r<<7)&0x7C00) | ((g<<2)&0x3E0) | ((b>>3)&0x1F);
|
|
fp_iputw(c, f);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
for (y=bmp->h; y; y--) {
|
|
for (x=0; x<bmp->w; x++) {
|
|
c = getpixel(bmp, x, y-1);
|
|
r = getr16(c);
|
|
g = getg16(c);
|
|
b = getb16(c);
|
|
c = ((r<<7)&0x7C00) | ((g<<2)&0x3E0) | ((b>>3)&0x1F);
|
|
fp_iputw(c, f);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef ALLEGRO_COLOR24
|
|
|
|
case 24:
|
|
for (y=bmp->h; y; y--) {
|
|
for (x=0; x<bmp->w; x++) {
|
|
c = getpixel(bmp, x, y-1);
|
|
fp_putc(getb24(c), f);
|
|
fp_putc(getg24(c), f);
|
|
fp_putc(getr24(c), f);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef ALLEGRO_COLOR32
|
|
|
|
case 32:
|
|
for (y=bmp->h; y; y--) {
|
|
for (x=0; x<bmp->w; x++) {
|
|
c = getpixel(bmp, x, y-1);
|
|
fp_putc(getb32(c), f);
|
|
fp_putc(getg32(c), f);
|
|
fp_putc(getr32(c), f);
|
|
fp_putc(geta32(c), f);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#endif
|
|
}
|
|
|
|
fp_fclose(f);
|
|
return *allegro_errno;
|
|
}
|
|
#endif
|
|
|
|
#endif /* _MGIMAGE_TGA */
|
|
|