#/* * PSD Save Plugin version 1.0 (BETA) * This GIMP plug-in is designed to save Adobe Photoshop(tm) files (.PSD) * * Monigotes * * If this plug-in fails to save a file which you think it should, * please tell me what seemed to go wrong, and anything you know * about the image you tried to save. Please don't send big PSD * files to me without asking first. * * Copyright (C) 2000 Monigotes * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * Adobe and Adobe Photoshop are trademarks of Adobe Systems * Incorporated that may be registered in certain jurisdictions. */ /* * Revision history: * * 2000.02 / v1.0 / Monigotes * First version. * */ /* * TODO: */ /* * BUGS: */ /* *** DEFINES *** */ /* set to TRUE if you want debugging, FALSE otherwise */ #define DEBUG FALSE /* 1: Normal debuggin, 2: Deep debuggin */ #define DEBUG_LEVEL 1 #define IFDBG if (DEBUG) #define IF_DEEP_DBG if (DEBUG && DEBUG_LEVEL==2) /* *** END OF DEFINES *** */ #include #include #include #include #include #include /* Local types etc */ typedef struct PsdLayerDimension { gint left; gint top; gint32 width; gint32 height; } PSD_Layer_Dimension; typedef struct PsdImageData { gint compression; /* 0, no hay compresion; 1, si la hay */ gint32 image_height; /* Numero de filas de la imagen */ gint32 image_width; /* Numero de columnas de la imagen*/ gint baseType; gint nChannels; /* Numero de canales de usuario de la imagen */ gint32 *lChannels; /* Canales de usuario de la imagen */ gint nLayers; /* Num de capas de la imagen */ gint32 *lLayers; /* Identificador de cada capa */ PSD_Layer_Dimension* layersDim; /* Dimensiones de cada capa */ } PSD_Image_Data; static PSD_Image_Data PSDImageData; /* Declare some local functions. */ static void query (void); static void run (char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals); static void* xmalloc(size_t n); static void psd_lmode_layer(gint32 idLayer, gchar* psdMode); static void reshuffle_cmap_write(guchar *mapGimp); static void save_header (FILE *fd, gint32 image_id); static void save_color_mode_data (FILE *fd, gint32 image_id); static void save_resources (FILE *fd, gint32 image_id); static void save_layerAndMask (FILE *fd, gint32 image_id); static void save_data (FILE *fd, gint32 image_id); static int save_image (gchar *filename, gint32 image_id); static void xfwrite(FILE *fd, void *buf, long len, gchar *why); static void write_pascalstring (FILE *fd, char *val, gint paded, gchar *why); static void write_string (FILE *fd, char *val, gchar *why); static void write_PSstring (FILE *fd, char *val, gchar *why); static void write_gchar(FILE *fd, unsigned char val, gchar *why); static void write_gshort(FILE *fd, gshort val, gchar *why); static void write_glong(FILE *fd, glong val, gchar *why); GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; static const gchar *prog_name = "PSD"; MAIN() static void query () { static GimpParamDef save_args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" }, { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" }, { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" }, { GIMP_PDB_INT32, "compression", "Compression type: { NONE (0), LZW (1), PACKBITS (2)" }, { GIMP_PDB_INT32, "fillorder", "Fill Order: { MSB to LSB (0), LSB to MSB (1)" } }; static int nsave_args = sizeof (save_args) / sizeof (save_args[0]); gimp_install_procedure ("file_psd_save", "saves files in the Photoshop(tm) PSD file format", "This filter saves files of Adobe Photoshop(tm) native PSD format. These files may be of any image type supported by GIMP, with or without layers, layer masks, aux channels and guides.", "Monigotes", "Monigotes", "2000", "/PSD", "RGB*, GRAY*, INDEXED*", GIMP_PLUGIN, nsave_args, 0, save_args, NULL); gimp_register_save_handler ("file_psd_save", "psd", ""); } static void run (char *name, int nparams, GimpParam *param, int *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpRunModeType run_mode; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_CALLING_ERROR; if (strcmp (name, "file_psd_save") == 0) { IFDBG printf("\n---------------- %s ----------------\n", param[3].data.d_string); if ( save_image (param[3].data.d_string, /* Nombre del fichero */ param[1].data.d_image) ) /* Identificador de la imagen */ { values[0].data.d_status = GIMP_PDB_SUCCESS; } else { values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; } } } static void * xmalloc(size_t n) { void *p; if (n == 0) { IFDBG printf("PSD: WARNING: %s: xmalloc asked for zero-sized chunk\n", prog_name); return (NULL); } if ((p = g_malloc(n)) != NULL) return p; IFDBG printf("%s: out of memory\n", prog_name); gimp_quit(); return NULL; } static void psd_lmode_layer(gint32 idLayer, gchar* psdMode) { switch ( gimp_layer_get_mode (idLayer) ) { case GIMP_NORMAL_MODE: strcpy (psdMode, "norm"); break; case GIMP_DARKEN_ONLY_MODE: strcpy (psdMode, "dark"); break; case GIMP_LIGHTEN_ONLY_MODE: strcpy (psdMode, "lite"); break; case GIMP_HUE_MODE: strcpy (psdMode, "hue "); break; case GIMP_SATURATION_MODE: strcpy (psdMode, "sat "); break; case GIMP_COLOR_MODE: strcpy (psdMode, "colr"); break; case GIMP_MULTIPLY_MODE: strcpy (psdMode, "mul "); break; case GIMP_SCREEN_MODE: strcpy (psdMode, "scrn"); break; case GIMP_DISSOLVE_MODE: strcpy (psdMode, "diss"); break; case GIMP_DIFFERENCE_MODE: strcpy (psdMode, "diff"); break; case GIMP_VALUE_MODE: /* ? */ strcpy (psdMode, "lum "); break; case GIMP_OVERLAY_MODE: /* ? */ strcpy (psdMode, "over"); break; /* case BEHIND_MODE: Estos son de GIMP 1.1.14*/ /* case DIVIDE_MODE: Estos son de GIMP 1.1.14*/ case GIMP_ADDITION_MODE: case GIMP_SUBTRACT_MODE: IFDBG printf("PSD: Warning - unsupported layer-blend mode: %c, using 'norm' mode\n", gimp_layer_get_mode (idLayer)); strcpy (psdMode, "norm"); break; default: IFDBG printf("PSD: Warning - UNKNOWN layer-blend mode, reverting to 'norm'\n"); strcpy (psdMode, "norm"); break; } } static void write_string (FILE *fd, char *val, gchar *why) { write_gchar(fd, strlen(val), why); xfwrite(fd, val, strlen(val), why); } static void write_PSstring (FILE *fd, char *val, gchar *why) { int longitud = strlen(val) + 1; int i; write_glong(fd, longitud, why); for (i=0; i 255 ) ? 255 : (unsigned char) strlen(val); /* Se realiza la grabacion */ if ( valLength != 0 ) { write_gchar(fd, valLength, why); xfwrite(fd, val, valLength, why); } else write_gshort(fd, 0, why); /* Si la longitud total (longitud + contenido) no es multiplo del valor 'paded', se añaden los ceros necesarios para rellenar */ valLength ++; /* Le añado el campo longitud */ if ( (valLength % paded) == 0 ) return; for ( i=0; i < (paded - (valLength % paded)); i++) write_gchar(fd, 0, why); } static void xfwrite(FILE * fd, void * buf, long len, gchar *why) { if (fwrite(buf, len, 1, fd) == 0) { IFDBG printf(" Funcion: xfwrite: Error mientras grababa '%s'\n", why); gimp_quit(); } } static void write_gchar(FILE *fd, unsigned char val, gchar *why) { unsigned char b[2]; gint32 pos; b[0] = val; b[1] = 0; pos = ftell(fd); if (fwrite(&b, 1, 2, fd) == 0) { IFDBG printf(" Funcion: write_gchar: Error mientras grababa '%s'\n", why); gimp_quit(); } fseek(fd, pos+1, SEEK_SET); } static void write_gshort(FILE *fd, gshort val, gchar *why) { unsigned char b[2]; /* b[0] = val & 255; b[1] = (val >> 8) & 255;*/ b[1] = val & 255; b[0] = (val >> 8) & 255; if (fwrite(&b, 1, 2, fd) == 0) { IFDBG printf(" Funcion: write_gshort: Error mientras grababa '%s'\n", why); gimp_quit(); } } static void write_glong(FILE *fd, glong val, gchar *why) { unsigned char b[4]; /* b[0] = val & 255; b[1] = (val >> 8) & 255; b[2] = (val >> 16) & 255; b[3] = (val >> 24) & 255;*/ b[3] = val & 255; b[2] = (val >> 8) & 255; b[1] = (val >> 16) & 255; b[0] = (val >> 24) & 255; if (fwrite(&b, 1, 4, fd) == 0) { IFDBG printf(" Funcion: write_glong: Error mientras grababa '%s'\n", why); gimp_quit(); } } static void pack_pb_line ( guchar* ini, guchar* fin, guchar* datosRes, gshort* longitud ) { int i,j; gint32 restantes; restantes = fin - ini; *longitud = 0; while ( restantes > 0 ) { /* Busca caracteres iguales a la muestra */ i = 0; while ( ( i < 128 ) && ( ini + i < fin ) && ( (*ini) == *(ini + i) ) ) i++; if ( i > 1 ) /* Ha encontrado iguales */ { IF_DEEP_DBG printf("Repeticion: '%d', %d veces ------------> ", *ini, i); IF_DEEP_DBG printf("Grabo: '%d' %d\n", -(i - 1), *ini); *(datosRes++) = -(i - 1); *(datosRes++) = *ini; ini += i; restantes -= i; *longitud += 2; } else /* Busca caracteres distintos al anterior */ { i = 0; while ( ( i < 128 ) && ( ini + i + 1 <= fin ) && ( *(ini + i) != *(ini + i + 1) ) ) i++; /* Si solo quedaba 1 en la linea, el while anterior no lo coje */ if ( restantes == 1 ) { IF_DEEP_DBG printf("1 Restante:\t"); i = 1; } if ( i > 0 ) /* Ha encontrado distintos */ { IF_DEEP_DBG printf("%d distintos ------------> Grabo: '%d' ", i, i - 1); *(datosRes++) = i - 1; for (j=0; j 0 ) chName = (char **) xmalloc( sizeof(char *) * PSDImageData.nChannels ); for (i=0; i 0 ) { xfwrite(fd, "8BIM", 4, "imageresources signature"); write_gshort(fd, 0x03EE, "0x03EE Id"); /* write_pascalstring(fd, Name, "Id name"); */ write_gshort(fd, 0, "Id name"); /* Pongo un string nulo, dos ceros */ /* Marco la posicion actual del fichero */ posNombres = ftell(fd); write_glong(fd, 0, "0x03EE resource size"); /* Grabo todos los strings */ for (i=PSDImageData.nChannels-1; i>=0; i--) /* write_pascalstring(fd, chName[i], 2, "chanel name"); */ write_string(fd, chName[i], "channel name"); /* Calculo y grabo la longitud real de este recurso */ posActual = ftell(fd); /* Posicion del fin de fichero */ fseek(fd, posNombres, SEEK_SET); write_glong(fd, posActual - posNombres - sizeof(glong), "0x03EE resource size"); IFDBG printf ("\n Longitud total de 0x03EE resource: %ld\n", posActual - posNombres - sizeof(glong) ); /* Vuelve al final de fichero para continuar con la grabacion */ fseek(fd, posActual, SEEK_SET); /* Si la longitud es impar, añado un cero */ if ( ( posActual - posNombres - sizeof(glong) ) & 1 ) write_gchar(fd, 0, "pad byte"); } /* ------------ Voy a grabar: Nombres de los canales version II ------------ */ /* if ( PSDImageData.nChannels > 0 ) { xfwrite(fd, "8BIM", 4, "imageresources signature"); write_gshort(fd, 0x0415, "0x0415 Id"); // write_pascalstring(fd, Name, "Id name"); write_gshort(fd, 0, "Id name"); // Pongo un string nulo, dos ceros // Marco la posicion actual del fichero posNombresII = ftell(fd); write_glong(fd, 0, "0x0415 resource size"); // Grabo todos los strings for (i=PSDImageData.nChannels-1; i>=0; i--) // write_pascalstring(fd, chName[i], 2, "chanel name"); write_PSstring(fd, chName[i], "channel name"); // Calculo y grabo la longitud real de este recurso posActual = ftell(fd); // Posicion del fin de fichero fseek(fd, posNombresII, SEEK_SET); write_glong(fd, posActual - posNombresII - sizeof(glong), "0x0415 resource size"); IFDBG printf ("\n Longitud total de 0x0415 resource: %ld\n", posActual - posNombresII - sizeof(glong) ); // Vuelve al final de fichero para continuar con la grabacion fseek(fd, posActual, SEEK_SET); // Si la longitud es impar, añado un cero if ( ( posActual - posNombresII - sizeof(glong) ) & 1 ) write_gchar(fd, 0, "pad byte"); } */ /* --------------- Voy a grabar: Titulo de la imagen --------------- */ /* NO LO GRABO xfwrite(fd, "8BIM", 4, "imageresources signature"); write_gshort(fd, 0x03F0, "0x03F0 Id"); write_gshort(fd, 0, "Id name"); // Pongo un string nulo, que son dos ceros // Marco la posicion actual del fichero posTitulo = ftell(fd); write_glong(fd, 0, "0x03F0 resource size"); // Grabo el titulo como pascal string, tendra siempre una longitud par write_pascalstring(fd, fileName, 2, "image caption"); // Calculo y grabo la longitud real de este recurso posActual = ftell(fd); // Posicion del fin de fichero fseek(fd, posTitulo, SEEK_SET); write_glong(fd, posActual - posTitulo - sizeof(glong), "0x03F0 resource size"); IFDBG printf (" Longitud total de 0x03F0 resource: %ld\n", posActual - posTitulo - sizeof(glong) ); // Vuelve al final de fichero para continuar con la grabacion fseek(fd, posActual, SEEK_SET); */ /* --------------- Voy a grabar: Numero de capa activa --------------- */ if ( hayActiveLayer ) { xfwrite(fd, "8BIM", 4, "imageresources signature"); write_gshort(fd, 0x0400, "0x0400 Id"); /* write_pascalstring(fd, Name, "Id name"); */ write_gshort(fd, 0, "Id name"); /* Pongo un string nulo, que son dos ceros */ write_glong(fd, sizeof(gshort), "0x0400 resource size"); /* Grabo el titulo como gshort, tendra siempre una longitud par */ write_gshort(fd, nActiveLayer, "active layer"); IFDBG printf (" Longitud total de 0x0400 resource: %ld\n", sizeof(gshort) ); } /* --------------- Voy a grabar: Longitud total de la seccion --------------- */ posActual = ftell(fd); /* Posicion del fin de fichero */ fseek(fd, posTotal, SEEK_SET); write_glong(fd, posActual - posTotal - sizeof(glong), "image resources length"); IFDBG printf (" Longitud total de la seccion de recursos: %ld\n", posActual - posTotal - sizeof(glong) ); /* Vuelve al final de fichero para continuar con la grabacion */ fseek(fd, posActual, SEEK_SET); g_free(chName); } static void get_compress_channel_data (guchar* channel_data, gint32 channel_cols, gint32 channel_rows, gshort** tablaLongitudes, guchar** datosRes, glong* longTotalComprimido ) { gint i; gint32 longitud; /* Longitud de datos comprimidos */ gshort longAux; /* Auxiliar */ guchar* ini; /* Posicion de inicio de una fila en channel_data */ guchar* fin; /* Posicion de fin de una fila en channel_data */ gint32 channel_length; /* Longitud total del canal */ channel_length = channel_cols * channel_rows; *datosRes = g_new (guchar, channel_length * 2); *tablaLongitudes = g_new (gshort, channel_rows); /* Para cada una de las filas del canal */ longitud = 0; for (i=0; i=0; i--) { gimp_drawable_offsets( PSDImageData.lLayers[i], &offset_x, &offset_y ); layerHeight = gimp_drawable_height( PSDImageData.lLayers[i] ); layerWidth = gimp_drawable_width( PSDImageData.lLayers[i] ); PSDImageData.layersDim[i].left = offset_x; PSDImageData.layersDim[i].top = offset_y; PSDImageData.layersDim[i].height = layerHeight; PSDImageData.layersDim[i].width = layerWidth; IFDBG printf (" Capa numero: %d\n", i); IFDBG printf (" Offset x: %d\n", PSDImageData.layersDim[i].left); IFDBG printf (" Offset y: %d\n", PSDImageData.layersDim[i].top); IFDBG printf (" Height: %ld\n", PSDImageData.layersDim[i].height); IFDBG printf (" Width: %ld\n", PSDImageData.layersDim[i].width); write_glong(fd, PSDImageData.layersDim[i].top, "Layer top"); write_glong(fd, PSDImageData.layersDim[i].left, "Layer left"); write_glong(fd, PSDImageData.layersDim[i].height + PSDImageData.layersDim[i].top, "Layer top"); write_glong(fd, PSDImageData.layersDim[i].width + PSDImageData.layersDim[i].left, "Layer right"); nChannelsLayer = nCanalesLayer (PSDImageData.baseType, gimp_drawable_has_alpha(PSDImageData.lLayers[i])); write_gshort(fd, nChannelsLayer, "Number channels in the layer"); IFDBG printf (" Numero de canales: %ld\n", nChannelsLayer); /* Creo la segunda dimension del array (capas, canales) */ posLongChannel[i] = g_new (gint32, nChannelsLayer); /* Probar con gimp_drawable_bytes() */ for (j=0; j=0; i--) { int nCanal; GimpDrawable* drawable; GimpPixelRgn region; /* Region de la imagen */ guchar* data; /* Bytes que componen un layer con todos sus canales */ guchar* red; /* Bytes que componen un canal R */ guchar* green; /* Bytes que componen un canal G */ guchar* blue; /* Bytes que componen un canal B */ guchar* gray; /* Bytes que componen un canal G */ guchar* alpha; /* Bytes que componen un canal Alpha */ gint32 longCanal; /* Longitud de los datos de un canal */ IFDBG printf ("\n Chanels image data. Layer: %d\n", i); longCanal = PSDImageData.layersDim[i].width * PSDImageData.layersDim[i].height; nChannelsLayer = nCanalesLayer (PSDImageData.baseType, gimp_drawable_has_alpha(PSDImageData.lLayers[i])); data = g_new (guchar, longCanal * nChannelsLayer); drawable = gimp_drawable_get(PSDImageData.lLayers[i]); gimp_pixel_rgn_init(®ion, drawable, 0, 0, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, FALSE, FALSE ); gimp_pixel_rgn_get_rect(®ion, data, 0, 0, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height ); IFDBG printf (" Longitud canal: %ld\n", longCanal); nCanal = 0; switch ( PSDImageData.baseType ) { case GIMP_RGB: if ( gimp_drawable_has_alpha(PSDImageData.lLayers[i]) ) { RGBA_to_chans (data, longCanal * nChannelsLayer, &red, &green, &blue, &alpha); IFDBG printf (" Grabando canal alpha...\n"); save_channel_data (fd, alpha, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "alpha channel" ); } else RGB_to_chans ( data, longCanal * nChannelsLayer, &red, &green, &blue); IFDBG printf (" Grabando canal red...\n"); save_channel_data (fd, red,PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "red channel" ); IFDBG printf (" Grabando canal green...\n"); save_channel_data (fd, green, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "green channel" ); IFDBG printf (" Grabando canal blue...\n"); save_channel_data (fd, blue, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "blue channel" ); break; case GIMP_GRAY: if ( gimp_drawable_has_alpha(PSDImageData.lLayers[i]) ) { GRAYA_to_chans ( data, longCanal * nChannelsLayer, &gray, &alpha ); IFDBG printf (" Grabando canal alpha...\n"); save_channel_data (fd, alpha, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "alpha channel" ); IFDBG printf (" Grabando canal gray...\n"); save_channel_data (fd, gray, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "gray channel" ); } else { IFDBG printf (" Grabando canal gray...\n"); save_channel_data (fd, data, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "gray channel" ); } break; case GIMP_INDEXED: IFDBG printf (" Grabando canal indexed...\n"); save_channel_data (fd, data, PSDImageData.layersDim[i].width, PSDImageData.layersDim[i].height, posLongChannel[i][nCanal++], "indexed channel" ); break; } } posActual = ftell(fd); /* Posicion del fin de fichero */ /* Graba la longitud real de: Seccion Layer info */ fseek(fd, posLayerInfo, SEEK_SET); write_glong(fd, posActual - posLayerInfo - sizeof(glong), "layers info section length"); IFDBG printf ("\n Longitud total de layers info section: %d\n", posActual - posLayerInfo - sizeof(glong)); /* Graba la longitud real de: Seccion Layer and mask information */ fseek(fd, posLayerMask, SEEK_SET); write_glong(fd, posActual - posLayerMask - sizeof(glong), "layers & mask information length"); IFDBG printf (" Longitud total de layers & mask information: %d\n", posActual - posLayerMask - sizeof(glong)); /* Vuelve al final de fichero para continuar con la grabacion */ fseek(fd, posActual, SEEK_SET); } static void save_data (FILE *fd, gint32 image_id) { int compression; int nCanales; int i, j; int nCanal; gint offset_x; /* Offset x de cada capa */ gint offset_y; /* Offset y de cada capa*/ gint32 layerHeight; /* Altura de cada capa */ gint32 layerWidth; /* Anchura de cada capa*/ GimpDrawable* drawable; GimpPixelRgn region; /* Region de la imagen */ guchar* data; /* Bytes que componen un layer con todos sus canales */ guchar* red; /* Bytes que componen un canal R */ guchar* green; /* Bytes que componen un canal G */ guchar* blue; /* Bytes que componen un canal B */ guchar* gray_indexed; /* Bytes que componen un canal B */ gint32 longCanal; /* Longitud de los datos de un canal */ gint nChannelsLayer; /* Numero de canales de una capa */ gshort** TLdataCompress; guchar** dataCompress; glong* longDataCompress; glong longTotal; IFDBG printf ("\n Funcion: save_data\n"); nCanales = PSDImageData.nChannels + nCanalesLayer (PSDImageData.baseType, 0); TLdataCompress = g_new (gshort*, nCanales); dataCompress = g_new (guchar*, nCanales); longDataCompress = g_new (glong*, nCanales); i = PSDImageData.nLayers - 1; /* Canal a grabar */ IFDBG printf (" Procesando capa %d\n", i); gimp_drawable_offsets( PSDImageData.lLayers[i], &offset_x, &offset_y ); layerHeight = gimp_drawable_height( PSDImageData.lLayers[i] ); layerWidth = gimp_drawable_width( PSDImageData.lLayers[i] ); longCanal = layerWidth * layerHeight; nChannelsLayer = nCanalesLayer (PSDImageData.baseType, gimp_drawable_has_alpha(PSDImageData.lLayers[i])); data = g_new (guchar, longCanal * nChannelsLayer); drawable = gimp_drawable_get(PSDImageData.lLayers[i]); gimp_pixel_rgn_init(®ion, drawable, 0, 0, layerWidth, layerHeight, FALSE, FALSE ); gimp_pixel_rgn_get_rect(®ion, data, 0, 0, layerWidth, layerHeight); nCanal = 0; switch ( PSDImageData.baseType ) { case GIMP_RGB: RGB_to_chans ( data, longCanal * nChannelsLayer, &red, &green, &blue); get_compress_channel_data ( red, layerWidth, layerHeight, &(TLdataCompress[nCanal]), &(dataCompress[nCanal]), &(longDataCompress[nCanal]) ); IFDBG printf (" Longitud comprimida canal rojo: %ld\n", longDataCompress[nCanal]); nCanal++; get_compress_channel_data ( green, layerWidth, layerHeight, &(TLdataCompress[nCanal]), &(dataCompress[nCanal]), &(longDataCompress[nCanal]) ); IFDBG printf (" Longitud comprimida canal verde: %ld\n", longDataCompress[nCanal]); nCanal++; get_compress_channel_data ( blue, layerWidth, layerHeight, &(TLdataCompress[nCanal]), &(dataCompress[nCanal]), &(longDataCompress[nCanal]) ); IFDBG printf (" Longitud comprimida canal azul: %ld\n", longDataCompress[nCanal]); nCanal++; break; case GIMP_GRAY: case GIMP_INDEXED: gray_indexed = data; get_compress_channel_data ( gray_indexed, layerWidth, layerHeight, &(TLdataCompress[nCanal]), &(dataCompress[nCanal]), &(longDataCompress[nCanal]) ); IFDBG printf (" Longitud comprimida canal gray o indexed: %ld\n", longDataCompress[nCanal]); nCanal++; break; } for (i=PSDImageData.nChannels-1; i>=0; i--) { longCanal = PSDImageData.image_width * PSDImageData.image_height; drawable = gimp_drawable_get(PSDImageData.lChannels[i]); gimp_pixel_rgn_init(®ion, drawable, 0, 0, PSDImageData.image_width, PSDImageData.image_height, FALSE, FALSE ); gimp_pixel_rgn_get_rect(®ion, data, 0, 0, PSDImageData.image_width, PSDImageData.image_height ); get_compress_channel_data ( data, layerWidth, layerHeight, &(TLdataCompress[nCanal]), &(dataCompress[nCanal]), &(longDataCompress[nCanal]) ); IFDBG printf (" Longitud comprimida canal usuario: %ld\n", longDataCompress[nCanal]); nCanal++; } /* Calculo la longitud de todos los canales comprimidos */ longTotal = 0; for (i=0; i=0; i--) { drawable = gimp_drawable_get(PSDImageData.lChannels[i]); gimp_pixel_rgn_init(®ion, drawable, 0, 0, PSDImageData.image_width, PSDImageData.image_height, FALSE, FALSE ); gimp_pixel_rgn_get_rect(®ion, data, 0, 0, PSDImageData.image_width, PSDImageData.image_height ); xfwrite(fd, data, longCanal, "channel data"); } /* ¡¡¡ y... YATAAAAA !!! (¿Como?,¿Yataaa?) */ } } static void get_image_data (FILE *fd, gint32 image_id) { IFDBG printf (" Funcion: get_image_data\n"); PSDImageData.compression = 0; /* No hay compresion */ PSDImageData.image_height = gimp_image_height(image_id); IFDBG printf (" Obtenido numero de filas: %d\n", PSDImageData.image_height); PSDImageData.image_width = gimp_image_width(image_id); IFDBG printf (" Obtenido numero de columnas: %d\n", PSDImageData.image_width); PSDImageData.baseType = gimp_image_base_type(image_id); IFDBG printf (" Obtenido tipo base: %d\n", PSDImageData.baseType); /* El formato PSD no permite imagenes indexadas con capas */ if ( PSDImageData.baseType == GIMP_INDEXED ) { IFDBG printf (" Realizo el flatten de la imagen indexada\n"); gimp_image_flatten(image_id); } PSDImageData.lChannels = gimp_image_get_channels(image_id, &PSDImageData.nChannels); IFDBG printf (" Obtenido numero de canales: %d\n", PSDImageData.nChannels); PSDImageData.lLayers = gimp_image_get_layers(image_id, &PSDImageData.nLayers); IFDBG printf (" Obtenido numero de capas: %d\n", PSDImageData.nLayers); PSDImageData.layersDim = g_new (PSD_Layer_Dimension, PSDImageData.nLayers); } int save_image (gchar *filename, gint32 image_id) { FILE *fd; gchar *name_buf; IFDBG printf (" Funcion: save_image\n"); name_buf = g_malloc (64+strlen(filename)); IFDBG printf (name_buf, "Saving %s:", filename); gimp_progress_init(name_buf); g_free(name_buf); IFDBG printf (" Se ha puesto el mensaje en GIMP\n"); fd = fopen(filename, "wb"); if (fd==NULL) { IFDBG printf("PSD Save: no pudo abrir \"%s\"\n", filename); return(-1); } IFDBG printf (" Se ha abierto el fichero \"%s\"\n", filename); get_image_data (fd, image_id); save_header (fd, image_id); save_color_mode_data (fd, image_id); save_resources (fd, image_id); /* El formato PSD no permite imagenes indexadas con capas */ if ( PSDImageData.baseType == GIMP_INDEXED ) write_glong(fd, 0, "layers info section length"); else save_layerAndMask (fd, image_id); /* Si es una indexada, aqui irá la información de la capa y los canales */ save_data (fd, image_id); IFDBG printf ("\n\n"); fclose(fd); return TRUE; }