--- psiconv/trunk/lib/psiconv/parse_image.c 2003/11/27 20:55:01 175 +++ psiconv/trunk/lib/psiconv/parse_image.c 2004/02/04 12:19:09 196 @@ -1,6 +1,6 @@ /* parse_image.c - Part of psiconv, a PSION 5 file formats converter - Copyright (c) 1999, 2000 Frodo Looijaard + Copyright (c) 1999-2004 Frodo Looijaard 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 @@ -24,11 +24,47 @@ #include "parse_routines.h" #include "error.h" +#include "image.h" #ifdef DMALLOC #include #endif +static int psiconv_decode_rle8 (const psiconv_config config, int lev, + psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded); + +static int psiconv_decode_rle12 (const psiconv_config config, int lev, + psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded); + +static int psiconv_decode_rle16 (const psiconv_config config, int lev, + psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded); + +static int psiconv_decode_rle24 (const psiconv_config config, int lev, + psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded); + +static int psiconv_bytes_to_pixel_data(const psiconv_config config, + int lev, psiconv_u32 off, + const psiconv_pixel_bytes bytes, + psiconv_pixel_ints *pixels, + int colordepth, int xsize, int ysize); + +static int psiconv_pixel_data_to_floats (const psiconv_config config, int lev, + psiconv_u32 off, + const psiconv_pixel_ints pixels, + psiconv_pixel_floats_t *floats, + int colordepth, int color, + int redbits, int bluebits, int greenbits, + const psiconv_pixel_floats_t palet); + + int psiconv_parse_jumptable_section(const psiconv_config config, const psiconv_buffer buf,int lev, @@ -73,7 +109,7 @@ ERROR2: psiconv_list_free(*result); ERROR1: - psiconv_warn(config,lev+1,off,"Reading of Jumptable Section failed"); + psiconv_error(config,lev+1,off,"Reading of Jumptable Section failed"); if (length) *length = 0; if (!res) @@ -82,41 +118,6 @@ return res; } -static int decode_byte(const psiconv_config config, int lev, psiconv_u32 off, - psiconv_paint_data_section data, psiconv_u32 *pixelnr, - psiconv_u8 byte, int bits_per_pixel, int linelen, - int *linepos,int picsize) -{ - int mask = (bits_per_pixel << 1) -1; - int i; - if (*linepos < (data->xsize + (8/bits_per_pixel) - 1) / (8/bits_per_pixel)) - for (i = 0; i < 8/bits_per_pixel; i ++) { - if ((i != 0) && ((*pixelnr % (data->xsize)) == 0)) { - psiconv_debug(config,lev+1,off,"Skipping padding: %02x",byte); - i = 8; - } else if (*pixelnr >= picsize) { - psiconv_warn(config,lev+1,off,"Corrupted picture data!"); - psiconv_debug(config,lev+1,off,"Trying to write a pixel too far"); - return -1; - } else { - data->red[*pixelnr] = data->green[*pixelnr] = data->blue[*pixelnr] = - ((float) (byte & mask)) / ((1 << bits_per_pixel) -1); - psiconv_debug(config,lev+1,off,"Pixel %04x: (%04x,%04x) value %02x, color %f", - *pixelnr,*pixelnr % data->xsize, - *pixelnr / data->xsize, byte&mask, data->red[*pixelnr]); - byte = byte >> bits_per_pixel; - (*pixelnr) ++; - } - } - else - psiconv_debug(config,lev+1,off,"Skipping padding byte"); - (*linepos) ++; - if (*linepos == linelen) - *linepos = 0; - return 0; -} - - int psiconv_parse_paint_data_section(const psiconv_config config, const psiconv_buffer buf,int lev, psiconv_u32 off, int *length,int isclipart, @@ -124,29 +125,35 @@ { int res = 0; int len = 0; - psiconv_u32 size,offset,picsize,temp,datasize,pixelnr,datanr,linelen; - psiconv_u8 marker; - int i,leng; + psiconv_u32 size,offset,picsize,temp,datasize,color, + redbits,bluebits,greenbits; + psiconv_u8 byte; + int leng,i; psiconv_u32 bits_per_pixel,compression; - int linepos = 0; + psiconv_pixel_bytes bytes,decoded; + psiconv_pixel_ints pixels; + psiconv_pixel_floats_t floats,palet; psiconv_progress(config,lev+1,off,"Going to read a paint data section"); if (!((*result) = malloc(sizeof(**result)))) goto ERROR1; + if (!(bytes = psiconv_list_new(sizeof(psiconv_u8)))) + goto ERROR2; + psiconv_progress(config,lev+2,off+len,"Going to read section size"); size = psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; + goto ERROR3; psiconv_debug(config,lev+2,off+len,"Section size: %08x",size); len += 4; psiconv_progress(config,lev+2,off+len,"Going to read pixel data offset"); offset = psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; + goto ERROR3; if (offset != 0x28) { - psiconv_warn(config,lev+2,off+len, + psiconv_error(config,lev+2,off+len, "Paint data section data offset has unexpected value"); psiconv_debug(config,lev+2,off+len, "Data offset: read %08x, expected %08x",offset,0x28); @@ -157,14 +164,14 @@ psiconv_progress(config,lev+2,off+len,"Going to read picture X size"); (*result)->xsize = psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; + goto ERROR3; psiconv_debug(config,lev+2,off+len,"Picture X size: %08x:",(*result)->xsize); len += 4; psiconv_progress(config,lev+2,off+len,"Going to read picture Y size"); (*result)->ysize = psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; + goto ERROR3; psiconv_debug(config,lev+2,off+len,"Picture Y size: %08x:",(*result)->ysize); len += 4; @@ -173,215 +180,189 @@ psiconv_progress(config,lev+2,off+len,"Going to read the real picture x size"); (*result)->pic_xsize = psiconv_read_length(config,buf,lev+2,off+len,&leng,&res); if (res) - goto ERROR2; + goto ERROR3; psiconv_debug(config,lev+2,off+len,"Picture x size: %f",(*result)->pic_xsize); len += leng; psiconv_progress(config,lev+2,off+len,"Going to read the real picture y size"); (*result)->pic_ysize = psiconv_read_length(config,buf,lev+2,off+len,&leng,&res); if (res) - goto ERROR2; + goto ERROR3; psiconv_debug(config,lev+2,off+len,"Picture y size: %f",(*result)->pic_ysize); len += leng; psiconv_progress(config,lev+2,off+len,"Going to read the number of bits per pixel"); bits_per_pixel=psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; - if (bits_per_pixel > 8) { - psiconv_warn(config,lev+2,off+len,"Picture has too many colors"); - psiconv_debug(config,lev+2,off+len,"Read %d colorbits",bits_per_pixel); - res = -PSICONV_E_PARSE; - goto ERROR2; - } + goto ERROR3; psiconv_debug(config,lev+2,off+len,"Bits per pixel: %d",bits_per_pixel); len += 4; - for (i = 0 ; i < 2; i++) { - temp = psiconv_read_u32(config,buf,lev+2,off+len,&res); - if (res) - goto ERROR2; - if (temp != 00) { - psiconv_warn(config,lev+2,off+len, - "Paint data section prologue has unknown values (ignored)"); - psiconv_debug(config,lev+2,off+len, - "offset %02x: read %08x, expected %08x",i,temp, 0x00); - } - len += 4; + psiconv_progress(config,lev+2,off+len, + "Going to read whether this is a colour or greyscale picture"); + color = psiconv_read_u32(config,buf,lev+2,off+len,&res); + if (res) + goto ERROR3; + if ((color != 0) && (color != 1)) { + psiconv_warn(config,lev+2,off+len, + "Paint data section unknown color type (ignored)"); + psiconv_debug(config,lev+2,off+len, + "Color: read %08x, expected %08x or %08x",color,0,1); + color = 1; + } else { + psiconv_debug(config,lev+2,off+len,"Color: %08x (%s picture)", + color,(color?"color":"greyscale")); + } + len += 4; + + temp = psiconv_read_u32(config,buf,lev+2,off+len,&res); + if (res) + goto ERROR3; + if (temp != 00) { + psiconv_warn(config,lev+2,off+len, + "Paint data section prologue has unknown values (ignored)"); + psiconv_debug(config,lev+2,off+len, + "read %08x, expected %08x",temp, 0x00); } + len += 4; psiconv_progress(config,lev+2,off+len, "Going to read whether RLE compression is used"); compression=psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; - if (compression > 1) { + goto ERROR3; + if (compression > 4) { psiconv_warn(config,lev+2,off+len,"Paint data section has unknown " "compression type, assuming RLE"); psiconv_debug(config,lev+2,off+len,"Read compression type %d",compression); - compression = 1; + compression = 0; } - psiconv_debug(config,lev+2,off+len,"Compression: %s",compression?"RLE8":"none"); + psiconv_debug(config,lev+2,off+len,"Compression: %s", + compression == 4?"RLE24":compression == 3?"RLE16": + compression == 2?"RLE12":compression == 1?"RLE8":"none"); len += 4; if (isclipart) { psiconv_progress(config,lev+2,off+len,"Going to read an unknown long"); temp = psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; + goto ERROR3; if (temp != 0xffffffff) { psiconv_warn(config,lev+2,off+len, "Paint data section prologue has unknown values (ignoring)"); psiconv_debug(config,lev+2,off+len, - "offset %02x: read %08x, expected %08x",i,temp, 0xffffffff); + "Read %08x, expected %08x",temp, 0xffffffff); } len += 4; psiconv_progress(config,lev+2,off+len,"Going to read a second unknown long"); temp = psiconv_read_u32(config,buf,lev+2,off+len,&res); if (res) - goto ERROR2; + goto ERROR3; if (temp != 0x44) { psiconv_warn(config,lev+2,off+len, "Paint data section prologue has unknown values (ignoring)"); psiconv_debug(config,lev+2,off+len, - "offset %02x: read %08x, expected %08x",i,temp, 0x44); + "read %08x, expected %08x",temp, 0x44); } len += 4; } - if (!((*result)->red = malloc(sizeof(float) * picsize))) - goto ERROR2; - if (!((*result)->green = malloc(sizeof(float) * picsize))) - goto ERROR3; - if (!((*result)->blue = malloc(sizeof(float) * picsize))) - goto ERROR4; len = offset; datasize = size - len; if (isclipart) len += 8; + if (color || (bits_per_pixel != 2)) + psiconv_warn(config,lev+2,off+len, + "All image types except 2-bit greyscale are experimental!"); + psiconv_progress(config,lev+2,off+len,"Going to read the pixel data"); - pixelnr = 0; - datanr = 0; - if (!compression) { - linelen = datasize / (*result)->ysize; - psiconv_debug(config,lev+3,off+len,"Line length: %04x bytes",linelen); - while((datanr < datasize)) { - temp = psiconv_read_u8(config,buf,lev+2,off+len+datanr,&res); - if (res) - goto ERROR5; - if (decode_byte(config,lev+3,off+len+datanr,*result,&pixelnr,temp,bits_per_pixel, - linelen,&linepos,picsize)) { - res = -PSICONV_E_PARSE; - break; - } - datanr++; - } - } else { - psiconv_progress(config,lev+2,off+len,"First pass: determining line length"); - datanr = 0; - i = 0; - while (datanr < datasize) { - marker = psiconv_read_u8(config,buf,lev+3,off+len+datanr,&res); - if (res) - goto ERROR5; - if (marker >= 0x80) { - datanr += 0x100 - marker + 1; - i += 0x100 - marker; - } else { - datanr += 2; - i += marker + 1; - } - } - linelen = i / (*result)->ysize; - datanr=0; - psiconv_debug(config,lev+2,off+len,"Linelen: %04x bytes",linelen); - while((datanr < datasize)) { - marker = psiconv_read_u8(config,buf,lev+3,off+len+datanr,&res); - if (res) - goto ERROR5; - psiconv_debug(config,lev+3,off+len+datanr, - "Pixelnr %08x, Datanr %08x: Read marker %02x", - pixelnr,datanr,marker); - datanr ++; - if (marker >= 0x80) { - /* 0x100 - marker bytes of data follow */ - for (i = 0; i < 0x100-marker; i++,datanr++) { - if (datanr >= datasize) { - psiconv_warn(config,lev+3,off+len+datanr,"Corrupted picture data"); - psiconv_debug(config,lev+3,off+len+datanr, - "Picsize: %08x, Datasize: %08x, Pixelnr: %08x," - "Datanr: %08x, marker: %02x",picsize,datasize,pixelnr, - datanr,marker); - res = -PSICONV_E_PARSE; - break; - } - temp = psiconv_read_u8(config,buf,lev+2,off+len+datanr,&res); - if (res) - goto ERROR5; - if (decode_byte(config,lev+2,off+len+datanr,*result,&pixelnr,temp, - bits_per_pixel,linelen,&linepos,picsize)) { - res = -PSICONV_E_PARSE; - break; - } - } - } else { - if (datanr >= datasize) { - psiconv_warn(config,lev+3,off+len+datanr,"Corrupted picture data"); - psiconv_debug(config,lev+3,off+len+datanr, - "Picsize: %08x, Datasize: %08x, Pixelnr: %08x," - "Datanr: %08x, marker: %02x",picsize,datasize,pixelnr, - datanr,marker); - res = -PSICONV_E_PARSE; - } else { - temp = psiconv_read_u8(config,buf,lev+3,off+len+datanr,&res); - if (res) - goto ERROR5; - for (i = 0; i <= marker; i++) { - if (decode_byte(config,lev+2,off+len+datanr,*result,&pixelnr,temp, - bits_per_pixel,linelen,&linepos,picsize)) { - res = -PSICONV_E_PARSE; - break; - } - } - datanr ++; - } - } - } + for (i = 0; i < datasize; i++) { + byte = psiconv_read_u8(config,buf,lev+2,off+len+i,&res); + psiconv_debug(config,lev+2,off+len+i, + "Pixel byte %04x of %04x has value %02x", + i,datasize,byte); + if (res) + goto ERROR3; + psiconv_list_add(bytes,&byte); } + len += datasize; - if (linepos >= ((*result)->xsize + (8/bits_per_pixel) - 1) / - (8/bits_per_pixel)) - datanr += (linelen - linepos); - - if (res || (datanr != datasize) || (pixelnr != picsize)) { - psiconv_warn(config,lev+2,off+len,"Corrupted picture data!"); - psiconv_debug(config,lev+3,off+len+datanr, - "Picsize: %08x, Datasize: %08x, Pixelnr: %08x," - "Datanr: %08x",picsize,datasize,pixelnr,datanr); - goto ERROR5; + switch(compression) { + case 1: + if ((res = psiconv_decode_rle8(config,lev+2,off+len,bytes,&decoded))) + goto ERROR3; + psiconv_list_free(bytes); + bytes = decoded; + break; + case 2: + if ((psiconv_decode_rle12(config,lev+2,off+len,bytes,&decoded))) + goto ERROR3; + psiconv_list_free(bytes); + bytes = decoded; + break; + case 3: + if ((psiconv_decode_rle16(config,lev+2,off+len,bytes,&decoded))) + goto ERROR3; + psiconv_list_free(bytes); + bytes = decoded; + break; + case 4: + if ((psiconv_decode_rle24(config,lev+2,off+len,bytes,&decoded))) + goto ERROR3; + psiconv_list_free(bytes); + bytes = decoded; + break; + } + + if ((res = psiconv_bytes_to_pixel_data(config,lev+2,off+len,bytes, + &pixels,bits_per_pixel, + (*result)->xsize,(*result)->ysize))) + goto ERROR3; + + /* Use some heuristics; things may get unexpected around here */ + bluebits = redbits = greenbits = 0; + palet = psiconv_palet_none; + if (color) { + if (bits_per_pixel == 4) + palet = psiconv_palet_color_4; + else if (bits_per_pixel == 8) + palet = psiconv_palet_color_8; + else { + redbits = (bits_per_pixel+2) / 3; + greenbits = (bits_per_pixel+2) / 3; + bluebits = bits_per_pixel - redbits - greenbits; + } } + if ((res = psiconv_pixel_data_to_floats(config,lev+2,off+len,pixels, + &floats,bits_per_pixel,color, + redbits,greenbits,bluebits,palet))) + goto ERROR4; + + (*result)->red = floats.red; + (*result)->green = floats.green; + (*result)->blue = floats.blue; + + psiconv_list_free(bytes); + psiconv_list_free(pixels); - len += datanr; if (length) *length = len; - psiconv_progress(config,lev+1,off+len-1,"End of paint data section " - "(total length: %08x)", len); + psiconv_progress(config,lev,off+len-1, + "End of Paint Data Section (total length: %08x)", len); - return res; + return 0; -ERROR5: - free((*result)->blue); ERROR4: - free((*result)->green); + psiconv_list_free(pixels); ERROR3: - free((*result)->red); + psiconv_list_free(bytes); ERROR2: - free (*result); + free(*result); ERROR1: - psiconv_warn(config,lev+1,off,"Reading of Paint Data Section failed"); + psiconv_error(config,lev+1,off,"Reading of Paint Data Section failed"); if (length) *length = 0; if (!res) @@ -546,7 +527,7 @@ ERROR2: free (*result); ERROR1: - psiconv_warn(config,lev+1,off,"Reading of Sketch Section failed"); + psiconv_error(config,lev+1,off,"Reading of Sketch Section failed"); if (length) *length = 0; if (!res) @@ -649,7 +630,7 @@ ERROR2: free (*result); ERROR1: - psiconv_warn(config,lev+1,off,"Reading of Font failed"); + psiconv_error(config,lev+1,off,"Reading of Font failed"); if (length) *length = 0; if (!res) @@ -657,3 +638,385 @@ else return res; } + +int psiconv_decode_rle8 (const psiconv_config config, int lev, psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded) +{ + int res=0; + psiconv_u8 *marker,*value; + int i,j; + + psiconv_progress(config,lev+1,off,"Going to decode the RLE8 encoding"); + if (!(*decoded = psiconv_list_new(sizeof(psiconv_u8)))) + goto ERROR1; + + for (i = 0; i < psiconv_list_length(encoded);) { + psiconv_progress(config,lev+2,off,"Going to read marker byte at %04x",i); + if (!(marker = psiconv_list_get(encoded,i))) + goto ERROR2; + psiconv_debug(config,lev+2,off,"Marker byte: %02x",*marker); + if (*marker < 0x80) { + psiconv_debug(config,lev+2,off,"Marker: repeat value byte %02x times", + *marker+1); + psiconv_progress(config,lev+2,off,"Going to read value byte at %04x",i+1); + if (!(value = psiconv_list_get(encoded,i+1))) + goto ERROR2; + psiconv_debug(config,lev+2,off,"Value byte: %02x",*value); + psiconv_progress(config,lev+2,off,"Adding %02x pixels %02x", + *marker+1,*value); + for (j = 0; j < *marker + 1; j++) + if ((res = psiconv_list_add(*decoded,value))) + goto ERROR2; + i += 2; + } else { + psiconv_debug(config,lev+2,off,"Marker: %02x value bytes follow", + 0x100 - *marker); + for (j = 0; j < (0x100 - *marker); j++) { + psiconv_progress(config,lev+2,off,"Going to read value byte at %04x", + i+j+1); + if (!(value = psiconv_list_get(encoded,i+j+1))) + goto ERROR2; + psiconv_debug(config,lev+2,off,"Value: %02x",*value); + if ((res = psiconv_list_add(*decoded,value))) + goto ERROR2; + } + i += (0x100 - *marker) + 1; + } + } + psiconv_progress(config,lev,off, + "End of RLE8 decoding process"); + return 0; + +ERROR2: + psiconv_list_free(*decoded); +ERROR1: + psiconv_error(config,lev+1,off,"Decoding of RLE8 failed"); + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + +int psiconv_decode_rle12 (const psiconv_config config, int lev, psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded) +{ + int res=0; + psiconv_u8 *value0,*value1; + psiconv_u32 value,repeat; + int i,j; + + psiconv_progress(config,lev+1,off,"Going to decode the RLE12 encoding"); + if (!(*decoded = psiconv_list_new(sizeof(psiconv_u8)))) + goto ERROR1; + + for (i = 0; i < psiconv_list_length(encoded);) { + psiconv_progress(config,lev+2,off,"Going to read data word at %04x",i); + if (!(value0 = psiconv_list_get(encoded,i))) + goto ERROR2; + if (!(value1 = psiconv_list_get(encoded,i+1))) + goto ERROR2; + psiconv_debug(config,lev+2,off,"Data Word: %04x",*value0 + (*value1 << 8)); + value = *value0 + ((*value1 & 0x0f) << 8); + repeat = (*value1 >> 4) + 1; + psiconv_progress(config,lev+2,off,"Adding %02x pixels %03x", + repeat,value); + for (j = 0; j < repeat; j ++) + if ((res = psiconv_list_add(*decoded,&value))) + goto ERROR2; + i += 2; + } + psiconv_progress(config,lev,off, + "End of RLE12 decoding process"); + return 0; + +ERROR2: + psiconv_list_free(*decoded); +ERROR1: + psiconv_error(config,lev+1,off,"Decoding of RLE12 failed"); + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + +int psiconv_decode_rle16 (const psiconv_config config, int lev, psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded) +{ + int res=0; + psiconv_u8 *marker,*value0,*value1; + psiconv_u32 value; + int i,j; + + psiconv_progress(config,lev+1,off,"Going to decode the RLE16 encoding"); + if (!(*decoded = psiconv_list_new(sizeof(psiconv_u8)))) + goto ERROR1; + + for (i = 0; i < psiconv_list_length(encoded);) { + psiconv_progress(config,lev+2,off,"Going to read marker byte at %04x",i); + if (!(marker = psiconv_list_get(encoded,i))) + goto ERROR2; + psiconv_debug(config,lev+2,off,"Marker byte: %02x",*marker); + if (*marker < 0x80) { + psiconv_debug(config,lev+2,off,"Marker: repeat value word %02x times", + *marker+1); + psiconv_progress(config,lev+2,off,"Going to read value word at %04x",i+1); + if (!(value0 = psiconv_list_get(encoded,i+1))) + goto ERROR2; + if (!(value1 = psiconv_list_get(encoded,i+2))) + goto ERROR2; + value = *value0 + (*value1 << 8); + psiconv_debug(config,lev+2,off,"Value word: %02x",value); + psiconv_progress(config,lev+2,off,"Adding %02x pixels %04x", + *marker+1,value); + for (j = 0; j < *marker + 1; j++) + if ((res = psiconv_list_add(*decoded,&value))) + goto ERROR2; + i += 3; + } else { + psiconv_debug(config,lev+2,off,"Marker: %02x value words follow", + 0x100 - *marker); + for (j = 0; j < (0x100 - *marker); j++) { + psiconv_progress(config,lev+2,off,"Going to read value word at %04x", + i+j*2+1); + if (!(value0 = psiconv_list_get(encoded,i+j*2+1))) + goto ERROR2; + if (!(value1 = psiconv_list_get(encoded,i+j*2+2))) + goto ERROR2; + value = *value0 + (*value1 << 8); + psiconv_debug(config,lev+2,off,"Value: %04x",value); + if ((res = psiconv_list_add(*decoded,&value))) + goto ERROR2; + } + i += (0x100 - *marker)*2 + 1; + } + } + psiconv_progress(config,lev,off, + "End of RLE16 decoding process"); + return 0; + +ERROR2: + psiconv_list_free(*decoded); +ERROR1: + psiconv_error(config,lev+1,off,"Decoding of RLE16 failed"); + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + +int psiconv_decode_rle24 (const psiconv_config config, int lev, psiconv_u32 off, + const psiconv_pixel_bytes encoded, + psiconv_pixel_bytes *decoded) +{ + int res=0; + psiconv_u8 *marker,*value0,*value1,*value2; + psiconv_u32 value; + int i,j; + + psiconv_progress(config,lev+1,off,"Going to decode the RLE24 encoding"); + if (!(*decoded = psiconv_list_new(sizeof(psiconv_u8)))) + goto ERROR1; + + for (i = 0; i < psiconv_list_length(encoded);) { + psiconv_progress(config,lev+2,off,"Going to read marker byte at %04x",i); + if (!(marker = psiconv_list_get(encoded,i))) + goto ERROR2; + psiconv_debug(config,lev+2,off,"Marker byte: %02x",*marker); + if (*marker < 0x80) { + psiconv_debug(config,lev+2,off,"Marker: repeat value byte triplet %02x times", + *marker+1); + psiconv_progress(config,lev+2,off,"Going to read value byte triplet at %04x",i+1); + if (!(value0 = psiconv_list_get(encoded,i+1))) + goto ERROR2; + if (!(value1 = psiconv_list_get(encoded,i+2))) + goto ERROR2; + if (!(value2 = psiconv_list_get(encoded,i+3))) + goto ERROR2; + value = *value0 + (*value1 << 8) + (*value2 << 16); + psiconv_debug(config,lev+2,off,"Value byte triplet: %06x",value); + psiconv_progress(config,lev+2,off,"Adding %02x pixels %06x", + *marker+1,value); + for (j = 0; j < *marker + 1; j++) + if ((res = psiconv_list_add(*decoded,&value))) + goto ERROR2; + i += 4; + } else { + psiconv_debug(config,lev+2,off,"Marker: %02x value byte triplets follow", + 0x100 - *marker); + for (j = 0; j < (0x100 - *marker); j++) { + psiconv_progress(config,lev+2,off,"Going to read value byte triplets at %04x", + i+j*3+1); + if (!(value0 = psiconv_list_get(encoded,i+j*3+1))) + goto ERROR2; + if (!(value1 = psiconv_list_get(encoded,i+j*3+2))) + goto ERROR2; + if (!(value2 = psiconv_list_get(encoded,i+j*3+3))) + goto ERROR2; + value = *value0 + (*value1 << 8) + (*value2 << 16); + psiconv_debug(config,lev+2,off,"Value: %06x",value); + if ((res = psiconv_list_add(*decoded,&value))) + goto ERROR2; + } + i += (0x100 - *marker)*3 + 1; + } + } + psiconv_progress(config,lev,off, + "End of RLE24 decoding process"); + return 0; + +ERROR2: + psiconv_list_free(*decoded); +ERROR1: + psiconv_error(config,lev+1,off,"Decoding of RLE24 failed"); + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + +int psiconv_bytes_to_pixel_data(const psiconv_config config, + int lev, psiconv_u32 off, + const psiconv_pixel_bytes bytes, + psiconv_pixel_ints *pixels, + int colordepth, int xsize, int ysize) +{ + int res=0; + int ibits,obits,x,y,bits; + psiconv_u8 input; + psiconv_u32 nr,output; + psiconv_u8 *ientry; + + psiconv_progress(config,lev+1,off,"Going to convert the bytes to pixels"); + if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) + goto ERROR1; + + nr = 0; + for (y = 0; y < ysize; y++) { + /* New lines will start at longs */ + while (nr % 4) + nr ++; + input = 0; + ibits = 0; + for (x= 0; x < xsize; x++) { + psiconv_progress(config,lev+2,off, + "Processing pixel at (x,y) = (%04x,%04x)",x,y); + output = 0; + obits = 0; + while (obits < colordepth) { + if (ibits == 0) { + psiconv_progress(config,lev+3,off, + "Going to read byte %08x",nr); + if (!(ientry = psiconv_list_get(bytes,nr))) + goto ERROR2; + psiconv_debug(config,lev+3,off,"Byte value: %02x",*ientry); + input = *ientry; + ibits = 8; + nr ++; + } + bits = ibits + obits > colordepth?colordepth-obits:ibits; + output = output << bits; + output |= input & ((1 << bits) - 1); + input = input >> bits; + ibits -= bits; + obits += bits; + } + psiconv_debug(config,lev+2,off,"Pixel value: %08x",output); + if ((res = psiconv_list_add(*pixels,&output))) + goto ERROR2; + } + } + + psiconv_progress(config,lev,off, + "Converting bytes to pixels completed"); + return 0; + + +ERROR2: + psiconv_list_free(*pixels); +ERROR1: + psiconv_error(config,lev+1,off,"Converting bytes to pixels failed"); + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + +int psiconv_pixel_data_to_floats (const psiconv_config config, int lev, + psiconv_u32 off, + const psiconv_pixel_ints pixels, + psiconv_pixel_floats_t *floats, + int colordepth, int color, + int redbits, int bluebits, int greenbits, + const psiconv_pixel_floats_t palet) +{ + int res = 0; + psiconv_u32 i; + psiconv_u32 *pixel; + + psiconv_progress(config,lev+1,off,"Going to convert pixels to floats"); + if (!((*floats).red = malloc(psiconv_list_length(pixels) * + sizeof(*(*floats).red)))) + goto ERROR1; + if (!((*floats).green = malloc(psiconv_list_length(pixels) * + sizeof(*(*floats).green)))) + goto ERROR2; + if (!((*floats).blue = malloc(psiconv_list_length(pixels) * + sizeof(*(*floats).blue)))) + goto ERROR3; + (*floats).length = psiconv_list_length(pixels); + + for (i = 0; i < psiconv_list_length(pixels); i++) { + if (!(pixel = psiconv_list_get(pixels,i))) + goto ERROR4; + psiconv_progress(config,lev+2,off, "Handling pixel %04x (%04x)",i,*pixel); + if (!palet.length) { + if (color) { + (*floats).blue[i] = ((float) (*pixel & ((1 << bluebits) - 1))) / + (1 << bluebits); + (*floats).green[i] = ((float) ((*pixel >> bluebits) & + ((1 << greenbits) - 1))) / (1 << greenbits); + (*floats).red[i] = ((float) ((*pixel >> (bluebits+greenbits)) & + ((1 << redbits) - 1))) / (1 << redbits); + } else { + (*floats).red[i] = (*floats).green[i] = + (*floats).blue[i] = ((float) *pixel) / + (1 << colordepth); + } + } else { + if (*pixel >= palet.length) { + psiconv_warn(config,lev+2,off, + "Invalid palet color found (using color 0x00)"); + (*floats).red[i] = palet.red[0]; + (*floats).green[i] = palet.green[0]; + (*floats).blue[i] = palet.blue[0]; + } else { + (*floats).red[i] = palet.red[*pixel]; + (*floats).green[i] = palet.green[*pixel]; + (*floats).blue[i] = palet.blue[*pixel]; + } + } + psiconv_debug(config,lev+2,off, "Pixel: Red (%f), green (%f), blue (%f)", + (*floats).red[i],(*floats).green[i],(*floats).blue[i]); + } + psiconv_progress(config,lev+1,off,"Finished converting pixels to floats"); + return 0; + +ERROR4: + free((*floats).blue); +ERROR3: + free((*floats).green); +ERROR2: + free((*floats).red); +ERROR1: + psiconv_error(config,lev+1,off,"Converting pixels to floats failed"); + if (!res) + return -PSICONV_E_NOMEM; + else + return res; +} + + +