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 / gbr.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-20  |  16.3 KB  |  628 lines

  1. /*
  2.  * gbr plug-in version 1.00
  3.  * Loads/saves version 2 GIMP .gbr files, by Tim Newsome <drz@frody.bloke.com>
  4.  * Some bits stolen from the .99.7 source tree.
  5.  * 
  6.  * Added in GBR version 1 support after learning that there wasn't a 
  7.  * tool to read them.  
  8.  * July 6, 1998 by Seth Burgess <sjburges@gimp.org>
  9.  *
  10.  * Dec 17, 2000
  11.  * Load and save GIMP brushes in GRAY or RGBA.  jtl + neo
  12.  * 
  13.  *
  14.  * TODO: Give some better error reporting on not opening files/bad headers
  15.  *       etc. 
  16.  */
  17.  
  18. #include "config.h"
  19.  
  20. #include <glib.h>        /* Include early for G_OS_WIN32 */
  21.  
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <fcntl.h>
  25. #ifdef HAVE_UNISTD_H
  26. #include <unistd.h>
  27. #endif
  28. #include <ctype.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <math.h>
  33.  
  34. #ifdef G_OS_WIN32
  35. #include <io.h>
  36. #endif
  37.  
  38. #ifndef _O_BINARY
  39. #define _O_BINARY 0
  40. #endif
  41.  
  42. #include <gtk/gtk.h>
  43.  
  44. #include <libgimp/gimp.h>
  45. #include <libgimp/gimpui.h>
  46.  
  47. #include "app/brush_header.h"
  48. #include "app/pattern_header.h"
  49.  
  50. #include "libgimp/stdplugins-intl.h"
  51.  
  52.  
  53. /* Declare local data types
  54.  */
  55.  
  56. typedef struct
  57. {
  58.   gchar description[256];
  59.   gint  spacing;
  60. } t_info;
  61.  
  62. t_info info = 
  63. {   /* Initialize to this, change if non-interactive later */
  64.   "GIMP Brush",     
  65.   10
  66. };
  67.  
  68. gboolean run_flag = FALSE;
  69.  
  70.  
  71. /* Declare some local functions.
  72.  */
  73. static void   query          (void);
  74. static void   run            (gchar      *name,
  75.                   gint        nparams,
  76.                   GimpParam  *param,
  77.                   gint       *nreturn_vals,
  78.                   GimpParam **return_vals);
  79.  
  80. static gint32 load_image     (gchar      *filename);
  81. static gint   save_image     (gchar      *filename,
  82.                   gint32      image_ID,
  83.                   gint32      drawable_ID);
  84.  
  85. static gint   save_dialog    (void);
  86. static void   ok_callback    (GtkWidget  *widget, 
  87.                   gpointer    data);
  88. static void   entry_callback (GtkWidget  *widget, 
  89.                   gpointer    data);
  90.  
  91.  
  92. GimpPlugInInfo PLUG_IN_INFO =
  93. {
  94.   NULL,  /* init_proc  */
  95.   NULL,  /* quit_proc  */
  96.   query, /* query_proc */
  97.   run,   /* run_proc   */
  98. };
  99.  
  100.  
  101. MAIN ()
  102.  
  103. static void
  104. query (void)
  105. {
  106.   static GimpParamDef load_args[] =
  107.   {
  108.     { GIMP_PDB_INT32,  "run_mode",       "Interactive, non-interactive" },
  109.     { GIMP_PDB_STRING, "filename",       "The name of the file to load" },
  110.     { GIMP_PDB_STRING, "raw_filename",   "The name of the file to load" }
  111.   };
  112.   static GimpParamDef load_return_vals[] =
  113.   {
  114.     { GIMP_PDB_IMAGE,  "image",          "Output image" }
  115.   };
  116.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  117.   static gint nload_return_vals = (sizeof (load_return_vals) /
  118.                    sizeof (load_return_vals[0]));
  119.  
  120.   static GimpParamDef save_args[] =
  121.   {
  122.     { GIMP_PDB_INT32,    "run_mode",     "Interactive, non-interactive" },
  123.     { GIMP_PDB_IMAGE,    "image",        "Input image" },
  124.     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save" },
  125.     { GIMP_PDB_STRING,   "filename",     "The name of the file to save the image in" },
  126.     { GIMP_PDB_STRING,   "raw_filename", "The name of the file to save the image in" },
  127.     { GIMP_PDB_INT32,    "spacing",      "Spacing of the brush" },
  128.     { GIMP_PDB_STRING,   "description",  "Short description of the brush" }
  129.   };
  130.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  131.  
  132.   gimp_install_procedure ("file_gbr_load",
  133.                           "Loads GIMP brushes (1 or 4 bpp and old .gpb format)",
  134.                           "FIXME: write help",
  135.                           "Tim Newsome, Jens Lautenbacher, Sven Neumann",
  136.                           "Tim Newsome, Jens Lautenbacher, Sven Neumann",
  137.                           "1997-2000",
  138.                           "<Load>/GBR",
  139.                           NULL,
  140.                           GIMP_PLUGIN,
  141.                           nload_args, nload_return_vals,
  142.                           load_args, load_return_vals);
  143.  
  144.   gimp_install_procedure ("file_gbr_save",
  145.                           "saves files in the .gbr file format",
  146.                           "Yeah!",
  147.                           "Tim Newsome, Jens Lautenbacher, Sven Neumann",
  148.                           "Tim Newsome, Jens Lautenbacher, Sven Neumann",
  149.                           "1997-2000",
  150.                           "<Save>/GBR",
  151.                           "RGBA, GRAY",
  152.                           GIMP_PLUGIN,
  153.                           nsave_args, 0,
  154.                           save_args, NULL);
  155.  
  156.   gimp_register_magic_load_handler ("file_gbr_load",
  157.                     "gbr, gpb",
  158.                     "",
  159.                     "20, string, GIMP");
  160.   gimp_register_save_handler       ("file_gbr_save",
  161.                     "gbr",
  162.                     "");
  163. }
  164.  
  165. static void
  166. run (gchar      *name,
  167.      gint        nparams,
  168.      GimpParam  *param,
  169.      gint       *nreturn_vals,
  170.      GimpParam **return_vals)
  171. {
  172.   static GimpParam     values[2];
  173.   GimpRunModeType      run_mode;
  174.   GimpPDBStatusType    status = GIMP_PDB_SUCCESS;
  175.   gint32               image_ID;
  176.   gint32               drawable_ID;
  177.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  178.  
  179.   run_mode = param[0].data.d_int32;
  180.  
  181.   *nreturn_vals = 1;
  182.   *return_vals = values;
  183.   values[0].type          = GIMP_PDB_STATUS;
  184.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  185.  
  186.   if (strcmp (name, "file_gbr_load") == 0) 
  187.     {
  188.       image_ID = load_image (param[1].data.d_string);
  189.       
  190.       if (image_ID != -1) 
  191.     {
  192.       *nreturn_vals = 2;
  193.       values[1].type         = GIMP_PDB_IMAGE;
  194.       values[1].data.d_image = image_ID;
  195.     }
  196.       else
  197.     {
  198.       status = GIMP_PDB_EXECUTION_ERROR;
  199.     }
  200.     }
  201.   else if (strcmp (name, "file_gbr_save") == 0) 
  202.     {
  203.       image_ID    = param[1].data.d_int32;
  204.       drawable_ID = param[2].data.d_int32;
  205.  
  206.       /*  eventually export the image */ 
  207.       switch (run_mode)
  208.     {
  209.     case GIMP_RUN_INTERACTIVE:
  210.     case GIMP_RUN_WITH_LAST_VALS:
  211.       INIT_I18N_UI();
  212.       gimp_ui_init ("gbr", FALSE);
  213.       export = gimp_export_image (&image_ID, &drawable_ID, "GBR", 
  214.                       GIMP_EXPORT_CAN_HANDLE_GRAY  |
  215.                       GIMP_EXPORT_CAN_HANDLE_RGB   |
  216.                       GIMP_EXPORT_CAN_HANDLE_ALPHA);
  217.       if (export == GIMP_EXPORT_CANCEL)
  218.         {
  219.           values[0].data.d_status = GIMP_PDB_CANCEL;
  220.           return;
  221.         }
  222.       break;
  223.     default:
  224.       INIT_I18N();
  225.       break;
  226.     }
  227.  
  228.       switch (run_mode) 
  229.     {
  230.     case GIMP_RUN_INTERACTIVE:
  231.       /*  Possibly retrieve data  */
  232.       strncpy (info.description, gimp_drawable_name (drawable_ID), 256);
  233.       gimp_get_data ("file_gbr_save", &info);
  234.       if (! save_dialog ())
  235.         status = GIMP_PDB_CANCEL;
  236.       break;
  237.  
  238.     case GIMP_RUN_NONINTERACTIVE:  
  239.       /* FIXME - need a real GIMP_RUN_NONINTERACTIVE */
  240.       if (nparams != 7)
  241.         {
  242.           status = GIMP_PDB_CALLING_ERROR;
  243.         }
  244.       else
  245.         {
  246.           info.spacing = (param[5].data.d_int32);
  247.           strncpy (info.description, param[6].data.d_string, 256);    
  248.         }
  249.       break;
  250.  
  251.     case GIMP_RUN_WITH_LAST_VALS:
  252.       gimp_get_data ("file_gbr_save", &info);
  253.       break;
  254.     }
  255.  
  256.       if (status == GIMP_PDB_SUCCESS)
  257.     {
  258.       if (save_image (param[3].data.d_string, image_ID, drawable_ID)) 
  259.         {
  260.           gimp_set_data ("file_gbr_save", &info, sizeof(info));
  261.         }
  262.       else
  263.         {
  264.           status = GIMP_PDB_EXECUTION_ERROR;
  265.         }
  266.     }
  267.  
  268.       if (export == GIMP_EXPORT_EXPORT)
  269.     gimp_image_delete (image_ID);
  270.     }
  271.   else
  272.     {
  273.       status = GIMP_PDB_CALLING_ERROR;
  274.     }
  275.  
  276.   values[0].data.d_status = status;
  277. }
  278.  
  279. static gint32 
  280. load_image (gchar *filename) 
  281. {
  282.   gchar         *temp;
  283.   gchar         *name = NULL;
  284.   gint           fd;
  285.   BrushHeader    bh;
  286.   guchar        *brush_buf   = NULL;
  287.   gint32         image_ID;
  288.   gint32         layer_ID;
  289.   GimpDrawable  *drawable;
  290.   GimpPixelRgn   pixel_rgn;
  291.   gint           version_extra;
  292.   gint           bn_size;
  293.   GimpImageBaseType  base_type;
  294.   GimpImageType      image_type;
  295.   
  296.   temp = g_strdup_printf (_("Loading %s:"), filename);
  297.   gimp_progress_init (temp);
  298.   g_free (temp);
  299.   
  300.   fd = open (filename, O_RDONLY | _O_BINARY);
  301.   
  302.   if (fd == -1) 
  303.     {
  304.       return -1;
  305.     }
  306.   
  307.   if (read (fd, &bh, sizeof (bh)) != sizeof (bh)) 
  308.     {
  309.       close (fd);
  310.       return -1;
  311.     }
  312.  
  313.   /*  rearrange the bytes in each unsigned int  */
  314.   bh.header_size  = g_ntohl (bh.header_size);
  315.   bh.version      = g_ntohl (bh.version);
  316.   bh.width        = g_ntohl (bh.width);
  317.   bh.height       = g_ntohl (bh.height);
  318.   bh.bytes        = g_ntohl (bh.bytes);
  319.   bh.magic_number = g_ntohl (bh.magic_number);
  320.   bh.spacing      = g_ntohl (bh.spacing);
  321.   
  322.   /* How much extra to add to the header seek - 1 needs a bit more */
  323.   version_extra = 0;
  324.   
  325.   if (bh.version == 1) 
  326.     {
  327.       /* Version 1 didn't know about spacing */    
  328.       bh.spacing = 25;
  329.       /* And we need to rewind the handle a bit too */
  330.       lseek (fd, -8, SEEK_CUR);
  331.       version_extra = 8;
  332.     }
  333.   /* Version 1 didn't know about magic either */
  334.   if ((bh.version != 1 && 
  335.        (bh.magic_number != GBRUSH_MAGIC || bh.version != 2)) ||
  336.       bh.header_size <= sizeof (bh)) 
  337.     {
  338.       close (fd);
  339.       return -1;
  340.     }
  341.   
  342.   if ((bn_size = (bh.header_size - sizeof (bh))) > 0)
  343.     {
  344.       name = g_new (gchar, bn_size);
  345.       if ((read (fd, name, bn_size)) < bn_size)
  346.     {
  347.       g_message (_("Error in GIMP brush file \"%s\"."), filename);
  348.       close (fd);
  349.       g_free (name);
  350.       return -1;
  351.     }
  352.     }
  353.   else
  354.     {
  355.       name = g_strdup (_("Unnamed"));
  356.     }
  357.  
  358.   /* Now there's just raw data left. */
  359.   
  360.   brush_buf = g_malloc (bh.width * bh.height * bh.bytes);
  361.  
  362.   if (read (fd, brush_buf, 
  363.         bh.width * bh.height * bh.bytes) != bh.width * bh.height * bh.bytes) 
  364.     {
  365.       close (fd);
  366.       g_free (brush_buf);
  367.       g_free (name);
  368.       return -1;
  369.     }
  370.  
  371.  
  372.   if (bh.bytes == 1)
  373.     {
  374.       PatternHeader ph;
  375.  
  376.       /*  For backwards-compatibility, check if a pattern follows.
  377.       The obsolete .gpb format did it this way.  */
  378.  
  379.       if (read (fd, &ph, sizeof(ph)) == sizeof(ph)) 
  380.     {
  381.       /*  rearrange the bytes in each unsigned int  */
  382.       ph.header_size  = g_ntohl (ph.header_size);
  383.       ph.version      = g_ntohl (ph.version);
  384.       ph.width        = g_ntohl (ph.width);
  385.       ph.height       = g_ntohl (ph.height);
  386.       ph.bytes        = g_ntohl (ph.bytes);
  387.       ph.magic_number = g_ntohl (ph.magic_number);
  388.  
  389.       if (ph.magic_number == GPATTERN_MAGIC && ph.version == 1 &&
  390.           ph.header_size > sizeof (ph) &&
  391.           ph.bytes == 3 && ph.width == bh.width && ph.height == bh.height &&
  392.           lseek (fd, ph.header_size - sizeof (ph), SEEK_CUR) > 0)
  393.         {
  394.           guchar *plain_brush = brush_buf;
  395.           gint    i;
  396.  
  397.           bh.bytes = 4;
  398.           brush_buf = g_malloc (4 * bh.width * bh.height);
  399.           
  400.           for (i = 0; i < ph.width * ph.height; i++)
  401.         {
  402.           if (read (fd, brush_buf + i * 4, 3) != 3)
  403.             {
  404.               close (fd);
  405.               g_free (name);
  406.               g_free (plain_brush);
  407.               g_free (brush_buf);
  408.               return -1;
  409.             }
  410.           brush_buf[i * 4 + 3] = plain_brush[i];
  411.         }
  412.           g_free (plain_brush);
  413.         }
  414.     }
  415.     }
  416.  
  417.   /*
  418.    * Create a new image of the proper size and 
  419.    * associate the filename with it.
  420.    */
  421.   
  422.   switch (bh.bytes)
  423.     {
  424.     case 1:
  425.       base_type = GIMP_GRAY;
  426.       image_type = GIMP_GRAY_IMAGE;
  427.       break;
  428.     case 4:
  429.       base_type = GIMP_RGB;
  430.       image_type = GIMP_RGBA_IMAGE;
  431.       break;
  432.     default:
  433.       g_message ("Unsupported brush depth: %d\nGIMP Brushes must be GRAY or RGBA\n",
  434.          bh.bytes);
  435.       return -1;
  436.     }
  437.  
  438.   image_ID = gimp_image_new (bh.width, bh.height, base_type);
  439.   gimp_image_set_filename (image_ID, filename);
  440.   
  441.   layer_ID = gimp_layer_new (image_ID, name, 
  442.                  bh.width, bh.height, 
  443.                  image_type, 100, GIMP_NORMAL_MODE);
  444.   gimp_image_add_layer (image_ID, layer_ID, 0);
  445.  
  446.   g_free (name);
  447.  
  448.   drawable = gimp_drawable_get (layer_ID);
  449.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 
  450.                0, 0, drawable->width, drawable->height, 
  451.                TRUE, FALSE);
  452.  
  453.   gimp_pixel_rgn_set_rect (&pixel_rgn, (guchar *) brush_buf, 
  454.                0, 0, bh.width, bh.height);
  455.   g_free (brush_buf);
  456.  
  457.   if (image_type == GIMP_GRAY_IMAGE)
  458.     gimp_invert (layer_ID);
  459.  
  460.   close (fd);
  461.  
  462.   gimp_drawable_flush (drawable);
  463.   gimp_progress_update (1.0);
  464.   
  465.   return image_ID;
  466. }
  467.  
  468. static gint 
  469. save_image (gchar  *filename, 
  470.         gint32  image_ID, 
  471.         gint32  drawable_ID) 
  472. {
  473.   gint          fd;
  474.   BrushHeader   bh;
  475.   guchar       *buffer;
  476.   GimpDrawable *drawable;
  477.   gint          line;
  478.   gint          x;
  479.   GimpPixelRgn  pixel_rgn;
  480.   gchar        *temp;
  481.   
  482.   if (gimp_drawable_type (drawable_ID) != GIMP_GRAY_IMAGE &&
  483.       gimp_drawable_type (drawable_ID) != GIMP_RGBA_IMAGE)
  484.     {
  485.       g_message (_("GIMP brushes are either GRAYSCALE or RGBA\n"));
  486.       return FALSE;
  487.     }
  488.  
  489.   temp = g_strdup_printf (_("Saving %s:"), filename);
  490.   gimp_progress_init (temp);
  491.   g_free (temp);
  492.   
  493.   drawable = gimp_drawable_get (drawable_ID);
  494.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 
  495.                0, 0, drawable->width, drawable->height, 
  496.                FALSE, FALSE);
  497.   
  498.   fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0644);
  499.   
  500.   if (fd == -1) 
  501.     {
  502.       g_message( _("Unable to open %s"), filename);
  503.       return FALSE;
  504.     }
  505.  
  506.   bh.header_size  = g_htonl (sizeof (bh) + strlen (info.description) + 1);
  507.   bh.version      = g_htonl (2);
  508.   bh.width        = g_htonl (drawable->width);
  509.   bh.height       = g_htonl (drawable->height);
  510.   bh.bytes        = g_htonl (drawable->bpp);
  511.   bh.magic_number = g_htonl (GBRUSH_MAGIC);
  512.   bh.spacing      = g_htonl (info.spacing);
  513.   
  514.   if (write (fd, &bh, sizeof (bh)) != sizeof (bh)) 
  515.     {
  516.       close (fd);
  517.       return FALSE;
  518.     }
  519.   
  520.   if (write (fd, info.description, strlen(info.description) + 1) !=
  521.       strlen (info.description) + 1) 
  522.     {
  523.       close(fd);
  524.       return FALSE;
  525.     }
  526.   
  527.   buffer = g_malloc (drawable->width * drawable->bpp);
  528.   for (line = 0; line < drawable->height; line++) 
  529.     {
  530.       gimp_pixel_rgn_get_row (&pixel_rgn, buffer, 0, line, drawable->width);
  531.  
  532.       if (drawable->bpp == 1)
  533.     {
  534.       for (x = 0; x < drawable->width; x++)
  535.         buffer[x] = 255 - buffer[x];
  536.     }
  537.  
  538.       if (write (fd, buffer, 
  539.          drawable->width * drawable->bpp) != drawable->width * drawable->bpp) 
  540.     {
  541.       g_free (buffer);
  542.       close (fd);
  543.       return FALSE;
  544.     }
  545.       gimp_progress_update ((gdouble) line / (gdouble) drawable->height);
  546.     }
  547.  
  548.   g_free (buffer);  
  549.   close (fd);
  550.   
  551.   return TRUE;
  552. }
  553.  
  554. static gint 
  555. save_dialog (void)
  556. {
  557.   GtkWidget *dlg;
  558.   GtkWidget *table;
  559.   GtkWidget *entry;
  560.   GtkWidget *spinbutton;
  561.   GtkObject *adj;
  562.  
  563.   dlg = gimp_dialog_new (_("Save as Brush"), "gbr",
  564.              gimp_standard_help_func, "filters/gbr.html",
  565.              GTK_WIN_POS_MOUSE,
  566.              FALSE, TRUE, FALSE,
  567.  
  568.              _("OK"), ok_callback,
  569.              NULL, NULL, NULL, TRUE, FALSE,
  570.              _("Cancel"), gtk_widget_destroy,
  571.              NULL, 1, NULL, FALSE, TRUE,
  572.  
  573.              NULL);
  574.  
  575.   gtk_signal_connect (GTK_OBJECT(dlg), "destroy",
  576.               GTK_SIGNAL_FUNC (gtk_main_quit),
  577.               NULL);
  578.  
  579.   /* The main table */
  580.   table = gtk_table_new (2, 2, FALSE);
  581.   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
  582.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  583.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  584.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
  585.   gtk_widget_show (table);
  586.  
  587.   spinbutton = gimp_spin_button_new (&adj,
  588.                      info.spacing, 1, 1000, 1, 10, 0, 1, 0);
  589.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  590.                  _("Spacing:"), 1.0, 0.5,
  591.                  spinbutton, 1, TRUE);
  592.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  593.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  594.               &info.spacing);
  595.  
  596.   entry = gtk_entry_new ();
  597.   gtk_widget_set_usize (entry, 200, 0);
  598.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
  599.                  _("Description:"), 1.0, 0.5,
  600.                  entry, 1, FALSE);
  601.   gtk_entry_set_text (GTK_ENTRY (entry), info.description);
  602.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  603.               GTK_SIGNAL_FUNC (entry_callback),
  604.               info.description);
  605.   
  606.   gtk_widget_show (dlg);
  607.   
  608.   gtk_main ();
  609.   gdk_flush ();
  610.   
  611.   return run_flag;
  612. }
  613.  
  614. static void 
  615. ok_callback (GtkWidget *widget, 
  616.          gpointer   data)
  617. {
  618.   run_flag = TRUE;
  619.   gtk_widget_destroy (GTK_WIDGET (data));
  620. }
  621.  
  622. static void 
  623. entry_callback (GtkWidget *widget, 
  624.         gpointer   data)
  625. {
  626.   strncpy (info.description, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
  627. }
  628.