1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3  *
4  * GIMP Plug-in for Windows Icon files.
5  * Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 
25 #include <libgimp/gimp.h>
26 #include <libgimp/gimpui.h>
27 
28 /* #define ICO_DBG */
29 
30 #include "ico.h"
31 #include "ico-load.h"
32 #include "ico-save.h"
33 
34 #include "libgimp/stdplugins-intl.h"
35 
36 #define LOAD_PROC        "file-ico-load"
37 #define LOAD_THUMB_PROC  "file-ico-load-thumb"
38 #define SAVE_PROC        "file-ico-save"
39 
40 
41 static void   query (void);
42 static void   run   (const gchar      *name,
43                      gint              nparams,
44                      const GimpParam  *param,
45                      gint             *nreturn_vals,
46                      GimpParam       **return_vals);
47 
48 
49 const GimpPlugInInfo PLUG_IN_INFO =
50 {
51   NULL,  /* init_proc  */
52   NULL,  /* quit_proc  */
53   query, /* query_proc */
54   run,   /* run_proc   */
55 };
56 
57 
MAIN()58 MAIN ()
59 
60 
61 static void
62 query (void)
63 {
64   static const GimpParamDef load_args[] =
65   {
66     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
67     { GIMP_PDB_STRING,   "filename",     "The name of the file to load" },
68     { GIMP_PDB_STRING,   "raw-filename", "The name entered"             }
69   };
70   static const GimpParamDef load_return_vals[] =
71   {
72     { GIMP_PDB_IMAGE, "image", "Output image" },
73   };
74 
75   static const GimpParamDef thumb_args[] =
76   {
77     { GIMP_PDB_STRING, "filename",     "The name of the file to load"  },
78     { GIMP_PDB_INT32,  "thumb-size",   "Preferred thumbnail size"      }
79   };
80   static const GimpParamDef thumb_return_vals[] =
81   {
82     { GIMP_PDB_IMAGE,  "image",        "Thumbnail image"               },
83     { GIMP_PDB_INT32,  "image-width",  "Width of full-sized image"     },
84     { GIMP_PDB_INT32,  "image-height", "Height of full-sized image"    }
85   };
86 
87   static const GimpParamDef save_args[] =
88   {
89     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
90     { GIMP_PDB_IMAGE,    "image",        "Input image" },
91     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save" },
92     { GIMP_PDB_STRING,   "filename",     "The name of the file to save the image in" },
93     { GIMP_PDB_STRING,   "raw-filename", "The name entered" },
94   };
95 
96   gimp_install_procedure (LOAD_PROC,
97                           "Loads files of Windows ICO file format",
98                           "Loads files of Windows ICO file format",
99                           "Christian Kreibich <christian@whoop.org>",
100                           "Christian Kreibich <christian@whoop.org>",
101                           "2002",
102                           N_("Microsoft Windows icon"),
103                           NULL,
104                           GIMP_PLUGIN,
105                           G_N_ELEMENTS (load_args),
106                           G_N_ELEMENTS (load_return_vals),
107                           load_args, load_return_vals);
108 
109   gimp_register_file_handler_mime (LOAD_PROC, "image/x-ico");
110   gimp_register_magic_load_handler (LOAD_PROC,
111                                     "ico",
112                                     "",
113                                     "0,string,\\000\\001\\000\\000,0,string,\\000\\002\\000\\000");
114 
115   gimp_install_procedure (LOAD_THUMB_PROC,
116                           "Loads a preview from an Windows ICO file",
117                           "",
118                           "Dom Lachowicz, Sven Neumann",
119                           "Sven Neumann <sven@gimp.org>",
120                           "2005",
121                           NULL,
122                           NULL,
123                           GIMP_PLUGIN,
124                           G_N_ELEMENTS (thumb_args),
125                           G_N_ELEMENTS (thumb_return_vals),
126                           thumb_args, thumb_return_vals);
127 
128   gimp_register_thumbnail_loader (LOAD_PROC, LOAD_THUMB_PROC);
129 
130   gimp_install_procedure (SAVE_PROC,
131                           "Saves files in Windows ICO file format",
132                           "Saves files in Windows ICO file format",
133                           "Christian Kreibich <christian@whoop.org>",
134                           "Christian Kreibich <christian@whoop.org>",
135                           "2002",
136                           N_("Microsoft Windows icon"),
137                           "*",
138                           GIMP_PLUGIN,
139                           G_N_ELEMENTS (save_args), 0,
140                           save_args, NULL);
141 
142   gimp_register_file_handler_mime (SAVE_PROC, "image/x-ico");
143   gimp_register_save_handler (SAVE_PROC, "ico", "");
144 }
145 
146 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)147 run (const gchar      *name,
148      gint              nparams,
149      const GimpParam  *param,
150      gint             *nreturn_vals,
151      GimpParam       **return_vals)
152 {
153   static GimpParam   values[4];
154   GimpRunMode        run_mode;
155   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
156   GimpExportReturn   export = GIMP_EXPORT_CANCEL;
157   GError            *error  = NULL;
158 
159   INIT_I18N ();
160   gegl_init (NULL, NULL);
161 
162   run_mode = param[0].data.d_int32;
163 
164   *nreturn_vals = 1;
165   *return_vals  = values;
166 
167   values[0].type          = GIMP_PDB_STATUS;
168   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
169 
170   if (strcmp (name, LOAD_PROC) == 0)
171     {
172       switch (run_mode)
173         {
174         case GIMP_RUN_INTERACTIVE:
175           break;
176 
177         case GIMP_RUN_NONINTERACTIVE:
178           if (nparams != 3)
179             status = GIMP_PDB_CALLING_ERROR;
180           break;
181 
182         default:
183           break;
184         }
185 
186       if (status == GIMP_PDB_SUCCESS)
187         {
188           gint32 image_ID;
189 
190           image_ID = ico_load_image (param[1].data.d_string, &error);
191           if (image_ID != -1)
192             {
193               *nreturn_vals = 2;
194               values[1].type         = GIMP_PDB_IMAGE;
195               values[1].data.d_image = image_ID;
196             }
197           else
198             {
199               status = GIMP_PDB_EXECUTION_ERROR;
200             }
201         }
202     }
203   else if (strcmp (name, LOAD_THUMB_PROC) == 0)
204     {
205       if (nparams < 2)
206         {
207           status = GIMP_PDB_CALLING_ERROR;
208         }
209       else
210         {
211           const gchar *filename = param[0].data.d_string;
212           gint         width    = param[1].data.d_int32;
213           gint         height   = param[1].data.d_int32;
214           gint32       image_ID;
215 
216           image_ID = ico_load_thumbnail_image (filename,
217                                                &width, &height, &error);
218 
219           if (image_ID != -1)
220             {
221               *nreturn_vals = 4;
222 
223               values[1].type         = GIMP_PDB_IMAGE;
224               values[1].data.d_image = image_ID;
225               values[2].type         = GIMP_PDB_INT32;
226               values[2].data.d_int32 = width;
227               values[3].type         = GIMP_PDB_INT32;
228               values[3].data.d_int32 = height;
229             }
230           else
231             {
232               status = GIMP_PDB_EXECUTION_ERROR;
233             }
234         }
235     }
236   else if (strcmp (name, SAVE_PROC) == 0)
237     {
238       gchar *file_name;
239       gint32 image_ID;
240 
241       image_ID    = param[1].data.d_int32;
242       file_name   = param[3].data.d_string;
243 
244       switch (run_mode)
245         {
246         case GIMP_RUN_INTERACTIVE:
247           break;
248 
249         case GIMP_RUN_NONINTERACTIVE:
250           /*  Make sure all the arguments are there!  */
251           if (nparams < 5)
252             status = GIMP_PDB_CALLING_ERROR;
253           break;
254 
255         case GIMP_RUN_WITH_LAST_VALS:
256           break;
257 
258         default:
259           break;
260         }
261 
262       if (status == GIMP_PDB_SUCCESS)
263         {
264           status = ico_save_image (file_name, image_ID, run_mode, &error);
265         }
266 
267       if (export == GIMP_EXPORT_EXPORT)
268         gimp_image_delete (image_ID);
269     }
270   else
271     {
272       status = GIMP_PDB_CALLING_ERROR;
273     }
274 
275   if (status != GIMP_PDB_SUCCESS && error)
276     {
277       *nreturn_vals = 2;
278       values[1].type          = GIMP_PDB_STRING;
279       values[1].data.d_string = error->message;
280     }
281 
282   values[0].data.d_status = status;
283 }
284 
285 
286 gint
ico_rowstride(gint width,gint bpp)287 ico_rowstride (gint width,
288                gint bpp)
289 {
290   switch (bpp)
291     {
292     case 1:
293       if ((width % 32) == 0)
294         return width / 8;
295       else
296         return 4 * (width/32 + 1);
297       break;
298 
299     case 4:
300       if ((width % 8) == 0)
301         return width / 2;
302       else
303         return 4 * (width/8 + 1);
304       break;
305 
306     case 8:
307       if ((width % 4) == 0)
308         return width;
309       else
310         return 4 * (width/4 + 1);
311       break;
312 
313     case 24:
314       if (((width*3) % 4) == 0)
315         return width * 3;
316       else
317         return 4 * (width*3/4+1);
318 
319     case 32:
320       return width * 4;
321 
322     default:
323       g_warning ("invalid bitrate: %d\n", bpp);
324       g_assert_not_reached ();
325       return width * (bpp/8);
326     }
327 }
328 
329 guint8 *
ico_alloc_map(gint width,gint height,gint bpp,gint * length)330 ico_alloc_map (gint  width,
331                gint  height,
332                gint  bpp,
333                gint *length)
334 {
335   gint    len = 0;
336   guint8 *map = NULL;
337 
338   len = ico_rowstride (width, bpp) * height;
339 
340   *length = len;
341   map = g_new0 (guint8, len);
342 
343   return map;
344 }
345