home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / gimpbrush.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-20  |  9.6 KB  |  404 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24.  
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #ifdef HAVE_UNISTD_H
  28. #include <unistd.h>
  29. #endif
  30. #include <fcntl.h>
  31.  
  32. #ifdef G_OS_WIN32
  33. #include <io.h>
  34. #endif
  35.  
  36. #ifndef _O_BINARY
  37. #define _O_BINARY 0
  38. #endif
  39.  
  40. #include <gtk/gtk.h>
  41.  
  42.  
  43. #include <stdio.h>
  44.  
  45. #include "apptypes.h"
  46.  
  47. #include "libgimp/gimpvector.h"
  48.  
  49. #include "brush_header.h"
  50. #include "pattern_header.h"
  51. #include "gimpbrush.h"
  52. #include "gimpbrushlist.h"
  53.  
  54. #include "gimpsignal.h"
  55. #include "gimprc.h"
  56.  
  57. #include "paint_core.h"
  58. #include "temp_buf.h"
  59.  
  60. #include "libgimp/gimpintl.h"
  61.  
  62. enum
  63. {
  64.   DIRTY,
  65.   RENAME,
  66.   LAST_SIGNAL
  67. };
  68.  
  69. static GimpBrush * gimp_brush_select_brush     (PaintCore *paint_core);
  70. static gboolean    gimp_brush_want_null_motion (PaintCore *paint_core);
  71.  
  72. static guint gimp_brush_signals[LAST_SIGNAL];
  73.  
  74. static GimpObjectClass *parent_class;
  75.  
  76. static void
  77. gimp_brush_destroy (GtkObject *object)
  78. {
  79.   GimpBrush *brush = GIMP_BRUSH (object);
  80.  
  81.   g_free (brush->filename);
  82.   g_free (brush->name);
  83.  
  84.   if (brush->mask)
  85.     temp_buf_free (brush->mask);
  86.  
  87.   if (GTK_OBJECT_CLASS (parent_class)->destroy)
  88.     GTK_OBJECT_CLASS (parent_class)->destroy (object);
  89. }
  90.  
  91. static void
  92. gimp_brush_class_init (GimpBrushClass *klass)
  93. {
  94.   GtkObjectClass *object_class;
  95.   GtkType         type;
  96.   
  97.   object_class = GTK_OBJECT_CLASS (klass);
  98.  
  99.   parent_class = gtk_type_class (gimp_object_get_type ());
  100.   
  101.   type = object_class->type;
  102.  
  103.   object_class->destroy = gimp_brush_destroy;
  104.  
  105.   klass->select_brush = gimp_brush_select_brush;
  106.   klass->want_null_motion = gimp_brush_want_null_motion;
  107.  
  108.   gimp_brush_signals[DIRTY] =
  109.     gimp_signal_new ("dirty",  GTK_RUN_FIRST, type, 0, gimp_sigtype_void);
  110.  
  111.   gimp_brush_signals[RENAME] =
  112.     gimp_signal_new ("rename", GTK_RUN_FIRST, type, 0, gimp_sigtype_void);
  113.  
  114.   gtk_object_class_add_signals (object_class, gimp_brush_signals, LAST_SIGNAL);
  115. }
  116.  
  117. void
  118. gimp_brush_init (GimpBrush *brush)
  119. {
  120.   brush->filename  = NULL;
  121.   brush->name      = NULL;
  122.  
  123.   brush->spacing   = 20;
  124.   brush->x_axis.x  = 15.0;
  125.   brush->x_axis.y  =  0.0;
  126.   brush->y_axis.x  =  0.0;
  127.   brush->y_axis.y  = 15.0;
  128.  
  129.   brush->mask      = NULL;
  130.   brush->pixmap    = NULL;
  131. }
  132.  
  133.  
  134. GtkType
  135. gimp_brush_get_type (void)
  136. {
  137.   static GtkType type = 0;
  138.  
  139.   if (!type)
  140.     {
  141.       static const GtkTypeInfo info =
  142.       {
  143.         "GimpBrush",
  144.         sizeof (GimpBrush),
  145.         sizeof (GimpBrushClass),
  146.         (GtkClassInitFunc) gimp_brush_class_init,
  147.         (GtkObjectInitFunc) gimp_brush_init,
  148.         /* reserved_1 */ NULL,
  149.         /* reserved_2 */ NULL,
  150.         (GtkClassInitFunc) NULL
  151.       };
  152.  
  153.     type = gtk_type_unique (gimp_object_get_type (), &info);
  154.   }
  155.   return type;
  156. }
  157.  
  158. GimpBrush *
  159. gimp_brush_load (gchar *filename)
  160. {
  161.   GimpBrush *brush;
  162.   gint       fd;
  163.  
  164.   g_return_val_if_fail (filename != NULL, NULL);
  165.  
  166.   fd = open (filename, O_RDONLY | _O_BINARY);
  167.   if (fd == -1) 
  168.     return NULL;
  169.  
  170.   brush = gimp_brush_load_brush (fd, filename);
  171.  
  172.   close (fd);
  173.  
  174.   brush->filename = g_strdup (filename);
  175.  
  176.   /*  Swap the brush to disk (if we're being stingy with memory) */
  177.   if (stingy_memory_use)
  178.     {
  179.       temp_buf_swap (brush->mask);
  180.       if (brush->pixmap)
  181.     temp_buf_swap (brush->pixmap);
  182.     }
  183.  
  184.   return brush;
  185. }
  186.  
  187. static GimpBrush *
  188. gimp_brush_select_brush (PaintCore *paint_core)
  189. {
  190.   return paint_core->brush;
  191. }
  192.  
  193. static gboolean
  194. gimp_brush_want_null_motion (PaintCore *paint_core)
  195. {
  196.   return TRUE;
  197. }
  198.  
  199. TempBuf *
  200. gimp_brush_get_mask (GimpBrush *brush)
  201. {
  202.   g_return_val_if_fail (brush != NULL, NULL);
  203.   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
  204.  
  205.   return brush->mask;
  206. }
  207.  
  208. TempBuf *
  209. gimp_brush_get_pixmap (GimpBrush *brush)
  210. {
  211.   g_return_val_if_fail (brush != NULL, NULL);
  212.   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
  213.  
  214.   return brush->pixmap;
  215. }
  216.  
  217. gchar *
  218. gimp_brush_get_name (GimpBrush *brush)
  219. {
  220.   g_return_val_if_fail (brush != NULL, NULL);
  221.   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
  222.  
  223.   return brush->name;
  224. }
  225.  
  226. void
  227. gimp_brush_set_name (GimpBrush *brush, 
  228.              gchar     *name)
  229. {
  230.   g_return_if_fail (brush != NULL);
  231.   g_return_if_fail (GIMP_IS_BRUSH (brush));
  232.  
  233.   if (strcmp (brush->name, name) == 0)
  234.     return;
  235.  
  236.   if (brush->name)
  237.     g_free (brush->name);
  238.   brush->name = g_strdup (name);
  239.  
  240.   gtk_signal_emit (GTK_OBJECT (brush), gimp_brush_signals[RENAME]);
  241. }
  242.  
  243. gint
  244. gimp_brush_get_spacing (GimpBrush *brush)
  245. {
  246.   g_return_val_if_fail (brush != NULL, 0);
  247.   g_return_val_if_fail (GIMP_IS_BRUSH (brush), 0);
  248.  
  249.   return brush->spacing;
  250. }
  251.  
  252. void
  253. gimp_brush_set_spacing (GimpBrush *brush,
  254.             gint       spacing)
  255. {
  256.   g_return_if_fail (brush != NULL);
  257.   g_return_if_fail (GIMP_IS_BRUSH (brush));
  258.  
  259.   brush->spacing = spacing;
  260. }
  261.  
  262. GimpBrush *
  263. gimp_brush_load_brush (gint   fd,
  264.                gchar *filename)
  265. {
  266.   GimpBrush   *brush;
  267.   GPattern    *pattern;
  268.   gint         bn_size;
  269.   BrushHeader  header;
  270.   gchar       *name;
  271.   gint         i;
  272.  
  273.   g_return_val_if_fail (filename != NULL, NULL);
  274.   g_return_val_if_fail (fd != -1, NULL);
  275.  
  276.   /*  Read in the header size  */
  277.   if (read (fd, &header, sizeof (header)) != sizeof (header)) 
  278.     return NULL;
  279.  
  280.   /*  rearrange the bytes in each unsigned int  */
  281.   header.header_size  = g_ntohl (header.header_size);
  282.   header.version      = g_ntohl (header.version);
  283.   header.width        = g_ntohl (header.width);
  284.   header.height       = g_ntohl (header.height);
  285.   header.bytes        = g_ntohl (header.bytes);
  286.   header.magic_number = g_ntohl (header.magic_number);
  287.   header.spacing      = g_ntohl (header.spacing);
  288.  
  289.   /*  Check for correct file format */
  290.   /*  It looks as if version 1 did not have the same magic number.  (neo)  */
  291.   if (header.version != 1 &&
  292.       (header.magic_number != GBRUSH_MAGIC || header.version != 2))
  293.     {
  294.       g_message (_("Unknown brush format version #%d in \"%s\"."),
  295.          header.version, filename);
  296.       return NULL;
  297.     }
  298.  
  299.   if (header.version == 1)
  300.     {
  301.       /*  If this is a version 1 brush, set the fp back 8 bytes  */
  302.       lseek (fd, -8, SEEK_CUR);
  303.       header.header_size += 8;
  304.       /*  spacing is not defined in version 1  */
  305.       header.spacing = 25;
  306.     }
  307.   
  308.    /*  Read in the brush name  */
  309.   if ((bn_size = (header.header_size - sizeof (header))))
  310.     {
  311.       name = g_new (gchar, bn_size);
  312.       if ((read (fd, name, bn_size)) < bn_size)
  313.     {
  314.       g_message (_("Error in GIMP brush file \"%s\"."), filename);
  315.       g_free (name);
  316.       return NULL;
  317.     }
  318.     }
  319.   else
  320.     {
  321.       name = g_strdup (_("Unnamed"));
  322.     }
  323.  
  324.   switch (header.bytes)
  325.     {
  326.     case 1:
  327.       brush = GIMP_BRUSH (gtk_type_new (gimp_brush_get_type ()));
  328.       brush->mask = temp_buf_new (header.width, header.height, 1,
  329.                   0, 0, NULL);
  330.       if (read (fd, 
  331.         temp_buf_data (brush->mask), header.width * header.height) <
  332.       header.width * header.height)
  333.     {
  334.       g_message (_("GIMP brush file appears to be truncated: \"%s\"."),
  335.              filename);
  336.       g_free (name);
  337.       gtk_object_unref (GTK_OBJECT (brush));
  338.       return NULL;
  339.     }
  340.       
  341.       /*  For backwards-compatibility, check if a pattern follows.
  342.       The obsolete .gpb format did it this way.  */
  343.       pattern = pattern_load (fd, filename);
  344.       
  345.       if (pattern)
  346.     {
  347.       if (pattern->mask && pattern->mask->bytes == 3)
  348.         {
  349.           brush->pixmap = pattern->mask;
  350.           pattern->mask = NULL;
  351.         }
  352.       pattern_free (pattern);
  353.     }
  354.       else
  355.     {
  356.       /*  rewind to make brush pipe loader happy  */
  357.       if (lseek (fd, - sizeof (PatternHeader), SEEK_CUR) < 0)
  358.         {
  359.           g_message (_("GIMP brush file appears to be corrupted: \"%s\"."),
  360.              filename);
  361.           g_free (name);
  362.           gtk_object_unref (GTK_OBJECT (brush));
  363.           return NULL;
  364.         }
  365.     }
  366.       break;
  367.  
  368.     case 4:
  369.       brush = GIMP_BRUSH (gtk_type_new (gimp_brush_get_type ()));
  370.       brush->mask =   temp_buf_new (header.width, header.height, 1, 0, 0, NULL);
  371.       brush->pixmap = temp_buf_new (header.width, header.height, 3, 0, 0, NULL);
  372.  
  373.       for (i = 0; i < header.width * header.height; i++)
  374.     {
  375.       if (read (fd, temp_buf_data (brush->pixmap) 
  376.             + i * 3, 3) != 3 ||
  377.           read (fd, temp_buf_data (brush->mask) + i, 1) != 1)
  378.         {
  379.           g_message (_("GIMP brush file appears to be truncated: \"%s\"."),
  380.              filename);
  381.           g_free (name);
  382.           gtk_object_unref (GTK_OBJECT (brush));
  383.           return NULL;
  384.         }
  385.     }
  386.       break;
  387.       
  388.     default:
  389.       g_message ("Unsupported brush depth: %d\n in file \"%s\"\nGIMP Brushes must be GRAY or RGBA\n",
  390.          header.bytes, filename);
  391.       g_free (name);
  392.       return NULL;
  393.     }
  394.  
  395.   brush->name     = name;
  396.   brush->spacing  = header.spacing;
  397.   brush->x_axis.x = header.width  / 2.0;
  398.   brush->x_axis.y = 0.0;
  399.   brush->y_axis.x = 0.0;
  400.   brush->y_axis.y = header.height / 2.0;
  401.  
  402.   return brush;
  403. }
  404.