#include #include #include #include #include "toonz.h" #include "tmsg.h" #include "file.h" #include "tiff.h" #include "tiffio.h" #include "version.h" #include "history.h" #include "colorsdb.h" #include "ImageP/img_security.h" #define LATEST_PLT_TYPE 4 static int Next_img_read_plt_without_buffer = FALSE; static int Read_without_buffer = FALSE; #define SET_READ_WITHOUT_BUFFER \ { \ Read_without_buffer = Next_img_read_plt_without_buffer; \ Next_img_read_plt_without_buffer = FALSE; \ } #ifdef VECCHIA_MANIERA static char *build_string_names(IMAGE *image); static void set_color_names(IMAGE *image, char *names); static char *plt_find_color_name(IMAGE *img, int color); static char *plt_find_pencil_name(IMAGE *img, int color); static void plt_set_color_name(IMAGE *img, int color, char *name); static void plt_set_pencil_name(IMAGE *img, int pencil, char *name); #endif /*---------------------------------------------------------------------------*/ int img_write_plt(char *filename, IMAGE *image) { TIFF *tfp; UCHAR *buffer; int i, j, scanline, width, rows_per_strip; LPIXEL *cmap, *color, *pencil; USHORT palette[TOONZPALETTE_COUNT]; char *names, *history; int plt_type, cmap_size; CHECK_IMAGEDLL_LICENSE_AND_GET_IMG_LICENSE_ATTR names = NIL; if (image->type != CMAP) return FALSE; tfp = TIFFOpen(filename, "w"); if (!tfp) return FALSE; plt_type = (image->cmap.offset > 0) ? 4 : 3; if (!image->cmap.info.n_colors) { assert(plt_type == 4); image->cmap.info = Tcm_old_default_info; image->cmap.info.n_colors = image->cmap.color_n; image->cmap.info.n_pencils = image->cmap.pencil_n; cmap_size = TCM_MIN_CMAP_BUFFER_SIZE(image->cmap.info); } else { cmap_size = TCM_CMAP_BUFFER_SIZE(image->cmap.info); } palette[0] = plt_type; palette[1] = image->cmap.offset; palette[2] = cmap_size <= 0xffff ? cmap_size : 0; palette[3] = 0 /* image->cmap.info.tone_offs */; palette[4] = image->cmap.info.tone_bits; palette[5] = image->cmap.info.color_offs; palette[6] = image->cmap.info.color_bits; palette[7] = image->cmap.info.pencil_offs; palette[8] = image->cmap.info.pencil_bits; palette[9] = image->cmap.info.offset_mask; palette[10] = image->cmap.info.n_colors; palette[11] = image->cmap.info.n_pencils; for (i = 12; i < TOONZPALETTE_COUNT - 1; i++) palette[i] = 0; palette[TOONZPALETTE_COUNT - 1] = (Img_license_attr & TA_TOONZ_EDU) != 0; TIFFSetField(tfp, TIFFTAG_TOONZPALETTE, palette); if (plt_type == 3) { assert(image->cmap.color && image->cmap.pencil); width = image->cmap.color_n + image->cmap.pencil_n; } else { if (image->cmap.color && image->cmap.pencil) width = cmap_size + image->cmap.color_n + image->cmap.pencil_n; else width = cmap_size; } TIFFSetField(tfp, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(tfp, TIFFTAG_SAMPLESPERPIXEL, 4); TIFFSetField(tfp, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(tfp, TIFFTAG_IMAGELENGTH, 1); TIFFSetField(tfp, TIFFTAG_COMPRESSION, COMPRESSION_NONE); TIFFSetField(tfp, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tfp, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); #ifdef VECCHIA_MANIERA names_pointer = (TREE *)image->cmap.names; image->cmap.names = cdb_encode_names((TREE *)image->cmap.names, &(image->cmap.names_max)); str = build_string_names(image); names_string_pointer = (char *)image->cmap.names; image->cmap.names = (USHORT *)names_pointer; if (names_string_pointer) free(names_string_pointer); #endif names = cdb_encode_all(image->cmap.names); TIFFSetField(tfp, TIFFTAG_TOONZCOLORNAMES, names); /* Aggiungo History */ history = build_history(); if (image->history) { switch (check_history(image->history, history)) { CASE APPEND : image->history = append_history(image->history, history); CASE REPLACE : image->history = replace_last_history(image->history, history); DEFAULT: printf("Internal error: bad history type; aborting...\n"); abort(); } free(history); } else image->history = history; TIFFSetField(tfp, TIFFTAG_TOONZHISTORY, image->history); scanline = TIFFScanlineSize(tfp); /* * massima lunghezza di bytes in una strip e' 8k * vedi Graphics File Formats pag.48 */ rows_per_strip = (8 * 1024) / scanline; TIFFSetField(tfp, TIFFTAG_ROWSPERSTRIP, rows_per_strip == 0 ? 1L : rows_per_strip); TMALLOC(buffer, scanline); cmap = image->cmap.buffer; color = image->cmap.color; pencil = image->cmap.pencil; switch (plt_type) { CASE 1 : printf("img_rwite_plt error: type 1 .plt's are not written any more\n"); abort(); CASE 2 : __OR 4 : for (i = 0, j = 0; i < cmap_size; i++, j += 4) { buffer[j + 0] = cmap[i].r; buffer[j + 1] = cmap[i].g; buffer[j + 2] = cmap[i].b; buffer[j + 3] = cmap[i].m; } if (width > cmap_size) { for (i = 0; i < image->cmap.color_n; i++, j += 4) { buffer[j + 0] = color[i].r; buffer[j + 1] = color[i].g; buffer[j + 2] = color[i].b; buffer[j + 3] = color[i].m; } for (i = 0; i < image->cmap.pencil_n; i++, j += 4) { buffer[j + 0] = pencil[i].r; buffer[j + 1] = pencil[i].g; buffer[j + 2] = pencil[i].b; buffer[j + 3] = pencil[i].m; } } CASE 3 : for (i = 0, j = 0; i < image->cmap.color_n; i++, j += 4) { buffer[j + 0] = color[i].m; /* different from type 2 */ buffer[j + 1] = color[i].b; buffer[j + 2] = color[i].g; buffer[j + 3] = color[i].r; } for (i = 0; i < image->cmap.pencil_n; i++, j += 4) { buffer[j + 0] = pencil[i].m; buffer[j + 1] = pencil[i].b; buffer[j + 2] = pencil[i].g; buffer[j + 3] = pencil[i].r; } DEFAULT: assert(!"bad palette type"); } if (TIFFWriteScanline(tfp, buffer, 0, 0) < 0) goto bad; TFREE(buffer); TIFFClose(tfp); TFREE(names); return TRUE; bad: TFREE(buffer); TIFFClose(tfp); TFREE(names); return FALSE; } /*===========================================================================*/ void next_img_read_plt_without_buffer(void) { Next_img_read_plt_without_buffer = TRUE; } /*---------------------------------------------------------------------------*/ IMAGE *img_read_plt(char *filename) { int with_cmap_buffer; IMAGE *image = NIL; TIFF *tfp; UCHAR *buffer = NIL; int i, j, scanline; LPIXEL *cmap; USHORT *palette; /* [TOONZPALETTE_COUNT] */ USHORT spp, bps, comp, plan_con, photom; int width, height; char *names; int plt_type, m, cmap_file_size, cmap_alloc_size; int colpen_cmap, colbuf_alloc_size, penbuf_alloc_size; int max_n_colors, max_n_pencils; int act_n_colors, act_n_pencils, index; LPIXEL grey, black; TBOOL edu_file; CHECK_IMAGEDLL_LICENSE_AND_GET_IMG_LICENSE_ATTR SET_READ_WITHOUT_BUFFER tfp = TIFFOpen(filename, "r"); if (!tfp) return NIL; TIFFGetField(tfp, TIFFTAG_TOONZPALETTE, &palette); TIFFGetField(tfp, TIFFTAG_TOONZCOLORNAMES, &names); TIFFGetField(tfp, TIFFTAG_BITSPERSAMPLE, &bps); TIFFGetField(tfp, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetField(tfp, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tfp, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(tfp, TIFFTAG_COMPRESSION, &comp); TIFFGetField(tfp, TIFFTAG_PLANARCONFIG, &plan_con); TIFFGetField(tfp, TIFFTAG_PHOTOMETRIC, &photom); if (photom != PHOTOMETRIC_RGB || plan_con != PLANARCONFIG_CONTIG) goto bad; edu_file = palette[TOONZPALETTE_COUNT - 1] & 1; if (edu_file && !(Img_license_attr & TA_TOONZ_EDU)) { char str[1024]; BUILD_EDU_ERROR_STRING(str) tmsg_error(str); goto bad; } scanline = TIFFScanlineSize(tfp); image = new_img(); if (!image) goto bad; image->type = CMAP; /* Leggo history */ if (!TIFFGetField(tfp, TIFFTAG_TOONZHISTORY, &image->history)) image->history = ""; image->history = strsave(image->history); plt_type = palette[0]; image->cmap.offset = palette[1]; image->cmap.color_n = palette[10]; image->cmap.pencil_n = palette[11]; image->cmap.info = Tcm_old_default_info; if (palette[6]) { /*image->cmap.info.tone_offs = palette[3]; */ image->cmap.info.tone_bits = palette[4]; image->cmap.info.color_offs = palette[5]; image->cmap.info.color_bits = palette[6]; image->cmap.info.pencil_offs = palette[7]; image->cmap.info.pencil_bits = palette[8]; image->cmap.info.offset_mask = palette[9]; image->cmap.info.n_tones = 1 << palette[4]; image->cmap.info.n_colors = palette[10]; image->cmap.info.n_pencils = palette[11]; } image->cmap.info.default_val = (image->cmap.info.n_tones - 1) | image->cmap.info.offset_mask; cmap_alloc_size = TCM_CMAP_BUFFER_SIZE(image->cmap.info); cmap_file_size = palette[2] ? palette[2] : cmap_alloc_size; colpen_cmap = image->cmap.info.n_tones > 16; colbuf_alloc_size = TCM_CMAP_COLBUFFER_SIZE(image->cmap.info); penbuf_alloc_size = TCM_CMAP_PENBUFFER_SIZE(image->cmap.info); TMALLOC(buffer, scanline); if (!buffer) goto bad; with_cmap_buffer = !Read_without_buffer || (plt_type <= 2) || (plt_type == 4); if (with_cmap_buffer) { if (colpen_cmap) { TMALLOC(image->cmap.colbuffer, colbuf_alloc_size); TMALLOC(image->cmap.penbuffer, penbuf_alloc_size); if (!image->cmap.colbuffer || !image->cmap.penbuffer) goto bad; } else { TMALLOC(image->cmap.buffer, cmap_alloc_size); if (!image->cmap.buffer) goto bad; } } TCALLOC(image->cmap.color, 1 << image->cmap.info.color_bits); if (!image->cmap.color) goto bad; TCALLOC(image->cmap.pencil, 1 << image->cmap.info.pencil_bits); if (!image->cmap.pencil) goto bad; if (TIFFReadScanline(tfp, buffer, 0, 0) < 0) goto bad; switch (plt_type) { CASE 1 : if (!with_cmap_buffer) { TCALLOC(image->cmap.buffer, cmap_alloc_size) if (!image->cmap.buffer) goto bad; } for (i = 0, j = 0; i < cmap_file_size; i++, j += 4) { image->cmap.buffer[i].r = buffer[j + 0]; image->cmap.buffer[i].g = buffer[j + 1]; image->cmap.buffer[i].b = buffer[j + 2]; } to_new_cmap(&image->cmap); set_colors_and_pencils(&image->cmap); if (!with_cmap_buffer) TFREE(image->cmap.buffer) CASE 2 : __OR 4 : if (with_cmap_buffer) for (i = 0, j = 0; i < cmap_file_size; i++, j += 4) { image->cmap.buffer[i].r = buffer[j + 0]; image->cmap.buffer[i].g = buffer[j + 1]; image->cmap.buffer[i].b = buffer[j + 2]; image->cmap.buffer[i].m = buffer[j + 3]; } else j = 4 * cmap_file_size; if (width > cmap_file_size) { for (i = 0; i < image->cmap.color_n; i++, j += 4) { image->cmap.color[i].r = buffer[j + 0]; image->cmap.color[i].g = buffer[j + 1]; image->cmap.color[i].b = buffer[j + 2]; image->cmap.color[i].m = buffer[j + 3]; } for (i = 0; i < image->cmap.pencil_n; i++, j += 4) { image->cmap.pencil[i].r = buffer[j + 0]; image->cmap.pencil[i].g = buffer[j + 1]; image->cmap.pencil[i].b = buffer[j + 2]; image->cmap.pencil[i].m = buffer[j + 3]; } } else set_colors_and_pencils(&image->cmap); CASE 3 : for (i = 0, j = 0; i < image->cmap.color_n; i++, j += 4) { image->cmap.color[i].m = buffer[j + 0]; /* different from type 2 */ image->cmap.color[i].b = buffer[j + 1]; image->cmap.color[i].g = buffer[j + 2]; image->cmap.color[i].r = buffer[j + 3]; } for (i = 0; i < image->cmap.pencil_n; i++, j += 4) { image->cmap.pencil[i].m = buffer[j + 0]; image->cmap.pencil[i].b = buffer[j + 1]; image->cmap.pencil[i].g = buffer[j + 2]; image->cmap.pencil[i].r = buffer[j + 3]; } if (with_cmap_buffer) if (colpen_cmap) { memset(image->cmap.colbuffer, 0, colbuf_alloc_size * sizeof(LPIXEL)); memset(image->cmap.penbuffer, 0, penbuf_alloc_size * sizeof(LPIXEL)); fill_cmap_colbuffer(image->cmap.colbuffer, image->cmap.info, image->cmap.color, FALSE); fill_cmap_penbuffer(image->cmap.penbuffer, image->cmap.info, image->cmap.pencil, FALSE); } else { memset(image->cmap.buffer, 0, cmap_alloc_size * sizeof(LPIXEL)); fill_cmap_buffer(image->cmap.buffer, image->cmap.info, image->cmap.color, image->cmap.pencil, FALSE); } DEFAULT: goto bad; } #ifdef VECCHIA_MANIERA set_color_names(image, names); names_pointer = image->cmap.names; image->cmap.names = (USHORT *)cdb_decode_names(image->cmap.names, image->cmap.names_max); TFREE(names_pointer); #endif image->cmap.names = cdb_decode_all(names, image->cmap.info); /* estendo la palette */ max_n_colors = 1 << image->cmap.info.color_bits; max_n_pencils = 1 << image->cmap.info.pencil_bits; if (max_n_colors > image->cmap.info.n_colors || max_n_pencils > image->cmap.info.n_pencils) { act_n_colors = image->cmap.info.n_colors; act_n_pencils = image->cmap.info.n_pencils; image->cmap.info.n_colors = max_n_colors; image->cmap.info.n_pencils = max_n_pencils; image->cmap.color_n = image->cmap.info.n_colors; image->cmap.pencil_n = image->cmap.info.n_pencils; grey.r = grey.g = grey.b = 127; grey.m = 255; black.r = black.g = black.b = 0; black.m = 255; for (i = act_n_colors; i < max_n_colors; i++) { image->cmap.color[i] = grey; index = TCM_COLOR_INDEX(image->cmap.info, i); cdb_set_group(image, index, UNUSED_COLOR_PAGE_NAME); if (with_cmap_buffer && colpen_cmap) fill_cmap_colramp(image->cmap.colbuffer, image->cmap.info, image->cmap.color[i], i, FALSE); } for (i = act_n_pencils; i < max_n_pencils; i++) { image->cmap.pencil[i] = black; index = TCM_PENCIL_INDEX(image->cmap.info, i); cdb_set_group(image, index, UNUSED_COLOR_PAGE_NAME); if (with_cmap_buffer && colpen_cmap) fill_cmap_penramp(image->cmap.penbuffer, image->cmap.info, image->cmap.pencil[i], i, FALSE); } if (with_cmap_buffer && !colpen_cmap) fill_cmap_buffer(image->cmap.buffer, image->cmap.info, image->cmap.color, image->cmap.pencil, FALSE); } if (buffer) TFREE(buffer); TIFFClose(tfp); return image; bad: if (image) free_img(image); TFREE(buffer); TIFFClose(tfp); return NIL; } /*---------------------------------------------------------------------------*/ IMAGE *img_read_plt_info(char *filename) { IMAGE *image = NIL; TIFF *tfp; USHORT *palette; /* [TOONZPALETTE_COUNT] */ USHORT plan_con, photom; char *names; int max_n_colors, max_n_pencils; TBOOL edu_file; CHECK_IMAGEDLL_LICENSE_AND_GET_IMG_LICENSE_ATTR tfp = TIFFOpen(filename, "r"); if (!tfp) return NIL; TIFFGetField(tfp, TIFFTAG_TOONZPALETTE, &palette); TIFFGetField(tfp, TIFFTAG_TOONZCOLORNAMES, &names); TIFFGetField(tfp, TIFFTAG_PLANARCONFIG, &plan_con); TIFFGetField(tfp, TIFFTAG_PHOTOMETRIC, &photom); if (photom != PHOTOMETRIC_RGB || plan_con != PLANARCONFIG_CONTIG) goto bad; edu_file = palette[TOONZPALETTE_COUNT - 1] & 1; if (edu_file && !(Img_license_attr & TA_TOONZ_EDU)) { char str[1024]; BUILD_EDU_ERROR_STRING(str) tmsg_warning(str); } image = new_img(); if (!image) goto bad; image->type = CMAP; if (palette[0] < 1 || palette[0] > LATEST_PLT_TYPE) goto bad; image->cmap.offset = palette[1]; image->cmap.color_n = palette[10]; image->cmap.pencil_n = palette[11]; image->cmap.info = Tcm_old_default_info; if (palette[6]) { /*image->cmap.info.tone_offs = palette[3]; */ image->cmap.info.tone_bits = palette[4]; image->cmap.info.color_offs = palette[5]; image->cmap.info.color_bits = palette[6]; image->cmap.info.pencil_offs = palette[7]; image->cmap.info.pencil_bits = palette[8]; image->cmap.info.offset_mask = palette[9]; image->cmap.info.n_tones = 1 << palette[4]; image->cmap.info.n_colors = palette[10]; image->cmap.info.n_pencils = palette[11]; } image->cmap.info.default_val = (image->cmap.info.n_tones - 1) | image->cmap.info.offset_mask; /* Leggo history */ if (!TIFFGetField(tfp, TIFFTAG_TOONZHISTORY, &image->history)) image->history = ""; image->history = strsave(image->history); /* estendo la palette */ max_n_colors = 1 << image->cmap.info.color_bits; max_n_pencils = 1 << image->cmap.info.pencil_bits; if (max_n_colors > image->cmap.info.n_colors || max_n_pencils > image->cmap.info.n_pencils) { image->cmap.info.n_colors = max_n_colors; image->cmap.info.n_pencils = max_n_pencils; image->cmap.color_n = image->cmap.info.n_colors; image->cmap.pencil_n = image->cmap.info.n_pencils; } image->cmap.names = cdb_decode_all(names, image->cmap.info); TIFFClose(tfp); return image; bad: if (image) free_img(image); TIFFClose(tfp); return NIL; } /*---------------------------------------------------------------------------*/ /* Attenzione: se si modifica questa funzione, occore riportare le * variazioni nella libreria line x line (simg_plt.c) */ #ifdef VECCHIA_MANIERA static char *plt_find_color_name(IMAGE *img, int color) { char *name; int index; index = TCM_COLOR_INDEX(img->cmap.info, color); name = find_color_name(img, index); return name; } #endif /*---------------------------------------------------------------------------*/ /* Attenzione: se si modifica questa funzione, occore riportare le * variazioni nella libreria line x line (simg_plt.c) */ #ifdef VECCHIA_MANIERA static char *plt_find_pencil_name(IMAGE *img, int pencil) { char *name; int index; index = TCM_PENCIL_INDEX(img->cmap.info, pencil); name = find_color_name(img, index); return name; } #endif /*---------------------------------------------------------------------------*/ /* Attenzione: se si modifica questa funzione, occore riportare le * variazioni nella libreria line x line (simg_plt.c) */ #ifdef VECCHIA_MANIERA static void plt_set_color_name(IMAGE *img, int color, char *name) { int index; index = TCM_COLOR_INDEX(img->cmap.info, color); set_color_name(img, index, name); } #endif /*---------------------------------------------------------------------------*/ /* Attenzione: se si modifica questa funzione, occore riportare le * variazioni nella libreria line x line (simg_plt.c) */ #ifdef VECCHIA_MANIERA static void plt_set_pencil_name(IMAGE *img, int pencil, char *name) { int index; index = TCM_PENCIL_INDEX(img->cmap.info, pencil); set_color_name(img, index, name); } #endif /*---------------------------------------------------------------------------*/ /* Attenzione: se si modifica questa funzione, occore riportare le * variazioni nella libreria line x line (simg_plt.c) */ #ifdef VECCHIA_MANIERA static char *build_string_names(IMAGE *image) { char *str, *name; int i, maxsize = 1000, ptr, len; str = (char *)malloc(maxsize); ptr = 0; for (i = 0; i < image->cmap.color_n; i++) { name = plt_find_color_name(image, i); if (name && *name) { len = strlen(name); if ((len + ptr) >= maxsize) { maxsize += 200; str = (char *)realloc(str, maxsize); } memmove(str + ptr, name, len); ptr += len; } if (ptr + 1 >= maxsize) { maxsize += 200; str = (char *)realloc(str, maxsize); } memmove(str + ptr, "|", 1); ptr++; } for (i = 0; i < image->cmap.pencil_n; i++) { name = plt_find_pencil_name(image, i); if (name && *name) { len = strlen(name); if ((len + ptr) >= maxsize) { maxsize += 200; str = (char *)realloc(str, maxsize); } memmove(str + ptr, name, len); ptr += len; } if (ptr + 1 >= maxsize) { maxsize += 200; str = (char *)realloc(str, maxsize); } memmove(str + ptr, "|", 1); ptr++; } str[ptr] = 0; return str; } #endif /*---------------------------------------------------------------------------*/ /* Attenzione: se si modifica questa funzione, occore riportare le * variazioni nella libreria line x line (simg_plt.c) */ #ifdef VECCHIA_MANIERA static void set_color_names(IMAGE *image, char *names) { int i; char *s, *name; s = names; i = 0; while (*s) { name = NULL; if (*s != '|') { name = s; while (*s && *s != '|') s++; *s = 0; } if (name) { if (i < image->cmap.info.n_colors) plt_set_color_name(image, i, name); else plt_set_pencil_name(image, i - image->cmap.info.n_colors, name); } i++; s++; } } #endif