home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / gih.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-18  |  36.1 KB  |  1,308 lines

  1. /* Plug-in to load and save .gih (GIMP Brush Pipe) files.
  2.  *
  3.  * Copyright (C) 1999 Tor Lillqvist
  4.  * Copyright (C) 2000 Jens Lautenbacher, Sven Neumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  */
  20.  
  21.   /* Example of how to call file_gih_save from script-fu:
  22.      
  23.   (let ((ranks (cons-array 1 'byte)))
  24.     (aset ranks 0 12)
  25.     (file-gih-save 1
  26.            img
  27.            drawable
  28.            "foo.gih"
  29.            "foo.gih"
  30.            100
  31.            "test brush"
  32.            125
  33.            125
  34.            3
  35.            4
  36.            1
  37.            ranks
  38.            1
  39.            '("random")))
  40.   */
  41.  
  42.  
  43. #include "config.h"
  44.  
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48.  
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <fcntl.h>
  52. #ifdef HAVE_UNISTD_H
  53. #include <unistd.h>
  54. #endif
  55. #include <ctype.h>
  56.  
  57. #ifdef G_OS_WIN32
  58. #include <io.h>
  59. #endif
  60.  
  61. #ifndef _O_BINARY
  62. #define _O_BINARY 0
  63. #endif
  64.  
  65. #include <gtk/gtk.h>
  66.  
  67. #include <libgimp/gimp.h>
  68. #include <libgimp/gimpui.h>
  69. #include <libgimp/gimpparasiteio.h>
  70.  
  71. #include "app/brush_header.h"
  72. #include "app/pattern_header.h"
  73.  
  74. #include "libgimp/stdplugins-intl.h"
  75.  
  76.  
  77. #define DUMMY_PATTERN_NAME "x"
  78.  
  79. #define MAXDESCLEN 256
  80.  
  81. /* Parameters applicable each time we save a gih, saved in the 
  82.  * main gimp application between invocations of this plug-in.
  83.  */
  84. static struct
  85. {
  86.   guint  spacing;
  87.   guchar description[MAXDESCLEN+1];
  88. } info =
  89. /* Initialize to this, change if non-interactive later */
  90. {  
  91.   20,
  92.   "GIMP Brush Pipe"
  93. };
  94.  
  95.  
  96. static gboolean run_flag = FALSE;
  97. static gint     num_useable_layers;
  98.  
  99.  
  100. static GimpPixPipeParams gihparams;
  101.  
  102. typedef struct
  103. {
  104.   GimpOrientationType orientation;
  105.   gint32     image;
  106.   gint32     toplayer;
  107.   gint       nguides;
  108.   gint32    *guides;
  109.   gint      *value;
  110.   GtkWidget *count_label;    /* Corresponding count adjustment, */
  111.   gint      *count;        /* cols or rows                    */
  112.   gint      *other_count;       /* and the other one               */
  113.   GtkObject *ncells;
  114.   GtkObject *rank0;
  115.   GtkWidget *warning_label;
  116. } SizeAdjustmentData;
  117.  
  118. /* static gint32 *vguides, *hguides;       */
  119. /* static gint nvguides = 0, nhguides = 0; */
  120.  
  121. /* Declare some local functions.
  122.  */
  123. static void   query    (void);
  124. static void   run      (gchar      *name,
  125.             gint        nparams,
  126.             GimpParam  *param,
  127.             gint       *nreturn_vals,
  128.             GimpParam **return_vals);
  129.  
  130. static gint32    gih_load_image      (gchar        *filename); 
  131. static gboolean  gih_load_one_brush  (gint          fd,
  132.                       gint32        image_ID); 
  133.  
  134. static gint      gih_save_dialog     (gint32        image_ID);
  135. static gboolean  gih_save_one_brush  (gint          fd,
  136.                       GimpPixelRgn *pixel_rgn,
  137.                       gchar        *name);
  138. static gboolean  gih_save_image      (gchar        *filename,
  139.                       gint32        image_ID,
  140.                       gint32        orig_image_ID,
  141.                       gint32        drawable_ID);
  142.  
  143.  
  144. GimpPlugInInfo PLUG_IN_INFO =
  145. {
  146.   NULL,  /* init_proc  */
  147.   NULL,  /* quit_proc  */
  148.   query, /* query_proc */
  149.   run,   /* run_proc   */
  150. };
  151.  
  152. MAIN ()
  153.  
  154. static void
  155. query (void)
  156. {
  157.   static GimpParamDef gih_save_args[] =
  158.   {
  159.     { GIMP_PDB_INT32,    "run_mode",     "Interactive, non-interactive" },
  160.     { GIMP_PDB_IMAGE,    "image",        "Input image" },
  161.     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save" },
  162.     { GIMP_PDB_STRING,   "filename",     "The name of the file to save the brush pipe in" },
  163.     { GIMP_PDB_STRING,   "raw_filename", "The name of the file to save the brush pipe in" },
  164.     { GIMP_PDB_INT32,    "spacing",      "Spacing of the brush" },
  165.     { GIMP_PDB_STRING,   "description",  "Short description of the brush pipe" },
  166.     { GIMP_PDB_INT32,    "cell_width",     "Width of the brush cells" },
  167.     { GIMP_PDB_INT32,    "cell_height",     "Width of the brush cells" },
  168.     { GIMP_PDB_INT8,     "display_cols",   "Display column number" },
  169.     { GIMP_PDB_INT8,     "display_rows",   "Display row number" },
  170.     { GIMP_PDB_INT32,     "dimension",     "Dimension of the brush pipe" },
  171.     /* The number of rank and sel args depend on the dimension */ 
  172.     { GIMP_PDB_INT8ARRAY,"rank",         "Ranks of the dimensions" },
  173.     { GIMP_PDB_INT32,     "dimension",     "Dimension (again)" },
  174.     { GIMP_PDB_STRINGARRAY, "sel",     "Selection modes" }
  175.   };
  176.   static const gint ngih_save_args = (sizeof (gih_save_args) /
  177.                       sizeof (gih_save_args[0]));
  178.  
  179.  
  180.   static GimpParamDef gih_load_args[] =
  181.   {
  182.     { GIMP_PDB_INT32,  "run_mode",       "Interactive, non-interactive" },
  183.     { GIMP_PDB_STRING, "filename",       "The name of the file to load" },
  184.     { GIMP_PDB_STRING, "raw_filename",   "The name of the file to load" }
  185.   };
  186.   static GimpParamDef gih_load_return_vals[] =
  187.   {
  188.     { GIMP_PDB_IMAGE,  "image",          "Output image" }
  189.   };
  190.   static gint ngih_load_args = sizeof (gih_load_args) / sizeof (gih_load_args[0]);
  191.   static gint ngih_load_return_vals = (sizeof (gih_load_return_vals) /
  192.                        sizeof (gih_load_return_vals[0]));
  193.  
  194.   gimp_install_procedure ("file_gih_save",
  195.               "saves images in GIMP brush pipe format", 
  196.               "This plug-in saves an image in the GIMP brush pipe format. The image must have an alpha chnannel and can be multi-layered, and additionally the layers can be divided into a rectangular array of brushes.",
  197.               "Tor Lillqvist",
  198.               "Tor Lillqvist",
  199.               "1999",
  200.               "<Save>/GIH",
  201.               "RGBA, GRAYA",
  202.               GIMP_PLUGIN,
  203.                           ngih_save_args, 0,
  204.               gih_save_args, NULL);
  205.   
  206.   gimp_install_procedure ("file_gih_load",
  207.               "loads images in GIMP brush pipe format", 
  208.               "This plug-in loads a GIMP brush pipe as an image.",
  209.               "Jens Lautenbacher, Sven Neumann",
  210.               "Jens Lautenbacher, Sven Neumann",
  211.               "2000",
  212.               "<Load>/GIH",
  213.               NULL,
  214.               GIMP_PLUGIN,
  215.                           ngih_load_args, ngih_load_return_vals,
  216.                           gih_load_args, gih_load_return_vals);
  217.  
  218.   gimp_register_save_handler ("file_gih_save",
  219.                   "gih",
  220.                   "");
  221.   gimp_register_magic_load_handler ("file_gih_load",
  222.                     "gih",
  223.                     "",
  224.                     "");
  225. }
  226.  
  227. static void
  228. run (gchar      *name,
  229.      gint        nparams,
  230.      GimpParam  *param,
  231.      gint       *nreturn_vals,
  232.      GimpParam **return_vals)
  233. {
  234.   static GimpParam      values[1];
  235.   GimpRunModeType       run_mode;
  236.   GimpPDBStatusType     status = GIMP_PDB_SUCCESS;
  237.   GimpParasite         *pipe_parasite;
  238.   gint32                image_ID;
  239.   gint32                orig_image_ID;
  240.   gint32                drawable_ID;
  241.   gint32               *layer_ID;
  242.   gint                  nlayers, layer;
  243.   gchar                *layer_name;
  244.   gint                  i;
  245.   GimpExportReturnType  export = GIMP_EXPORT_CANCEL;
  246.  
  247.   run_mode = param[0].data.d_int32;
  248.  
  249.   *return_vals  = values;
  250.   *nreturn_vals = 1;
  251.   values[0].type          = GIMP_PDB_STATUS;
  252.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  253.  
  254.   if (run_mode == GIMP_RUN_INTERACTIVE)
  255.     {
  256.       INIT_I18N_UI();
  257.     }
  258.   else
  259.     {
  260.       INIT_I18N();
  261.     }
  262.  
  263.   if (strcmp (name, "file_gih_load") == 0) 
  264.     {
  265.       image_ID = gih_load_image (param[1].data.d_string);
  266.       
  267.       if (image_ID != -1) 
  268.     {
  269.       *nreturn_vals = 2;
  270.       values[1].type         = GIMP_PDB_IMAGE;
  271.       values[1].data.d_image = image_ID;
  272.     }
  273.       else
  274.     {
  275.       status = GIMP_PDB_EXECUTION_ERROR;
  276.     }
  277.     }
  278.   else if (strcmp (name, "file_gih_save") == 0)
  279.     {
  280.       image_ID = orig_image_ID = param[1].data.d_int32;
  281.       drawable_ID = param[2].data.d_int32; 
  282.  
  283.       /*  eventually export the image */ 
  284.       switch (run_mode)
  285.     {
  286.     case GIMP_RUN_INTERACTIVE:
  287.     case GIMP_RUN_WITH_LAST_VALS:
  288.       gimp_ui_init ("gih", FALSE);
  289.       export = gimp_export_image (&image_ID, &drawable_ID, "GIH",
  290.                       GIMP_EXPORT_CAN_HANDLE_RGB    |
  291.                       GIMP_EXPORT_CAN_HANDLE_GRAY   |
  292.                       GIMP_EXPORT_CAN_HANDLE_ALPHA  | 
  293.                       GIMP_EXPORT_CAN_HANDLE_LAYERS |
  294.                       GIMP_EXPORT_NEEDS_ALPHA);
  295.       if (export == GIMP_EXPORT_CANCEL)
  296.         {
  297.           values[0].data.d_status = GIMP_PDB_CANCEL;
  298.           return;
  299.         }
  300.       break;
  301.     default:
  302.       break;
  303.     }
  304.  
  305.       layer_ID = gimp_image_get_layers (image_ID, &nlayers);
  306.       num_useable_layers = 0;
  307.       for (layer = 0; layer < nlayers; layer++)
  308.     {
  309.       if (!gimp_drawable_has_alpha (layer_ID[layer]))
  310.         {
  311.           layer_name = gimp_layer_get_name (layer_ID[layer]);
  312.           g_message (_("Layer %s doesn't have an alpha channel, skipped"),
  313.              layer_name);
  314.           g_free (layer_name);
  315.         }
  316.       num_useable_layers++;
  317.     }
  318.  
  319.       switch (run_mode)
  320.     {
  321.     case GIMP_RUN_INTERACTIVE:
  322.       /*  Possibly retrieve data  */
  323.       gimp_get_data ("file_gih_save", &info);
  324.  
  325.       gimp_pixpipe_params_init (&gihparams);
  326.  
  327.       /* Setup default values */
  328.       if (gihparams.rows < 1) gihparams.rows = 1;      
  329.       if (gihparams.cols < 1) gihparams.cols = 1;
  330.       
  331.       gihparams.ncells = num_useable_layers * gihparams.rows * gihparams.cols;
  332.       
  333.       if (gihparams.cellwidth == 1 && gihparams.cellheight == 1)
  334.         {
  335.           gihparams.cellwidth  = 
  336.         gimp_image_width (image_ID)  / gihparams.cols;
  337.           gihparams.cellheight = 
  338.         gimp_image_height (image_ID) / gihparams.rows;
  339.         }
  340.  
  341.       pipe_parasite =
  342.         gimp_image_parasite_find (orig_image_ID,
  343.                       "gimp-brush-pipe-parameters");
  344.       if (pipe_parasite)
  345.         gimp_pixpipe_params_parse (pipe_parasite->data, &gihparams);
  346.  
  347.       if (!gih_save_dialog (image_ID))
  348.         status = GIMP_PDB_CANCEL;
  349.       break;
  350.  
  351.     case GIMP_RUN_NONINTERACTIVE:
  352.       if (nparams != 15)
  353.         {
  354.           status = GIMP_PDB_CALLING_ERROR;
  355.         }
  356.       else
  357.         {
  358.           info.spacing = param[5].data.d_int32;
  359.           strncpy (info.description, param[6].data.d_string, MAXDESCLEN);
  360.           info.description[MAXDESCLEN] = 0;
  361.  
  362.           gimp_pixpipe_params_init (&gihparams);
  363.  
  364.           gihparams.cellwidth  = param[7].data.d_int32;
  365.           gihparams.cellheight = param[8].data.d_int32;
  366.           gihparams.cols       = param[9].data.d_int8;
  367.           gihparams.rows       = param[10].data.d_int8;
  368.           gihparams.dim        = param[11].data.d_int32;
  369.           gihparams.ncells     = 1; 
  370.  
  371.           if (param[13].data.d_int32 != gihparams.dim)
  372.         {
  373.           status = GIMP_PDB_CALLING_ERROR;
  374.         }
  375.           else
  376.         {
  377.           for (i = 0; i < gihparams.dim; i++)
  378.             {
  379.               gihparams.rank[i]      = param[12].data.d_int8array[i];
  380.               gihparams.selection[i] = g_strdup (param[14].data.d_stringarray[i]);
  381.               gihparams.ncells       *= gihparams.rank[i];
  382.             }
  383.         }
  384.         }
  385.       break;
  386.       
  387.     case GIMP_RUN_WITH_LAST_VALS:
  388.       gimp_get_data ("file_gih_save", &info);
  389.       pipe_parasite =
  390.         gimp_image_parasite_find (orig_image_ID,
  391.                       "gimp-brush-pipe-parameters");
  392.       gimp_pixpipe_params_init (&gihparams);
  393.       if (pipe_parasite)
  394.         gimp_pixpipe_params_parse (pipe_parasite->data, &gihparams);
  395.       break;
  396.     }
  397.  
  398.       if (status == GIMP_PDB_SUCCESS)
  399.     {
  400.       if (gih_save_image (param[3].data.d_string, 
  401.                   image_ID, orig_image_ID, drawable_ID))
  402.         {
  403.           gimp_set_data ("file_gih_save", &info, sizeof (info));
  404.         }
  405.       else
  406.         {
  407.           status = GIMP_PDB_EXECUTION_ERROR;
  408.         }
  409.     }
  410.  
  411.       if (export == GIMP_EXPORT_EXPORT)
  412.     gimp_image_delete (image_ID);
  413.     }
  414.   else
  415.     {
  416.       status = GIMP_PDB_CALLING_ERROR;
  417.     }
  418.  
  419.   values[0].data.d_status = status;
  420. }
  421.  
  422.  
  423. /*  load routines  */
  424.  
  425. static gboolean
  426. gih_load_one_brush (gint   fd,
  427.             gint32 image_ID)
  428. {
  429.   static gint    num_layers = 0;
  430.   gchar         *name       = NULL;
  431.   BrushHeader    bh;
  432.   guchar        *brush_buf  = NULL;
  433.   gint32         layer_ID;
  434.   GimpDrawable  *drawable;
  435.   GimpPixelRgn   pixel_rgn;
  436.   gint           version_extra;
  437.   gint           bn_size;
  438.   GimpImageType  image_type;
  439.   gint           width, height;
  440.   gint           new_width, new_height;
  441.  
  442.   g_return_val_if_fail (fd != -1, FALSE);
  443.   g_return_val_if_fail (image_ID != -1, FALSE);
  444.  
  445.   if (read (fd, &bh, sizeof (bh)) != sizeof (bh)) 
  446.     return FALSE;
  447.  
  448.   /*  rearrange the bytes in each unsigned int  */
  449.   bh.header_size  = g_ntohl (bh.header_size);
  450.   bh.version      = g_ntohl (bh.version);
  451.   bh.width        = g_ntohl (bh.width);
  452.   bh.height       = g_ntohl (bh.height);
  453.   bh.bytes        = g_ntohl (bh.bytes);
  454.   bh.magic_number = g_ntohl (bh.magic_number);
  455.   bh.spacing      = g_ntohl (bh.spacing);
  456.   
  457.   /* How much extra to add to the header seek - 1 needs a bit more */
  458.   version_extra = 0;
  459.   
  460.   if (bh.version == 1) 
  461.     {
  462.       /* Version 1 didn't know about spacing */    
  463.       bh.spacing = 25;
  464.       /* And we need to rewind the handle a bit too */
  465.       lseek (fd, -8, SEEK_CUR);
  466.       version_extra = 8;
  467.     }
  468.   /* Version 1 didn't know about magic either */
  469.   if ((bh.version != 1 && 
  470.        (bh.magic_number != GBRUSH_MAGIC || bh.version != 2)) ||
  471.       bh.header_size <= sizeof (bh)) 
  472.     {
  473.       return FALSE;
  474.     }
  475.   
  476.   if ((bn_size = (bh.header_size - sizeof (bh))) > 0)
  477.     {
  478.       name = g_new (gchar, bn_size);
  479.       if ((read (fd, name, bn_size)) < bn_size)
  480.     {
  481.       g_message (_("Error in GIMP brush pipe file."));
  482.       g_free (name);
  483.       return FALSE;
  484.     }
  485.     }
  486.   else
  487.     {
  488.       name = g_strdup (_("Unnamed"));
  489.     }
  490.  
  491.   /* Now there's just raw data left. */
  492.   
  493.   brush_buf = g_malloc (bh.width * bh.height * bh.bytes);
  494.  
  495.   if (read (fd, brush_buf, 
  496.         bh.width * bh.height * bh.bytes) != bh.width * bh.height * bh.bytes) 
  497.     {
  498.       g_free (brush_buf);
  499.       g_free (name);
  500.       return FALSE;
  501.     }
  502.  
  503.  
  504.   if (bh.bytes == 1)
  505.     {
  506.       PatternHeader ph;
  507.  
  508.       /*  For backwards-compatibility, check if a pattern follows.
  509.       The obsolete .gpb format did it this way.  */
  510.  
  511.       if (read (fd, &ph, sizeof(ph)) == sizeof(ph)) 
  512.     {
  513.       /*  rearrange the bytes in each unsigned int  */
  514.       ph.header_size  = g_ntohl (ph.header_size);
  515.       ph.version      = g_ntohl (ph.version);
  516.       ph.width        = g_ntohl (ph.width);
  517.       ph.height       = g_ntohl (ph.height);
  518.       ph.bytes        = g_ntohl (ph.bytes);
  519.       ph.magic_number = g_ntohl (ph.magic_number);
  520.  
  521.       if (ph.magic_number == GPATTERN_MAGIC && ph.version == 1 &&
  522.           ph.header_size > sizeof (ph) &&
  523.           ph.bytes == 3 && ph.width == bh.width && ph.height == bh.height &&
  524.           lseek (fd, ph.header_size - sizeof (ph), SEEK_CUR) > 0)
  525.         {
  526.           guchar *plain_brush = brush_buf;
  527.           gint    i;
  528.  
  529.           bh.bytes = 4;
  530.           brush_buf = g_malloc (4 * bh.width * bh.height);
  531.           
  532.           for (i = 0; i < ph.width * ph.height; i++)
  533.         {
  534.           if (read (fd, brush_buf + i * 4, 3) != 3)
  535.             {
  536.               g_free (name);
  537.               g_free (plain_brush);
  538.               g_free (brush_buf);
  539.               return FALSE;
  540.             }
  541.           brush_buf[i * 4 + 3] = plain_brush[i];
  542.         }
  543.           g_free (plain_brush);
  544.         }
  545.       else if (lseek (fd, - sizeof (PatternHeader), SEEK_CUR) < 0)
  546.         {
  547.           g_message (_("GIMP brush file appears to be corrupted."));
  548.           g_free (name);
  549.           g_free (brush_buf);
  550.           return FALSE;
  551.         }
  552.     }
  553.     }
  554.  
  555.   /*
  556.    * Create a new layer of the proper size.
  557.    */
  558.   
  559.   switch (bh.bytes)
  560.     {
  561.     case 1:
  562.       image_type = GIMP_GRAY_IMAGE;
  563.       break;
  564.  
  565.     case 4:
  566.       image_type = GIMP_RGBA_IMAGE;
  567.       if (gimp_image_base_type (image_ID) == GIMP_GRAY)
  568.     gimp_convert_rgb (image_ID);
  569.       break;
  570.  
  571.     default:
  572.       g_message ("Unsupported brush depth: %d\nGIMP Brushes must be GRAY or RGBA\n",
  573.          bh.bytes);
  574.       return FALSE;
  575.     }
  576.  
  577.   new_width  = width  = gimp_image_width (image_ID);
  578.   new_height = height = gimp_image_height (image_ID);
  579.  
  580.   if (bh.width > width || bh.height > height)
  581.     {
  582.       new_width  = MAX (width, bh.width);
  583.       new_height = MAX (height, bh.height);
  584.       gimp_image_resize (image_ID,
  585.              new_width, new_height,
  586.              (width - new_width) / 2, (height - new_height) / 2);
  587.     }
  588.  
  589.   layer_ID = gimp_layer_new (image_ID, name, 
  590.                  bh.width, bh.height, 
  591.                  image_type, 100, GIMP_NORMAL_MODE);
  592.   g_free (name);
  593.  
  594.   if (layer_ID != -1)
  595.     {
  596.       gimp_image_add_layer (image_ID, layer_ID, num_layers++);
  597.       gimp_layer_set_offsets (layer_ID, 
  598.                   (new_width - bh.width)   / 2, 
  599.                   (new_height - bh.height) / 2);
  600.  
  601.       drawable = gimp_drawable_get (layer_ID);
  602.       gimp_pixel_rgn_init (&pixel_rgn, drawable, 
  603.                0, 0, drawable->width, drawable->height, 
  604.                TRUE, FALSE);
  605.       
  606.       gimp_pixel_rgn_set_rect (&pixel_rgn, (guchar *) brush_buf, 
  607.                    0, 0, bh.width, bh.height);
  608.  
  609.       if (image_type == GIMP_GRAY_IMAGE)
  610.     gimp_invert (layer_ID);
  611.     }
  612.  
  613.   g_free (brush_buf);
  614.  
  615.   return TRUE;
  616. }
  617.  
  618. static gint32 
  619. gih_load_image (gchar *filename) 
  620. {
  621.   gchar   *temp;
  622.   gint     fd;
  623.   gint     i;
  624.   gint32   image_ID;
  625.   GString *buffer;
  626.   gchar    c;
  627.   gchar   *name = NULL;
  628.   gint     num_of_brushes = 0;
  629.   gchar   *paramstring;
  630.   GimpParasite *pipe_parasite;
  631.  
  632.   temp = g_strdup_printf (_("Loading %s:"), filename);
  633.   gimp_progress_init (temp);
  634.   g_free (temp);
  635.   
  636.   fd = open (filename, O_RDONLY | _O_BINARY);
  637.   
  638.   if (fd == -1) 
  639.     {
  640.       return -1;
  641.     }
  642.  
  643.   /* The file format starts with a painfully simple text header */
  644.  
  645.   /*  get the name  */
  646.   buffer = g_string_new (NULL);
  647.   while (read (fd, &c, 1) == 1 && c != '\n' && buffer->len < 1024)
  648.     g_string_append_c (buffer, c);
  649.     
  650.   if (buffer->len > 0 && buffer->len < 1024)
  651.     name = buffer->str;
  652.  
  653.   g_string_free (buffer, FALSE);
  654.  
  655.   if (!name)
  656.     {
  657.       g_message ("Couldn't read name for brush pipe from file '%s'\n", 
  658.          filename);
  659.       close (fd);
  660.       return -1;
  661.     }
  662.  
  663.   /*  get the number of brushes  */
  664.   buffer = g_string_new (NULL);
  665.   while (read (fd, &c, 1) == 1 && c != '\n' && buffer->len < 1024)
  666.     g_string_append_c (buffer, c);
  667.  
  668.   if (buffer->len > 0 && buffer->len < 1024)
  669.     {
  670.       num_of_brushes = strtol (buffer->str, ¶mstring, 10);
  671.     }
  672.  
  673.   if (num_of_brushes < 1)
  674.     {
  675.       g_message ("Brush pipes should have at least one brush.");
  676.       close (fd);
  677.       g_free (name);
  678.       g_string_free (buffer, TRUE);
  679.       return -1;
  680.     }
  681.  
  682.   image_ID = gimp_image_new (1, 1, GIMP_GRAY);
  683.   gimp_image_set_filename (image_ID, filename);
  684.  
  685.   for (i = 0; i < num_of_brushes; i++)
  686.     {
  687.       if (! gih_load_one_brush (fd, image_ID))
  688.     {
  689.       g_message (_("Couldn't load one brush in the pipe, giving up."));
  690.       close (fd);
  691.       g_free (name);
  692.       g_string_free (buffer, TRUE);
  693.       return -1;
  694.     }
  695.     
  696.       gimp_progress_update ((gdouble) i / (gdouble) num_of_brushes);
  697.     }
  698.  
  699.   while (*paramstring && isspace (*paramstring))
  700.     paramstring++;
  701.  
  702.   /*  Since we do not (yet) load the pipe as described in the header,
  703.       but use one layer per brush, we have to alter the paramstring
  704.       before attaching it as a parasite.
  705.    */
  706.  
  707.   if (*paramstring)
  708.     {
  709.       gimp_pixpipe_params_parse (paramstring, &gihparams);
  710.       
  711.       gihparams.cellwidth  = gimp_image_width  (image_ID);
  712.       gihparams.cellheight = gimp_image_height (image_ID);
  713.       gihparams.cols       = 1;
  714.       gihparams.rows       = 1;
  715.  
  716.       paramstring = gimp_pixpipe_params_build (&gihparams);
  717.       if (paramstring)
  718.     {
  719.       pipe_parasite = gimp_parasite_new ("gimp-brush-pipe-parameters",
  720.                          GIMP_PARASITE_PERSISTENT,
  721.                          strlen (paramstring) + 1, 
  722.                          paramstring);
  723.       gimp_image_parasite_attach (image_ID, pipe_parasite);
  724.       gimp_parasite_free (pipe_parasite);
  725.       g_free (paramstring);
  726.     }
  727.     }
  728.  
  729.   g_string_free (buffer, TRUE);
  730.  
  731.   return image_ID;
  732. }
  733.  
  734. /*  save routines */
  735.  
  736. static void
  737. size_adjustment_callback (GtkWidget *widget,
  738.               gpointer   data)
  739. {
  740.   /* Unfortunately this doesn't work, sigh. The guides don't show up unless
  741.    * you manually force a redraw of the image.
  742.    */
  743.   gint  i;
  744.   gint  size;
  745.   gint  newn;
  746.   gchar buf[10];
  747.   SizeAdjustmentData *adj = (SizeAdjustmentData *) data;
  748.  
  749.   for (i = 0; i < adj->nguides; i++)
  750.     gimp_image_delete_guide (adj->image, adj->guides[i]);
  751.  
  752.   g_free (adj->guides);
  753.   adj->guides = NULL;
  754.   gimp_displays_flush ();
  755.  
  756.   *(adj->value) = GTK_ADJUSTMENT (widget)->value;
  757.  
  758.   if (adj->orientation == GIMP_VERTICAL)
  759.     {
  760.       size = gimp_image_width (adj->image);
  761.       newn = size / *(adj->value);
  762.       adj->nguides = newn - 1;
  763.       adj->guides = g_new (gint32, adj->nguides);
  764.       for (i = 0; i < adj->nguides; i++)
  765.     adj->guides[i] = gimp_image_add_vguide (adj->image,
  766.                         *(adj->value) * (i+1));
  767.     }
  768.   else
  769.     {
  770.       size = gimp_image_height (adj->image);
  771.       newn = size / *(adj->value);
  772.       adj->nguides = newn - 1;
  773.       adj->guides = g_new (gint32, adj->nguides);
  774.       for (i = 0; i < adj->nguides; i++)
  775.     adj->guides[i] = gimp_image_add_hguide (adj->image,
  776.                         *(adj->value) * (i+1));
  777.     }
  778.   gimp_displays_flush ();
  779.   sprintf (buf, "%2d", newn);
  780.   gtk_label_set_text (GTK_LABEL (adj->count_label), buf);
  781.  
  782.   *(adj->count) = newn;
  783.  
  784.   if (newn * *(adj->value) != size)
  785.     gtk_widget_show (GTK_WIDGET (adj->warning_label));
  786.   else
  787.     gtk_widget_hide (GTK_WIDGET (adj->warning_label));
  788.  
  789.   if (adj->ncells != NULL)
  790.     gtk_adjustment_set_value (GTK_ADJUSTMENT (adj->ncells),
  791.                   *(adj->other_count) * *(adj->count));
  792.   if (adj->rank0 != NULL)
  793.     gtk_adjustment_set_value (GTK_ADJUSTMENT (adj->rank0),
  794.                   *(adj->other_count) * *(adj->count));
  795. }
  796.  
  797. static void
  798. entry_callback (GtkWidget *widget,
  799.         gpointer   data)
  800. {
  801.   if (data == info.description)
  802.     {
  803.       strncpy (info.description, 
  804.            gtk_entry_get_text (GTK_ENTRY (widget)), MAXDESCLEN);
  805.       info.description[MAXDESCLEN]  = 0;
  806.     }
  807. }
  808.  
  809. static void
  810. cb_callback (GtkWidget *widget,
  811.          gpointer   data)
  812. {
  813.   *((gchar **) data) = gtk_entry_get_text (GTK_ENTRY (widget));
  814. }
  815.  
  816. static void
  817. ok_callback (GtkWidget *widget,
  818.          gpointer    data)
  819. {
  820.   gint i;
  821.  
  822.   for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
  823.     gihparams.selection[i] = g_strdup (gihparams.selection[i]);
  824.  
  825.   run_flag = TRUE;
  826.   gtk_widget_destroy (GTK_WIDGET (data));
  827. }
  828.  
  829. static gint
  830. gih_save_dialog (gint32 image_ID)
  831. {
  832.   GtkWidget *dlg;
  833.   GtkWidget *table;
  834.   GtkWidget *dimtable;
  835.   GtkWidget *label;
  836.   GtkObject *adjustment;
  837.   GtkWidget *spinbutton;
  838.   GtkWidget *entry;
  839.   GtkWidget *box;
  840.   GtkWidget *cb;
  841.   GList     *cbitems = NULL;
  842.   gint       i;
  843.   gchar      buffer[100];
  844.   SizeAdjustmentData cellw_adjust;
  845.   SizeAdjustmentData cellh_adjust;
  846.   gint32    *layer_ID;
  847.   gint32     nlayers;
  848.  
  849.   dlg = gimp_dialog_new (_("Save as Brush Pipe"), "gih",
  850.              gimp_standard_help_func, "filters/gih.html",
  851.              GTK_WIN_POS_MOUSE,
  852.              FALSE, TRUE, FALSE,
  853.              
  854.              _("OK"), ok_callback,
  855.              NULL, NULL, NULL, TRUE, FALSE,
  856.              _("Cancel"), gtk_widget_destroy,
  857.              NULL, 1, NULL, FALSE, TRUE,
  858.              
  859.              NULL);
  860.  
  861.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  862.               GTK_SIGNAL_FUNC (gtk_main_quit),
  863.               NULL);
  864.  
  865.   /* The main table */
  866.   table = gtk_table_new (8, 2, FALSE);
  867.   gtk_table_set_row_spacings (GTK_TABLE (table), 4);
  868.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  869.   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
  870.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
  871.   gtk_widget_show (table);
  872.  
  873.   /*
  874.    * Spacing: __
  875.    */
  876.   spinbutton = gimp_spin_button_new (&adjustment, info.spacing,
  877.                      1, 1000, 1, 10, 10, 1, 0);
  878.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  879.                  _("Spacing (Percent):"), 1.0, 0.5,
  880.                  spinbutton, 1, TRUE);
  881.   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  882.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  883.               &info.spacing);
  884.  
  885.   /*
  886.    * Description: ___________
  887.    */
  888.   entry = gtk_entry_new ();
  889.   gtk_widget_set_usize (entry, 200, 0);
  890.   gtk_entry_set_text (GTK_ENTRY (entry), info.description);
  891.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  892.                  _("Description:"), 1.0, 0.5,
  893.                  entry, 1, FALSE);
  894.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  895.               GTK_SIGNAL_FUNC (entry_callback),
  896.               info.description);
  897.  
  898.   /*
  899.    * Cell size: __ x __ pixels
  900.    */
  901.   box = gtk_hbox_new (FALSE, 4);
  902.  
  903.   spinbutton = gimp_spin_button_new (&adjustment,
  904.                      gihparams.cellwidth,
  905.                      2, gimp_image_width (image_ID), 1, 1, 1,
  906.                      1, 0);
  907.   gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, FALSE, 0);
  908.  
  909.   layer_ID = gimp_image_get_layers (image_ID, &nlayers);
  910.   cellw_adjust.orientation = GIMP_VERTICAL;
  911.   cellw_adjust.image       = image_ID;
  912.   cellw_adjust.toplayer    = layer_ID[nlayers-1];
  913.   cellw_adjust.nguides     = 0;
  914.   cellw_adjust.guides      = NULL;
  915.   cellw_adjust.value       = &gihparams.cellwidth;
  916.   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  917.               GTK_SIGNAL_FUNC (size_adjustment_callback),
  918.               &cellw_adjust);
  919.   gtk_widget_show (spinbutton);
  920.  
  921.   label = gtk_label_new ("x");
  922.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  923.   gtk_widget_show (label);
  924.  
  925.   spinbutton = gimp_spin_button_new (&adjustment,
  926.                      gihparams.cellheight,
  927.                      2, gimp_image_height (image_ID), 1, 1, 1,
  928.                      1, 0);
  929.   gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, FALSE, 0);
  930.   cellh_adjust.orientation = GIMP_HORIZONTAL;
  931.   cellh_adjust.image       = image_ID;
  932.   cellh_adjust.toplayer    = layer_ID[nlayers-1];
  933.   cellh_adjust.nguides     = 0;
  934.   cellh_adjust.guides      = NULL;
  935.   cellh_adjust.value       = &gihparams.cellheight;
  936.   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  937.               GTK_SIGNAL_FUNC (size_adjustment_callback),
  938.               &cellh_adjust);
  939.   gtk_widget_show (spinbutton);
  940.  
  941.   label = gtk_label_new ( _("Pixels"));
  942.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  943.   gtk_widget_show (label);
  944.  
  945.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
  946.                  _("Cell Size:"), 1.0, 0.5,
  947.                  box, 1, FALSE);
  948.  
  949.   g_free (layer_ID);
  950.  
  951.   /*
  952.    * Number of cells: ___
  953.    */
  954.   spinbutton = gimp_spin_button_new (&adjustment,
  955.                      gihparams.ncells, 1, 1000, 1, 10, 10,
  956.                      1, 0);
  957.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
  958.                  _("Number of Cells:"), 1.0, 0.5,
  959.                  spinbutton, 1, TRUE);
  960.   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  961.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  962.               &gihparams.ncells);
  963.  
  964.   if (gihparams.dim == 1)
  965.     cellw_adjust.ncells = cellh_adjust.ncells = adjustment;
  966.   else
  967.     cellw_adjust.ncells = cellh_adjust.ncells = NULL;
  968.  
  969.   /*
  970.    * Display as: __ rows x __ cols
  971.    */
  972.   box = gtk_hbox_new (FALSE, 0);
  973.  
  974.   g_snprintf (buffer, sizeof (buffer), "%2d", gihparams.rows);
  975.   label = gtk_label_new (buffer);
  976.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  977.   cellh_adjust.count_label = label;
  978.   cellh_adjust.count       = &gihparams.rows;
  979.   cellh_adjust.other_count = &gihparams.cols;
  980.   gtk_widget_show (label);
  981.  
  982.   label = gtk_label_new (_(" Rows of "));
  983.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  984.   gtk_widget_show (label);
  985.  
  986.   g_snprintf (buffer, sizeof (buffer), "%2d", gihparams.cols);
  987.   label = gtk_label_new (buffer);
  988.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  989.   cellw_adjust.count_label = label;
  990.   cellw_adjust.count       = &gihparams.cols;  
  991.   cellw_adjust.other_count = &gihparams.rows;
  992.   gtk_widget_show (label);
  993.  
  994.   label = gtk_label_new (_(" Columns on each Layer"));
  995.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  996.   gtk_widget_show (label);
  997.  
  998.   label = gtk_label_new (_(" (Width Mismatch!) "));
  999.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  1000.   cellw_adjust.warning_label = label;
  1001.   
  1002.   label = gtk_label_new (_(" (Height Mismatch!) "));
  1003.   gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
  1004.   cellh_adjust.warning_label = label;
  1005.  
  1006.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
  1007.                  _("Display as:"), 1.0, 0.5,
  1008.                  box, 1, FALSE);
  1009.   
  1010.   /*
  1011.    * Dimension: ___
  1012.    */
  1013.   spinbutton = gimp_spin_button_new (&adjustment, gihparams.dim,
  1014.                      1, 5, 1, 1, 1, 1, 0);
  1015.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 5,
  1016.                  _("Dimension:"), 1.0, 0.5,
  1017.                  spinbutton, 1, TRUE);
  1018.   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  1019.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1020.               &gihparams.dim);
  1021.  
  1022.   /*
  1023.    * Ranks: __ __ __ __ __
  1024.    */
  1025.   dimtable = gtk_table_new (1, GIMP_PIXPIPE_MAXDIM, FALSE);
  1026.   gtk_table_set_col_spacings (GTK_TABLE (dimtable), 4);
  1027.   for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
  1028.     {
  1029.       box = gtk_hbox_new (FALSE, 0);
  1030.       gtk_table_attach (GTK_TABLE (dimtable), box, i, i + 1, 0, 1,
  1031.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  1032.       gtk_widget_show (box);
  1033.  
  1034.       spinbutton = gimp_spin_button_new (&adjustment,
  1035.                      gihparams.rank[i], 0, 100, 1, 1, 1,
  1036.                      1, 0);
  1037.       gtk_box_pack_start (GTK_BOX (box), spinbutton, FALSE, TRUE, 0);
  1038.       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
  1039.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1040.               &gihparams.rank[i]);
  1041.       gtk_widget_show (spinbutton);
  1042.       if (i == 0)
  1043.     { 
  1044.       if (gihparams.dim == 1)
  1045.         cellw_adjust.rank0 = cellh_adjust.rank0 = adjustment;
  1046.       else
  1047.         cellw_adjust.rank0 = cellh_adjust.rank0 = NULL;
  1048.     }
  1049.     }
  1050.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 6,
  1051.                  _("Ranks:"), 1.0, 0.5,
  1052.                  dimtable, 1, FALSE);
  1053.  
  1054.   /*
  1055.    * Selection: ______ ______ ______ ______ ______
  1056.    */
  1057.   cbitems = g_list_append (cbitems, "incremental");
  1058.   cbitems = g_list_append (cbitems, "angular");
  1059.   cbitems = g_list_append (cbitems, "random");
  1060.   cbitems = g_list_append (cbitems, "velocity");
  1061.   cbitems = g_list_append (cbitems, "pressure");
  1062.   cbitems = g_list_append (cbitems, "xtilt");
  1063.   cbitems = g_list_append (cbitems, "ytilt");
  1064.  
  1065.   box = gtk_hbox_new (TRUE, 4);
  1066.   for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
  1067.     {
  1068.       cb = gtk_combo_new ();
  1069.       gtk_combo_set_popdown_strings (GTK_COMBO (cb), cbitems);
  1070.       if (gihparams.selection[i])
  1071.     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (cb)->entry)
  1072.                 , gihparams.selection[i]);
  1073.       else
  1074.     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (cb)->entry), "random");
  1075.       gtk_entry_set_editable (GTK_ENTRY (GTK_COMBO (cb)->entry), FALSE);
  1076.  
  1077.       gtk_box_pack_start (GTK_BOX (box), cb, FALSE, TRUE, 0);
  1078.       gtk_signal_connect (GTK_OBJECT (GTK_COMBO (cb)->entry), "changed",
  1079.               GTK_SIGNAL_FUNC (cb_callback),
  1080.               &gihparams.selection[i]);
  1081.       gtk_widget_show (cb);
  1082.     }
  1083.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 7,
  1084.                  _("Selection:"), 1.0, 0.5,
  1085.                  box, 1, FALSE);
  1086.  
  1087.   gtk_widget_show (dlg);
  1088.  
  1089.   gtk_main ();
  1090.   gdk_flush ();
  1091.  
  1092.   for (i = 0; i < cellw_adjust.nguides; i++)
  1093.     gimp_image_delete_guide (image_ID, cellw_adjust.guides[i]);
  1094.   for (i = 0; i < cellh_adjust.nguides; i++)
  1095.     gimp_image_delete_guide (image_ID, cellh_adjust.guides[i]);
  1096.  
  1097.   if (run_flag)
  1098.     {
  1099.       /* Fix up bogus values */
  1100.       gihparams.ncells =
  1101.     MIN (gihparams.ncells, 
  1102.          num_useable_layers * gihparams.rows * gihparams.cols);
  1103.     }
  1104.  
  1105.   return run_flag;
  1106. }
  1107.  
  1108. static gboolean
  1109. gih_save_one_brush (gint          fd,
  1110.             GimpPixelRgn *pixel_rgn,
  1111.             gchar        *name)
  1112. {
  1113.   BrushHeader  header;
  1114.   guint        x;
  1115.   guint        y;
  1116.   guchar      *buffer;
  1117.  
  1118.   g_return_val_if_fail (fd != -1, FALSE);
  1119.   g_return_val_if_fail (pixel_rgn != NULL, FALSE);
  1120.  
  1121.   if (!name)
  1122.     name = g_strdup (_("Unnamed"));
  1123.  
  1124.   if (pixel_rgn->bpp != 2 && pixel_rgn->bpp != 4)
  1125.     {
  1126.       g_free (name);
  1127.       return FALSE;
  1128.     }
  1129.  
  1130.   if (pixel_rgn->w < 1 || pixel_rgn->h < 1)
  1131.     {
  1132.       g_free (name);
  1133.       return FALSE;
  1134.     }
  1135.  
  1136.   header.header_size  = 
  1137.     g_htonl (sizeof (header) + strlen (name) + 1);
  1138.   header.version      = g_htonl (2);
  1139.   header.width        = g_htonl (pixel_rgn->w);
  1140.   header.height       = g_htonl (pixel_rgn->h);
  1141.   header.bytes        = g_htonl (pixel_rgn->bpp == 2 ? 1 : 4);
  1142.   header.magic_number = g_htonl (GBRUSH_MAGIC);
  1143.   header.spacing      = g_htonl (info.spacing);
  1144.  
  1145.   if (write (fd, &header, sizeof (header)) != sizeof (header)) 
  1146.     return FALSE;
  1147.   
  1148.   if (write (fd, name, strlen (name) + 1) !=
  1149.       strlen (name) + 1) 
  1150.     {
  1151.       g_free (name);
  1152.       return FALSE;
  1153.     }
  1154.  
  1155.   g_free (name);
  1156.  
  1157.   buffer = g_malloc (pixel_rgn->w * pixel_rgn->bpp);
  1158.  
  1159.   for (y = 0; y < pixel_rgn->h; y++)
  1160.     {
  1161.       gimp_pixel_rgn_get_row (pixel_rgn, buffer,
  1162.                   0 + pixel_rgn->x, y + pixel_rgn->y,
  1163.                   pixel_rgn->w);
  1164.  
  1165.       if (pixel_rgn->bpp == 2) /* GRAYA */
  1166.     {
  1167.       for (x = 0; x < pixel_rgn->w; x++)
  1168.         {
  1169.           guchar value = 255 - buffer[2 * x];
  1170.  
  1171.           if (write (fd, &value, 1) != 1)
  1172.         {
  1173.           g_free (buffer);
  1174.           return FALSE;
  1175.         }
  1176.         }
  1177.     }
  1178.       else if (pixel_rgn->bpp == 4) /* RGBA */
  1179.     {
  1180.       if (write (fd, buffer, pixel_rgn->w * pixel_rgn->bpp) != 
  1181.           pixel_rgn->w * pixel_rgn->bpp) 
  1182.         {
  1183.           g_free (buffer);
  1184.           return FALSE;
  1185.         }
  1186.     }
  1187.     }
  1188.  
  1189.   g_free (buffer);
  1190.  
  1191.   return TRUE;
  1192. }
  1193.  
  1194. static gboolean
  1195. gih_save_image (gchar  *filename,
  1196.         gint32  image_ID,
  1197.         gint32  orig_image_ID,
  1198.         gint32  drawable_ID)
  1199. {
  1200.   GimpDrawable *drawable;
  1201.   GimpPixelRgn  pixel_rgn;
  1202.   GimpParasite *pipe_parasite;
  1203.   gchar *header;
  1204.   gchar *msg, *parstring;
  1205.   gint32 *layer_ID;
  1206.   gint fd;
  1207.   gint nlayers, layer, row, col;
  1208.   gint imagew, imageh, offsetx, offsety;
  1209.   gint k, x, y, thisx, thisy, xnext, ynext, thisw, thish;
  1210.  
  1211.   if (gihparams.ncells < 1)
  1212.     return FALSE;
  1213.  
  1214.   imagew = gimp_image_width (image_ID);
  1215.   imageh = gimp_image_height (image_ID);
  1216.   gimp_tile_cache_size (gimp_tile_height () * imagew * 4);
  1217.  
  1218.   msg = g_strdup_printf (_("Saving %s:"), filename);
  1219.   gimp_progress_init (msg);
  1220.   g_free (msg);
  1221.  
  1222.   fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0644);
  1223.   
  1224.   if (fd == -1) 
  1225.     {
  1226.       g_message( _("Unable to open %s"), filename);
  1227.       return FALSE;
  1228.     }
  1229.  
  1230.   parstring = gimp_pixpipe_params_build (&gihparams);
  1231.  
  1232.   header = g_strdup_printf ("%s\n%d %s\n",
  1233.                 info.description, gihparams.ncells, parstring);
  1234.  
  1235.   if (write (fd, header, strlen (header)) != strlen (header))
  1236.     {
  1237.       g_free (header);
  1238.       g_free (parstring);
  1239.       close (fd);
  1240.       return FALSE;
  1241.     }
  1242.  
  1243.   g_free (header);
  1244.  
  1245.   pipe_parasite = gimp_parasite_new ("gimp-brush-pipe-parameters",
  1246.                      GIMP_PARASITE_PERSISTENT,
  1247.                      strlen (parstring) + 1, parstring);
  1248.   gimp_image_parasite_attach (orig_image_ID, pipe_parasite);
  1249.   gimp_parasite_free (pipe_parasite);
  1250.  
  1251.   g_free (parstring);
  1252.  
  1253.   layer_ID = gimp_image_get_layers (image_ID, &nlayers);
  1254.   
  1255.   k = 0;
  1256.   for (layer = 0; layer < nlayers; layer++)
  1257.     {
  1258.       if (!gimp_drawable_has_alpha (layer_ID[layer]))
  1259.     continue;
  1260.  
  1261.       drawable = gimp_drawable_get (layer_ID[layer]);
  1262.       gimp_drawable_offsets (layer_ID[layer], &offsetx, &offsety);
  1263.  
  1264.       for (row = 0; row < gihparams.rows; row++)
  1265.     {
  1266.       y = (row * imageh) / gihparams.rows ;
  1267.       ynext = ((row + 1) * imageh / gihparams.rows);
  1268.       /* Assume layer is offset to positive direction in x and y.
  1269.        * That's reasonable, as otherwise all of the layer
  1270.        * won't be visible.
  1271.        * thisy and thisx are in the drawable's coordinate space.
  1272.        */
  1273.       thisy = MAX (0, y - offsety);
  1274.       thish = (ynext - offsety) - thisy;
  1275.       thish = MIN (thish, drawable->height - thisy);
  1276.  
  1277.       for (col = 0; col < gihparams.cols; col++)
  1278.         {
  1279.           x = (col * imagew / gihparams.cols);
  1280.           xnext = ((col + 1) * imagew / gihparams.cols);
  1281.           thisx = MAX (0, x - offsetx);
  1282.           thisw = (xnext - offsetx) - thisx;
  1283.           thisw = MIN (thisw, drawable->width - thisx);
  1284.           gimp_pixel_rgn_init (&pixel_rgn, drawable, thisx, thisy, 
  1285.                    thisw, thish, FALSE, FALSE);
  1286.           
  1287.           if (! gih_save_one_brush (fd, &pixel_rgn, 
  1288.                     gimp_drawable_name (layer_ID[layer])))
  1289.         {
  1290.           close (fd);
  1291.           return FALSE;
  1292.         }
  1293.  
  1294.           k++;
  1295.           gimp_progress_update ((gdouble) k / gihparams.ncells);
  1296.         }
  1297.     }
  1298.  
  1299.     }
  1300.   
  1301.   gimp_progress_update (1.0);
  1302.  
  1303.   close (fd);
  1304.  
  1305.   return TRUE;
  1306. }
  1307.  
  1308.