--- psiconv/trunk/lib/psiconv/generate_image.c 2002/01/29 18:38:38 142 +++ psiconv/trunk/lib/psiconv/generate_image.c 2003/11/25 17:57:05 168 @@ -27,4 +27,205 @@ #include #endif +typedef psiconv_list psiconv_pixel_bytes; /* psiconv_u8 */ +typedef psiconv_list psiconv_pixel_ints; /* of psiconv_u32 */ + +typedef struct psiconv_pixel_float_s +{ + float *red; + float *green; + float *blue; +} psiconv_pixel_floats_t; + +static int psiconv_collect_pixel_data(const psiconv_config config, + psiconv_pixel_ints *pixels,int xsize, + int ysize, + const psiconv_pixel_floats_t data, + int colordepth, int palet_len, + const psiconv_pixel_floats_t palet); + +static int psiconv_pixel_data_to_bytes(const psiconv_config config, psiconv_pixel_bytes *bytes, int xsize, + int ysize, const psiconv_pixel_ints pixels, + int colordepth); + +float palet_grey_2_rgb[4] = {0.0/3, 1.0/3, 2.0/3, 3.0/3}; +float palet_grey_4_rgb[16] = { 0.0/15, 1.0/15, 2.0/15, 3.0/15, + 4.0/15, 5.0/15, 6.0/15, 7.0/15, + 8.0/15, 9.0/15, 10.0/15, 11.0/15, + 12.0/15, 13.0/15, 14.0/15, 15.0/15}; + +psiconv_pixel_floats_t palet_grey_2 = + { + (float *) palet_grey_2_rgb, + (float *) palet_grey_2_rgb, + (float *) palet_grey_2_rgb + }; + +psiconv_pixel_floats_t palet_grey_4 = + { + (float *) palet_grey_4_rgb, + (float *) palet_grey_4_rgb, + (float *) palet_grey_4_rgb + }; + + +/* For now, we only write 2-bit non-RLE-encoded stuff */ +int psiconv_write_paint_data_section(const psiconv_config config, + psiconv_buffer buf, + const psiconv_paint_data_section value) +{ + int res; + psiconv_buffer pix_buf; + + if (!value) { + psiconv_warn(config,0,psiconv_buffer_length(buf),"Null paint data section"); + res = -PSICONV_E_GENERATE; + goto ERROR1; + } + + if (!(pix_buf = psiconv_buffer_new())) { + res = -PSICONV_E_NOMEM; + goto ERROR1; + } + + return 0; + +ERROR2: + psiconv_buffer_free(pix_buf); +ERROR1: + return res; +} + +/* Translate the floating point RGB information into pixel values. + The palet is optional; without it, we just use the + colordepth. With a large palet this is not very fast, but it will do for + now. For greyscale pictures, just use the palet. */ +int psiconv_collect_pixel_data(const psiconv_config config, + psiconv_pixel_ints *pixels,int xsize,int ysize, + const psiconv_pixel_floats_t data, + int colordepth, int palet_len, + const psiconv_pixel_floats_t palet) +{ + int res,x,y,i; + psiconv_u32 index,mask,pixel; + float p_red,p_green,p_blue,mult,dist,new_dist; + + if (!(*pixels = psiconv_list_new(sizeof(psiconv_u32)))) { + res = -PSICONV_E_NOMEM; + goto ERROR1; + } + + mult = 1 << colordepth; + mask = mult -1; + for (y = 0; y < ysize; y++) { + for (x = 0; x < xsize; x++) { + index = y*ysize+x; + p_red = data.red[index]; + p_green = data.green[index]; + p_blue = data.blue[index]; + if (! palet_len) { + pixel = (((psiconv_u32) (p_red*mult) & mask) << (2*colordepth)) + + (((psiconv_u32) (p_green*mult) & mask) << colordepth) + + ((psiconv_u32) (p_blue*mult) & mask); + } else { + dist = 4; /* Max distance is 3, so this is safe */ + pixel = -1; + for (i = 0; i < palet_len; i++) { + new_dist = (p_red - palet.red[i]) * (p_red - palet.red[i]) + + (p_green - palet.green[i]) * (p_green - palet.green[i]) + + (p_blue - palet.blue[i]) * (p_blue - palet.blue[i]); + if (new_dist < dist) { + pixel = i; + dist = new_dist; + } + } + } + if ((res = psiconv_list_add(*pixels,&pixel))) + goto ERROR2; + } + } + return 0; + +ERROR2: + psiconv_list_free(*pixels); +ERROR1: + return res; +} + +int psiconv_pixel_data_to_bytes(const psiconv_config config, psiconv_pixel_bytes *bytes, int xsize, + int ysize, const psiconv_pixel_ints pixels, + int colordepth) +{ + int res; + int x,y; + + psiconv_u32 inputdata; + psiconv_u8 outputbyte; + psiconv_u32 *pixelptr; + int inputbitsleft,outputbitnr,bitsfit; + + + if (!bytes) { + psiconv_warn(config,0,0,"NULL pixel data"); + res = -PSICONV_E_GENERATE; + goto ERROR1; + } + if (!pixels) { + psiconv_warn(config,0,0,"NULL pixel data"); + res = -PSICONV_E_GENERATE; + goto ERROR1; + } + if (psiconv_list_length(pixels) != xsize * ysize) { + psiconv_warn(config,0,0,"Pixel number is not correct"); + res = -PSICONV_E_GENERATE; + goto ERROR1; + } + + if (!(*bytes = psiconv_list_new(sizeof(psiconv_u8)))) { + res = -PSICONV_E_NOMEM; + goto ERROR1; + } + + + outputbitnr = 0; + outputbyte = 0; + for (y = 0; y < ysize; y++) { + for (x = 0; x < xsize; x++) { + if (!(pixelptr = psiconv_list_get(pixels,y*xsize+x))) { + psiconv_warn(config,0,0,"Massive internal corruption"); + res = -PSICONV_E_NOMEM; + goto ERROR2; + } + inputbitsleft = colordepth; + inputdata = *pixelptr; + while (inputbitsleft) { + bitsfit = (inputbitsleft+outputbitnr<=8?inputbitsleft:8-outputbitnr); + outputbyte |= (inputdata & ((1 << bitsfit) - 1)) << outputbitnr; + inputdata = inputdata >> bitsfit; + inputbitsleft -= bitsfit; + outputbitnr += bitsfit; + if (outputbitnr == 8) { + if ((res = psiconv_list_add(*bytes,&outputbyte))) + goto ERROR2; + outputbitnr = 0; + outputbyte = 0; + } + } + } + /* Always end lines on a byte border */ + if (outputbitnr != 0) { + if ((res = psiconv_list_add(*bytes,&outputbyte))) + goto ERROR2; + outputbitnr = 0; + outputbyte = 0; + } + } + + return 0; + +ERROR2: + psiconv_list_free(*bytes); +ERROR1: + return res; +}