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

  1. /*
  2.  * pat plug-in version 1.01
  3.  * Loads/saves version 1 GIMP .pat files, by Tim Newsome <drz@frody.bloke.com>
  4.  * Some bits stolen from the .99.7 source tree.
  5.  * Updated to fix various outstanding problems, brief help -- Nick Lamb
  6.  * njl195@zepler.org.uk, April 2000
  7.  */
  8.  
  9. #include "config.h"
  10.  
  11. #include <setjmp.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h>
  15. #ifdef HAVE_UNISTD_H
  16. #include <unistd.h>
  17. #endif
  18. #include <ctype.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22.  
  23. #include <libgimp/gimp.h>
  24. #include <libgimp/gimpui.h>
  25.  
  26. #include "libgimp/stdplugins-intl.h"
  27.  
  28.  
  29. #ifdef G_OS_WIN32
  30. #include <io.h>
  31. #endif
  32.  
  33. #ifndef _O_BINARY
  34. #define _O_BINARY 0
  35. #endif
  36.  
  37. #include "app/pattern_header.h"
  38.  
  39.  
  40. /*  local function prototypes  */
  41.  
  42. static void       query          (void);
  43. static void       run            (gchar        *name,
  44.                   gint          nparams,
  45.                   GimpParam    *param,
  46.                   gint         *nreturn_vals,
  47.                   GimpParam   **return_vals);
  48. static gint32     load_image     (gchar        *filename);
  49. static gboolean   save_image     (gchar        *filename,
  50.                   gint32        image_ID,
  51.                   gint32        drawable_ID);
  52.  
  53. static gboolean   save_dialog    (void);
  54. static void       ok_callback    (GtkWidget    *widget,
  55.                   gpointer      data);
  56. static void       entry_callback (GtkWidget    *widget,
  57.                   gpointer      data);
  58.  
  59.  
  60. GimpPlugInInfo PLUG_IN_INFO =
  61. {
  62.   NULL,  /* init_proc  */
  63.   NULL,  /* quit_proc  */
  64.   query, /* query_proc */
  65.   run,   /* run_proc   */
  66. };
  67.  
  68. /*  private variables  */
  69.  
  70. static gchar    description[256] = "GIMP Pattern";
  71. static gboolean run_flag = FALSE;
  72.  
  73.  
  74.  
  75. MAIN ()
  76.  
  77. static void
  78. query (void)
  79. {
  80.   static GimpParamDef load_args[] =
  81.   {
  82.     { GIMP_PDB_INT32,  "run_mode", "Interactive, non-interactive" },
  83.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  84.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to load" }
  85.   };
  86.   static GimpParamDef load_return_vals[] =
  87.   {
  88.     { GIMP_PDB_IMAGE, "image", "Output image" }
  89.   };
  90.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  91.   static gint nload_return_vals = (sizeof (load_return_vals) /
  92.                    sizeof (load_return_vals[0]));
  93.  
  94.   static GimpParamDef save_args[] =
  95.   {
  96.     { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive" },
  97.     { GIMP_PDB_IMAGE,    "image", "Input image" },
  98.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  99.     { GIMP_PDB_STRING,   "filename", "The name of the file to save the image in" },
  100.     { GIMP_PDB_STRING,   "raw_filename", "The name of the file to save the image in" },
  101.     { GIMP_PDB_STRING,   "description", "Short description of the pattern" },
  102.   };
  103.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  104.  
  105.   gimp_install_procedure ("file_pat_load",
  106.                           "Loads Gimp's .PAT pattern files",
  107.                           "The images in the pattern dialog can be loaded "
  108.               "directly with this plug-in",
  109.                           "Tim Newsome",
  110.                           "Tim Newsome",
  111.                           "1997",
  112.                           "<Load>/PAT",
  113.                           NULL,
  114.                           GIMP_PLUGIN,
  115.                           nload_args, nload_return_vals,
  116.                           load_args, load_return_vals);
  117.  
  118.   gimp_install_procedure ("file_pat_save",
  119.                           "Saves Gimp pattern file (.PAT)",
  120.                           "New Gimp patterns can be created by saving them "
  121.               "in the appropriate place with this plug-in.",
  122.                           "Tim Newsome",
  123.                           "Tim Newsome",
  124.                           "1997",
  125.                           "<Save>/PAT",
  126.                           "RGB, GRAY",
  127.                           GIMP_PLUGIN,
  128.                           nsave_args, 0,
  129.                           save_args, NULL);
  130.  
  131.   gimp_register_magic_load_handler ("file_pat_load",
  132.                     "pat",
  133.                     "",
  134.                     "20,string,GPAT");
  135.   gimp_register_save_handler       ("file_pat_save",
  136.                     "pat",
  137.                     "");
  138. }
  139.  
  140. static void
  141. run (gchar      *name,
  142.      gint        nparams,
  143.      GimpParam  *param,
  144.      gint       *nreturn_vals,
  145.      GimpParam **return_vals)
  146. {
  147.   static GimpParam     values[2];
  148.   GimpRunModeType      run_mode;
  149.   GimpPDBStatusType    status = GIMP_PDB_SUCCESS;
  150.   gint32               image_ID;
  151.   gint32               drawable_ID;
  152.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  153.  
  154.   run_mode = param[0].data.d_int32;
  155.  
  156.   *nreturn_vals = 1;
  157.   *return_vals  = values;
  158.   values[0].type          = GIMP_PDB_STATUS;
  159.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  160.  
  161.   if (strcmp (name, "file_pat_load") == 0) 
  162.     {
  163.       INIT_I18N();
  164.       image_ID = load_image (param[1].data.d_string);
  165.  
  166.       if (image_ID != -1) 
  167.     {
  168.       *nreturn_vals = 2;
  169.       values[1].type         = GIMP_PDB_IMAGE;
  170.       values[1].data.d_image = image_ID;
  171.     }
  172.       else
  173.     {
  174.       status = GIMP_PDB_EXECUTION_ERROR;
  175.     }
  176.     }
  177.   else if (strcmp (name, "file_pat_save") == 0) 
  178.     {
  179.       image_ID    = param[1].data.d_int32;
  180.       drawable_ID = param[2].data.d_int32;
  181.  
  182.       /*  eventually export the image */ 
  183.       switch (run_mode)
  184.     {
  185.     case GIMP_RUN_INTERACTIVE:
  186.     case GIMP_RUN_WITH_LAST_VALS:
  187.       INIT_I18N_UI();
  188.       gimp_ui_init ("pat", FALSE);
  189.       export = gimp_export_image (&image_ID, &drawable_ID, "PAT", 
  190.                       (GIMP_EXPORT_CAN_HANDLE_GRAY |
  191.                        GIMP_EXPORT_CAN_HANDLE_RGB));
  192.       if (export == GIMP_EXPORT_CANCEL)
  193.         {
  194.           values[0].data.d_status = GIMP_PDB_CANCEL;
  195.           return;
  196.         }
  197.       break;
  198.     default:
  199.       INIT_I18N();
  200.       break;
  201.     }
  202.  
  203.       switch (run_mode) 
  204.     {
  205.     case GIMP_RUN_INTERACTIVE:
  206.       /*  Possibly retrieve data  */
  207.       gimp_get_data ("file_pat_save", description);
  208.       if (!save_dialog ())
  209.         status = GIMP_PDB_CANCEL;
  210.       break;
  211.  
  212.     case GIMP_RUN_NONINTERACTIVE:
  213.       if (nparams != 6)
  214.         {
  215.           status = GIMP_PDB_CALLING_ERROR;
  216.         }
  217.       else
  218.         {
  219.           strcpy (description, param[5].data.d_string);
  220.         }
  221.       break;
  222.  
  223.     case GIMP_RUN_WITH_LAST_VALS:
  224.       gimp_get_data ("file_pat_save", description);
  225.       break;
  226.     }
  227.  
  228.       if (status == GIMP_PDB_SUCCESS)
  229.     {
  230.       if (save_image (param[3].data.d_string, image_ID, drawable_ID))
  231.         {
  232.           gimp_set_data ("file_pat_save", description, 256);
  233.         } 
  234.       else
  235.         {
  236.           status = GIMP_PDB_EXECUTION_ERROR;
  237.         }
  238.     }
  239.  
  240.       if (export == GIMP_EXPORT_EXPORT)
  241.     gimp_image_delete (image_ID);
  242.     }
  243.   else
  244.     {
  245.       status = GIMP_PDB_CALLING_ERROR;
  246.     }
  247.  
  248.   values[0].data.d_status = status;
  249. }
  250.  
  251. static gint32 
  252. load_image (gchar *filename) 
  253. {
  254.   gchar            *temp;
  255.   gint              fd;
  256.   PatternHeader     ph;
  257.   guchar           *buffer;
  258.   gint32            image_ID;
  259.   gint32            layer_ID;
  260.   GimpDrawable     *drawable;
  261.   gint              line;
  262.   GimpPixelRgn      pixel_rgn;
  263.   GimpImageBaseType base_type;
  264.   GimpImageType     image_type;
  265.  
  266.   temp = g_strdup_printf (_("Loading %s:"), filename);
  267.   gimp_progress_init (temp);
  268.   g_free (temp);
  269.  
  270.   fd = open (filename, O_RDONLY | _O_BINARY);
  271.  
  272.   if (fd == -1)
  273.     return -1;
  274.  
  275.   if (read (fd, &ph, sizeof (PatternHeader)) != sizeof (PatternHeader)) 
  276.     {
  277.       close (fd);
  278.       return -1;
  279.     }
  280.  
  281.   /*  rearrange the bytes in each unsigned int  */
  282.   ph.header_size  = g_ntohl (ph.header_size);
  283.   ph.version      = g_ntohl (ph.version);
  284.   ph.width        = g_ntohl (ph.width);
  285.   ph.height       = g_ntohl (ph.height);
  286.   ph.bytes        = g_ntohl (ph.bytes);
  287.   ph.magic_number = g_ntohl (ph.magic_number);
  288.  
  289.   if (ph.magic_number != GPATTERN_MAGIC ||
  290.       ph.version      != 1 ||
  291.       ph.header_size  <= sizeof (PatternHeader)) 
  292.     {
  293.       close (fd);
  294.       return -1;
  295.     }
  296.  
  297.   if (lseek (fd, ph.header_size - sizeof (PatternHeader), SEEK_CUR) != ph.header_size) 
  298.     {
  299.       close (fd);
  300.       return -1;
  301.     }
  302.  
  303.   /* Now there's just raw data left. */
  304.   
  305.   /*
  306.    * Create a new image of the proper size and associate the filename with it.
  307.    */
  308.  
  309.   switch (ph.bytes)
  310.     {
  311.     case 1:
  312.       base_type = GIMP_GRAY;
  313.       image_type = GIMP_GRAY_IMAGE;
  314.       break;
  315.     case 2:
  316.       base_type = GIMP_GRAY;
  317.       image_type = GIMP_GRAYA_IMAGE;
  318.       g_message ("Your pattern has an aplha channel,\n"
  319.          "please flatten and save it again to fix this.\n"
  320.          "Loading it anyway...");
  321.       break;
  322.     case 3:
  323.       base_type = GIMP_RGB;
  324.       image_type = GIMP_RGB_IMAGE;
  325.       break;
  326.     case 4:
  327.       base_type = GIMP_RGB;
  328.       image_type = GIMP_RGBA_IMAGE;
  329.       g_message ("Your pattern has an aplha channel,\n"
  330.          "please flatten and save it again to fix this.\n"
  331.          "Loading it anyway...");
  332.       break;
  333.     default:
  334.       g_message ("Unsupported pattern depth: %d\nGIMP Patterns must be GRAY or RGB\n", ph.bytes);
  335.       return -1;
  336.     }
  337.  
  338.   image_ID = gimp_image_new (ph.width, ph.height, base_type);
  339.   gimp_image_set_filename (image_ID, filename);
  340.  
  341.   layer_ID = gimp_layer_new (image_ID, _("Background"), ph.width, ph.height,
  342.                 image_type, 100, GIMP_NORMAL_MODE);
  343.   gimp_image_add_layer (image_ID, layer_ID, 0);
  344.  
  345.   drawable = gimp_drawable_get (layer_ID);
  346.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
  347.                drawable->width, drawable->height, 
  348.                TRUE, FALSE);
  349.  
  350.   buffer = g_malloc (ph.width * ph.bytes);
  351.  
  352.   for (line = 0; line < ph.height; line++) 
  353.     {
  354.       if (read (fd, buffer, ph.width * ph.bytes) != ph.width * ph.bytes)
  355.     {
  356.       close (fd);
  357.       g_free (buffer);
  358.       return -1;
  359.     }
  360.  
  361.       gimp_pixel_rgn_set_row (&pixel_rgn, buffer, 0, line, ph.width);
  362.  
  363.       gimp_progress_update ((gdouble) line / (gdouble) ph.height);
  364.     }
  365.  
  366.   gimp_drawable_flush (drawable);
  367.  
  368.   return image_ID;
  369. }
  370.  
  371. static gboolean
  372. save_image (gchar  *filename, 
  373.         gint32  image_ID, 
  374.         gint32  drawable_ID) 
  375. {
  376.   gint          fd;
  377.   PatternHeader ph;
  378.   guchar       *buffer;
  379.   GimpDrawable *drawable;
  380.   gint          line;
  381.   GimpPixelRgn  pixel_rgn;
  382.   gchar        *temp;
  383.  
  384.   temp = g_strdup_printf (_("Saving %s:"), filename);
  385.   gimp_progress_init (temp);
  386.   g_free (temp);
  387.  
  388.   drawable = gimp_drawable_get (drawable_ID);
  389.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width,
  390.                drawable->height, FALSE, FALSE);
  391.  
  392.   fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0644);
  393.  
  394.   if (fd == -1)
  395.     return FALSE;
  396.  
  397.   ph.header_size  = g_htonl (sizeof (PatternHeader) + strlen (description) + 1);
  398.   ph.version      = g_htonl (1);
  399.   ph.width        = g_htonl (drawable->width);
  400.   ph.height       = g_htonl (drawable->height);
  401.   ph.bytes        = g_htonl (drawable->bpp);
  402.   ph.magic_number = g_htonl (GPATTERN_MAGIC);
  403.  
  404.   if (write (fd, &ph, sizeof (PatternHeader)) != sizeof (PatternHeader)) 
  405.     {
  406.       close (fd);
  407.       return FALSE;
  408.     }
  409.  
  410.   if (write (fd, description, strlen (description) + 1) != strlen (description) + 1) 
  411.     {
  412.       close (fd);
  413.       return FALSE;
  414.     }
  415.  
  416.   buffer = g_malloc (drawable->width * drawable->bpp);
  417.   if (buffer == NULL) 
  418.     {
  419.       close (fd);
  420.       return FALSE;
  421.     }
  422.  
  423.   for (line = 0; line < drawable->height; line++) 
  424.     {
  425.       gimp_pixel_rgn_get_row (&pixel_rgn, buffer, 0, line, drawable->width);
  426.  
  427.       if (write (fd, buffer, drawable->width * drawable->bpp) !=
  428.       drawable->width * drawable->bpp) 
  429.     {
  430.       close (fd);
  431.       return FALSE;
  432.     }
  433.  
  434.       gimp_progress_update ((gdouble) line / (gdouble) drawable->height);
  435.     }
  436.  
  437.   g_free (buffer);
  438.   close (fd);
  439.  
  440.   return TRUE;
  441. }
  442.  
  443. static gboolean
  444. save_dialog (void)
  445. {
  446.   GtkWidget *dlg;
  447.   GtkWidget *table;
  448.   GtkWidget *entry;
  449.  
  450.   dlg = gimp_dialog_new (_("Save as Pattern"), "pat",
  451.              gimp_standard_help_func, "filters/pat.html",
  452.              GTK_WIN_POS_MOUSE,
  453.              FALSE, TRUE, FALSE,
  454.  
  455.              _("OK"), ok_callback,
  456.              NULL, NULL, NULL, TRUE, FALSE,
  457.              _("Cancel"), gtk_widget_destroy,
  458.              NULL, 1, NULL, FALSE, TRUE,
  459.  
  460.              NULL);
  461.  
  462.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  463.               GTK_SIGNAL_FUNC (gtk_main_quit),
  464.               NULL);
  465.  
  466.   /* The main table */
  467.   table = gtk_table_new (1, 2, FALSE);
  468.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  469.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  470.   gtk_container_set_border_width (GTK_CONTAINER (table), 6);
  471.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
  472.   gtk_widget_show (table);
  473.  
  474.   entry = gtk_entry_new ();
  475.   gtk_widget_set_usize (entry, 200, 0);
  476.   gtk_entry_set_text (GTK_ENTRY (entry), description);
  477.   gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
  478.                  _("Description:"), 1.0, 0.5,
  479.                  entry, 1, FALSE);
  480.   gtk_signal_connect (GTK_OBJECT (entry), "changed",
  481.               GTK_SIGNAL_FUNC (entry_callback),
  482.               description);
  483.   gtk_widget_show (entry);
  484.  
  485.   gtk_widget_show (dlg);
  486.  
  487.   gtk_main ();
  488.   gdk_flush ();
  489.  
  490.   return run_flag;
  491. }
  492.  
  493. static void 
  494. ok_callback (GtkWidget *widget, 
  495.          gpointer   data)
  496. {
  497.   run_flag = TRUE;
  498.  
  499.   gtk_widget_destroy (GTK_WIDGET (data));
  500. }
  501.  
  502. static void 
  503. entry_callback (GtkWidget *widget, 
  504.         gpointer   data)
  505. {
  506.   if (data == description)
  507.     strncpy (description, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
  508. }
  509.