1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  * SUN raster reading and writing code Copyright (C) 1996 Peter Kirchgessner
4  * (email: peter@kirchgessner.net, WWW: http://www.kirchgessner.net)
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 3 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, see <https://www.gnu.org/licenses/>.
18  *
19  */
20 
21 /* This program was written using pages 625-629 of the book
22  * "Encyclopedia of Graphics File Formats", Murray/van Ryper,
23  * O'Reilly & Associates Inc.
24  * Bug reports or suggestions should be e-mailed to peter@kirchgessner.net
25  */
26 
27 /* Event history:
28  * V 1.00, PK, 25-Jul-96: First try
29  * V 1.90, PK, 15-Mar-97: Upgrade to work with GIMP V0.99
30  * V 1.91, PK, 05-Apr-97: Return all arguments, even in case of an error
31  * V 1.92, PK, 18-May-97: Ignore EOF-error on reading image data
32  * V 1.93, PK, 05-Oct-97: Parse rc file
33  * V 1.94, PK, 12-Oct-97: No progress bars for non-interactive mode
34  * V 1.95, nn, 20-Dec-97: Initialize some variable
35  * V 1.96, PK, 21-Nov-99: Internationalization
36  * V 1.97, PK, 20-Dec-00: Recognize extensions .rs and .ras too
37  */
38 
39 #include "config.h"
40 
41 #include <errno.h>
42 #include <string.h>
43 
44 #include <glib/gstdio.h>
45 
46 #include <libgimp/gimp.h>
47 #include <libgimp/gimpui.h>
48 
49 #include "libgimp/stdplugins-intl.h"
50 
51 
52 #define LOAD_PROC      "file-sunras-load"
53 #define SAVE_PROC      "file-sunras-save"
54 #define PLUG_IN_BINARY "file-sunras"
55 #define PLUG_IN_ROLE   "gimp-file-sunras"
56 
57 
58 typedef int WRITE_FUN(void*,size_t,size_t,FILE*);
59 
60 typedef gulong  L_CARD32;
61 typedef gushort L_CARD16;
62 typedef guchar  L_CARD8;
63 
64 /* Fileheader of SunRaster files */
65 typedef struct
66 {
67   L_CARD32 l_ras_magic;    /* Magic Number */
68   L_CARD32 l_ras_width;    /* Width */
69   L_CARD32 l_ras_height;   /* Height */
70   L_CARD32 l_ras_depth;    /* Number of bits per pixel (1,8,24,32) */
71   L_CARD32 l_ras_length;   /* Length of image data (but may also be 0) */
72   L_CARD32 l_ras_type;     /* Encoding */
73   L_CARD32 l_ras_maptype;  /* Type of colormap */
74   L_CARD32 l_ras_maplength;/* Number of bytes for colormap */
75 } L_SUNFILEHEADER;
76 
77 /* Sun-raster magic */
78 #define RAS_MAGIC 0x59a66a95
79 
80 #define RAS_TYPE_STD 1    /* Standard uncompressed format */
81 #define RAS_TYPE_RLE 2    /* Runlength compression format */
82 
83 typedef struct
84 {
85   gint val;   /* The value that is to be repeated */
86   gint n;     /* How many times it is repeated */
87 } RLEBUF;
88 
89 
90 /* Declare some local functions.
91  */
92 static void      query            (void);
93 static void      run              (const gchar       *name,
94                                    gint               nparams,
95                                    const GimpParam   *param,
96                                    gint              *nreturn_vals,
97                                    GimpParam        **return_vals);
98 
99 static gint32    load_image       (const gchar       *filename,
100                                    GError           **error);
101 static gboolean  save_image       (const gchar       *filename,
102                                    gint32             image_ID,
103                                    gint32             drawable_ID,
104                                    GError           **error);
105 
106 static void      set_color_table  (gint32             image_ID,
107                                    L_SUNFILEHEADER   *sunhdr,
108                                    const guchar      *suncolmap);
109 static gint32    create_new_image (const gchar       *filename,
110                                    guint              width,
111                                    guint              height,
112                                    GimpImageBaseType  type,
113                                    gint32            *layer_ID,
114                                    GeglBuffer       **buffer);
115 
116 static gint32    load_sun_d1      (const gchar       *filename,
117                                    FILE              *ifp,
118                                    L_SUNFILEHEADER   *sunhdr,
119                                    guchar            *suncolmap);
120 static gint32    load_sun_d8      (const gchar       *filename,
121                                    FILE              *ifp,
122                                    L_SUNFILEHEADER   *sunhdr,
123                                    guchar            *suncolmap);
124 static gint32    load_sun_d24     (const gchar       *filename,
125                                    FILE              *ifp,
126                                    L_SUNFILEHEADER   *sunhdr,
127                                    guchar            *suncolmap);
128 static gint32    load_sun_d32     (const gchar       *filename,
129                                    FILE              *ifp,
130                                    L_SUNFILEHEADER   *sunhdr,
131                                    guchar            *suncolmap);
132 
133 static L_CARD32  read_card32      (FILE              *ifp,
134                                    int               *err);
135 
136 static void      write_card32     (FILE              *ofp,
137                                    L_CARD32           c);
138 
139 static void      byte2bit         (guchar            *byteline,
140                                    int                width,
141                                    guchar            *bitline,
142                                    gboolean           invert);
143 
144 static void      rle_startread    (FILE              *ifp);
145 static int       rle_fread        (char              *ptr,
146                                    int                sz,
147                                    int                nelem,
148                                    FILE              *ifp);
149 static int       rle_fgetc        (FILE              *ifp);
150 #define rle_getc(fp) ((rlebuf.n > 0) ? (rlebuf.n)--,rlebuf.val : rle_fgetc (fp))
151 
152 static void      rle_startwrite   (FILE              *ofp);
153 static int       rle_fwrite       (char              *ptr,
154                                    int                sz,
155                                    int                nelem,
156                                    FILE              *ofp);
157 static int       rle_fputc        (int                val,
158                                    FILE              *ofp);
159 static int       rle_putrun       (int                n,
160                                    int                val,
161                                    FILE              *ofp);
162 static void      rle_endwrite     (FILE              *ofp);
163 #define rle_putc rle_fputc
164 
165 static void      read_sun_header  (FILE              *ifp,
166                                    L_SUNFILEHEADER   *sunhdr);
167 static void      write_sun_header (FILE              *ofp,
168                                    L_SUNFILEHEADER   *sunhdr);
169 static void      read_sun_cols    (FILE              *ifp,
170                                    L_SUNFILEHEADER   *sunhdr,
171                                    guchar            *colormap);
172 static void      write_sun_cols   (FILE              *ofp,
173                                    L_SUNFILEHEADER   *sunhdr,
174                                    guchar            *colormap);
175 
176 static gint      save_index       (FILE             *ofp,
177                                    gint32            image_ID,
178                                    gint32            drawable_ID,
179                                    gboolean          grey,
180                                    gboolean          rle);
181 static gint      save_rgb         (FILE             *ofp,
182                                    gint32            image_ID,
183                                    gint32            drawable_ID,
184                                    gboolean          rle);
185 
186 static gboolean  save_dialog      (void);
187 
188 /* Portability kludge */
189 static int       my_fwrite        (void             *ptr,
190                                    int               size,
191                                    int               nmemb,
192                                    FILE             *stream);
193 
194 
195 static int    read_msb_first = 1;
196 static RLEBUF rlebuf;
197 
198 
199 const GimpPlugInInfo PLUG_IN_INFO =
200 {
201   NULL,  /* init_proc  */
202   NULL,  /* quit_proc  */
203   query, /* query_proc */
204   run,   /* run_proc   */
205 };
206 
207 
208 /* Export info  */
209 typedef struct
210 {
211   gboolean  rle;  /*  rle or standard */
212 } SUNRASSaveVals;
213 
214 
215 static SUNRASSaveVals psvals =
216 {
217   TRUE     /* rle */
218 };
219 
220 
MAIN()221 MAIN ()
222 
223 
224 static void
225 query (void)
226 {
227   static const GimpParamDef load_args[] =
228   {
229     { GIMP_PDB_INT32,  "run-mode",      "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
230     { GIMP_PDB_STRING, "filename",      "The name of the file to load" },
231     { GIMP_PDB_STRING, "raw-filename",  "The name of the file to load" }
232   };
233 
234   static const GimpParamDef load_return_vals[] =
235   {
236     { GIMP_PDB_IMAGE,  "image",         "Output image" }
237   };
238 
239   static const GimpParamDef save_args[] =
240   {
241     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
242     { GIMP_PDB_IMAGE,    "image",        "Input image" },
243     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to export" },
244     { GIMP_PDB_STRING,   "filename",     "The name of the file to export the image in" },
245     { GIMP_PDB_STRING,   "raw-filename", "The name of the file to export the image in" },
246     { GIMP_PDB_INT32,    "rle",          "Specify non-zero for rle output, zero for standard output" }
247   };
248 
249   gimp_install_procedure (LOAD_PROC,
250                           "load file of the SunRaster file format",
251                           "load file of the SunRaster file format",
252                           "Peter Kirchgessner",
253                           "Peter Kirchgessner",
254                           "1996",
255                           N_("SUN Rasterfile image"),
256                           NULL,
257                           GIMP_PLUGIN,
258                           G_N_ELEMENTS (load_args),
259                           G_N_ELEMENTS (load_return_vals),
260                           load_args, load_return_vals);
261 
262   gimp_register_file_handler_mime (LOAD_PROC, "image/x-sun-raster");
263   gimp_register_magic_load_handler (LOAD_PROC,
264                                     "im1,im8,im24,im32,rs,ras,sun",
265                                     "",
266                                     "0,long,0x59a66a95");
267 
268   gimp_install_procedure (SAVE_PROC,
269                           "export file in the SunRaster file format",
270                           "SUNRAS exporting handles all image types except "
271                           "those with alpha channels.",
272                           "Peter Kirchgessner",
273                           "Peter Kirchgessner",
274                           "1996",
275                           N_("SUN Rasterfile image"),
276                           "RGB, GRAY, INDEXED",
277                           GIMP_PLUGIN,
278                           G_N_ELEMENTS (save_args), 0,
279                           save_args, NULL);
280 
281   gimp_register_file_handler_mime (SAVE_PROC, "image/x-sun-raster");
282   gimp_register_save_handler (SAVE_PROC,
283                               "im1,im8,im24,im32,rs,ras,sun", "");
284 }
285 
286 
287 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)288 run (const gchar      *name,
289      gint              nparams,
290      const GimpParam  *param,
291      gint             *nreturn_vals,
292      GimpParam       **return_vals)
293 {
294   static GimpParam   values[2];
295   GimpRunMode        run_mode;
296   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
297   gint32             image_ID;
298   gint32             drawable_ID;
299   GimpExportReturn   export = GIMP_EXPORT_CANCEL;
300   GError            *error  = NULL;
301 
302   run_mode = param[0].data.d_int32;
303 
304   INIT_I18N ();
305   gegl_init (NULL, NULL);
306 
307   *nreturn_vals = 1;
308   *return_vals  = values;
309 
310   values[0].type          = GIMP_PDB_STATUS;
311   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
312 
313   if (strcmp (name, LOAD_PROC) == 0)
314     {
315       image_ID = load_image (param[1].data.d_string, &error);
316 
317       if (image_ID != -1)
318         {
319           *nreturn_vals = 2;
320           values[1].type         = GIMP_PDB_IMAGE;
321           values[1].data.d_image = image_ID;
322         }
323       else
324         {
325           status = GIMP_PDB_EXECUTION_ERROR;
326         }
327     }
328   else if (strcmp (name, SAVE_PROC) == 0)
329     {
330       image_ID = param[1].data.d_int32;
331       drawable_ID = param[2].data.d_int32;
332 
333       /*  eventually export the image */
334       switch (run_mode)
335         {
336         case GIMP_RUN_INTERACTIVE:
337         case GIMP_RUN_WITH_LAST_VALS:
338           gimp_ui_init (PLUG_IN_BINARY, FALSE);
339 
340           export = gimp_export_image (&image_ID, &drawable_ID, "SUNRAS",
341                                       GIMP_EXPORT_CAN_HANDLE_RGB  |
342                                       GIMP_EXPORT_CAN_HANDLE_GRAY |
343                                       GIMP_EXPORT_CAN_HANDLE_INDEXED);
344 
345           if (export == GIMP_EXPORT_CANCEL)
346             {
347               values[0].data.d_status = GIMP_PDB_CANCEL;
348               return;
349           }
350           break;
351         default:
352           break;
353         }
354 
355       switch (run_mode)
356         {
357         case GIMP_RUN_INTERACTIVE:
358           /*  Possibly retrieve data  */
359           gimp_get_data (SAVE_PROC, &psvals);
360 
361           /*  First acquire information with a dialog  */
362           if (! save_dialog ())
363             status = GIMP_PDB_CANCEL;
364           break;
365 
366         case GIMP_RUN_NONINTERACTIVE:
367           /*  Make sure all the arguments are there!  */
368           if (nparams != 6)
369             {
370               status = GIMP_PDB_CALLING_ERROR;
371             }
372           else
373             {
374               psvals.rle = (param[5].data.d_int32) ? TRUE : FALSE;
375             }
376           break;
377 
378         case GIMP_RUN_WITH_LAST_VALS:
379           /*  Possibly retrieve data  */
380           gimp_get_data (SAVE_PROC, &psvals);
381           break;
382 
383         default:
384           break;
385         }
386 
387       if (status == GIMP_PDB_SUCCESS)
388         {
389           if (save_image (param[3].data.d_string, image_ID, drawable_ID,
390                           &error))
391             {
392               /*  Store psvals data  */
393               gimp_set_data (SAVE_PROC, &psvals, sizeof (SUNRASSaveVals));
394             }
395           else
396             {
397               status = GIMP_PDB_EXECUTION_ERROR;
398             }
399         }
400 
401       if (export == GIMP_EXPORT_EXPORT)
402         gimp_image_delete (image_ID);
403     }
404   else
405     {
406       status = GIMP_PDB_CALLING_ERROR;
407     }
408 
409   if (status != GIMP_PDB_SUCCESS && error)
410     {
411       *nreturn_vals = 2;
412       values[1].type          = GIMP_PDB_STRING;
413       values[1].data.d_string = error->message;
414     }
415 
416   values[0].data.d_status = status;
417 }
418 
419 
420 static gint32
load_image(const gchar * filename,GError ** error)421 load_image (const gchar  *filename,
422             GError      **error)
423 {
424   gint32           image_ID;
425   FILE            *ifp;
426   L_SUNFILEHEADER  sunhdr;
427   guchar          *suncolmap = NULL;
428 
429   gimp_progress_init_printf (_("Opening '%s'"),
430                              gimp_filename_to_utf8 (filename));
431 
432   ifp = g_fopen (filename, "rb");
433   if (!ifp)
434     {
435       g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
436                    _("Could not open '%s' for reading: %s"),
437                    gimp_filename_to_utf8 (filename), g_strerror (errno));
438       return -1;
439     }
440 
441   read_msb_first = 1;   /* SUN raster is always most significant byte first */
442 
443   read_sun_header (ifp, &sunhdr);
444   if (sunhdr.l_ras_magic != RAS_MAGIC)
445     {
446       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
447                    _("Could not open '%s' as SUN-raster-file"),
448                    gimp_filename_to_utf8 (filename));
449       fclose (ifp);
450       return -1;
451     }
452 
453   if (sunhdr.l_ras_type > 5)
454     {
455       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
456                    "%s",
457                    _("The type of this SUN-rasterfile is not supported"));
458       fclose (ifp);
459       return -1;
460     }
461 
462   if (sunhdr.l_ras_maplength > (256 * 3))
463     {
464       g_message ("Map lengths greater than 256 entries are unsupported by GIMP.");
465       gimp_quit ();
466     }
467 
468   /* Is there a RGB colormap ? */
469   if ((sunhdr.l_ras_maptype == 1) && (sunhdr.l_ras_maplength > 0))
470     {
471       suncolmap = g_new (guchar, sunhdr.l_ras_maplength);
472 
473       read_sun_cols (ifp, &sunhdr, suncolmap);
474 #ifdef DEBUG
475       {
476         int j, ncols;
477         printf ("File %s\n",filename);
478         ncols = sunhdr.l_ras_maplength/3;
479         for (j=0; j < ncols; j++)
480           printf ("Entry 0x%08x: 0x%04x,  0x%04x, 0x%04x\n",
481                   j,suncolmap[j],suncolmap[j+ncols],suncolmap[j+2*ncols]);
482       }
483 #endif
484       if (sunhdr.l_ras_magic != RAS_MAGIC)
485         {
486           g_message (_("Could not read color entries from '%s'"),
487                      gimp_filename_to_utf8 (filename));
488           fclose (ifp);
489           g_free (suncolmap);
490           return -1;
491         }
492     }
493   else if (sunhdr.l_ras_maplength > 0)
494     {
495       g_message (_("Type of colormap not supported"));
496       fseek (ifp, (sizeof (L_SUNFILEHEADER)/sizeof (L_CARD32))
497              *4 + sunhdr.l_ras_maplength, SEEK_SET);
498     }
499 
500   if (sunhdr.l_ras_width <= 0)
501     {
502       g_message (_("'%s':\nNo image width specified"),
503                  gimp_filename_to_utf8 (filename));
504       fclose (ifp);
505       return -1;
506     }
507 
508   if (sunhdr.l_ras_width > GIMP_MAX_IMAGE_SIZE)
509     {
510       g_message (_("'%s':\nImage width is larger than GIMP can handle"),
511                  gimp_filename_to_utf8 (filename));
512       fclose (ifp);
513       return -1;
514     }
515 
516   if (sunhdr.l_ras_height <= 0)
517     {
518       g_message (_("'%s':\nNo image height specified"),
519                  gimp_filename_to_utf8 (filename));
520       fclose (ifp);
521       return -1;
522     }
523 
524   if (sunhdr.l_ras_height > GIMP_MAX_IMAGE_SIZE)
525     {
526       g_message (_("'%s':\nImage height is larger than GIMP can handle"),
527                  gimp_filename_to_utf8 (filename));
528       fclose (ifp);
529       return -1;
530     }
531 
532   switch (sunhdr.l_ras_depth)
533     {
534     case 1:    /* bitmap */
535       image_ID = load_sun_d1 (filename, ifp, &sunhdr, suncolmap);
536       break;
537 
538     case 8:    /* 256 colors */
539       image_ID = load_sun_d8 (filename, ifp, &sunhdr, suncolmap);
540       break;
541 
542     case 24:   /* True color */
543       image_ID = load_sun_d24 (filename, ifp, &sunhdr, suncolmap);
544       break;
545 
546     case 32:   /* True color with extra byte */
547       image_ID = load_sun_d32 (filename, ifp, &sunhdr, suncolmap);
548       break;
549 
550     default:
551       image_ID = -1;
552       break;
553     }
554   gimp_progress_update (1.0);
555 
556   fclose (ifp);
557 
558   g_free (suncolmap);
559 
560   if (image_ID == -1)
561     {
562       g_message (_("This image depth is not supported"));
563       return -1;
564     }
565 
566   return image_ID;
567 }
568 
569 
570 static gboolean
save_image(const gchar * filename,gint32 image_ID,gint32 drawable_ID,GError ** error)571 save_image (const gchar  *filename,
572             gint32        image_ID,
573             gint32        drawable_ID,
574             GError      **error)
575 {
576   FILE          *ofp;
577   GimpImageType  drawable_type;
578   gboolean       retval;
579 
580   drawable_type = gimp_drawable_type (drawable_ID);
581 
582   /*  Make sure we're not exporting an image with an alpha channel  */
583   if (gimp_drawable_has_alpha (drawable_ID))
584     {
585       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
586                    _("SUNRAS export cannot handle images with alpha channels"));
587       return FALSE;
588     }
589 
590   switch (drawable_type)
591     {
592     case GIMP_INDEXED_IMAGE:
593     case GIMP_GRAY_IMAGE:
594     case GIMP_RGB_IMAGE:
595       break;
596     default:
597       g_message (_("Can't operate on unknown image types"));
598       return FALSE;
599       break;
600     }
601 
602   gimp_progress_init_printf (_("Exporting '%s'"),
603                              gimp_filename_to_utf8 (filename));
604 
605   /* Open the output file. */
606   ofp = g_fopen (filename, "wb");
607   if (! ofp)
608     {
609       g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
610                    _("Could not open '%s' for writing: %s"),
611                    gimp_filename_to_utf8 (filename), g_strerror (errno));
612       return FALSE;
613     }
614 
615   if (drawable_type == GIMP_INDEXED_IMAGE)
616     retval = save_index (ofp,image_ID, drawable_ID, FALSE, psvals.rle);
617   else if (drawable_type == GIMP_GRAY_IMAGE)
618     retval = save_index (ofp,image_ID, drawable_ID, TRUE, psvals.rle);
619   else if (drawable_type == GIMP_RGB_IMAGE)
620     retval = save_rgb (ofp,image_ID, drawable_ID, psvals.rle);
621   else
622     retval = FALSE;
623 
624   fclose (ofp);
625 
626   return retval;
627 }
628 
629 
630 static L_CARD32
read_card32(FILE * ifp,gint * err)631 read_card32 (FILE *ifp,
632              gint *err)
633 {
634   L_CARD32 c;
635 
636   if (read_msb_first)
637     {
638       c = (((L_CARD32)(getc (ifp))) << 24);
639       c |= (((L_CARD32)(getc (ifp))) << 16);
640       c |= (((L_CARD32)(getc (ifp))) << 8);
641       c |= ((L_CARD32)(*err = getc (ifp)));
642     }
643   else
644     {
645       c = ((L_CARD32)(getc (ifp)));
646       c |= (((L_CARD32)(getc (ifp))) << 8);
647       c |= (((L_CARD32)(getc (ifp))) << 16);
648       c |= (((L_CARD32)(*err = getc (ifp))) << 24);
649     }
650 
651   *err = (*err < 0);
652 
653   return c;
654 }
655 
656 
657 static void
write_card32(FILE * ofp,L_CARD32 c)658 write_card32 (FILE     *ofp,
659               L_CARD32  c)
660 {
661   putc ((int)((c >> 24) & 0xff), ofp);
662   putc ((int)((c >> 16) & 0xff), ofp);
663   putc ((int)((c >> 8) & 0xff), ofp);
664   putc ((int)((c) & 0xff), ofp);
665 }
666 
667 
668 /* Convert n bytes of 0/1 to a line of bits */
669 static void
byte2bit(guchar * byteline,gint width,guchar * bitline,gboolean invert)670 byte2bit (guchar   *byteline,
671           gint      width,
672           guchar   *bitline,
673           gboolean  invert)
674 {
675   guchar bitval;
676   guchar rest[8];
677 
678   while (width >= 8)
679     {
680       bitval = 0;
681       if (*(byteline++)) bitval |= 0x80;
682       if (*(byteline++)) bitval |= 0x40;
683       if (*(byteline++)) bitval |= 0x20;
684       if (*(byteline++)) bitval |= 0x10;
685       if (*(byteline++)) bitval |= 0x08;
686       if (*(byteline++)) bitval |= 0x04;
687       if (*(byteline++)) bitval |= 0x02;
688       if (*(byteline++)) bitval |= 0x01;
689       *(bitline++) = invert ? ~bitval : bitval;
690       width -= 8;
691     }
692   if (width > 0)
693     {
694       memset (rest, 0, 8);
695       memcpy (rest, byteline, width);
696       bitval = 0;
697       byteline = rest;
698       if (*(byteline++)) bitval |= 0x80;
699       if (*(byteline++)) bitval |= 0x40;
700       if (*(byteline++)) bitval |= 0x20;
701       if (*(byteline++)) bitval |= 0x10;
702       if (*(byteline++)) bitval |= 0x08;
703       if (*(byteline++)) bitval |= 0x04;
704       if (*(byteline++)) bitval |= 0x02;
705       *bitline = invert ? ~bitval : bitval;
706     }
707 }
708 
709 
710 /* Start reading Runlength Encoded Data */
711 static void
rle_startread(FILE * ifp)712 rle_startread (FILE *ifp)
713 {
714   /* Clear RLE-buffer */
715   rlebuf.val = rlebuf.n = 0;
716 }
717 
718 
719 /* Read uncompressed elements from RLE-stream */
720 static gint
rle_fread(gchar * ptr,gint sz,gint nelem,FILE * ifp)721 rle_fread (gchar *ptr,
722            gint   sz,
723            gint   nelem,
724            FILE  *ifp)
725 {
726   int elem_read, cnt, val, err = 0;
727 
728   for (elem_read = 0; elem_read < nelem; elem_read++)
729     {
730       for (cnt = 0; cnt < sz; cnt++)
731         {
732           val = rle_getc (ifp);
733 
734           if (val < 0)
735             {
736               err = 1;
737               break;
738             }
739 
740           *(ptr++) = (char)val;
741         }
742 
743       if (err)
744         break;
745     }
746 
747   return elem_read;
748 }
749 
750 
751 /* Get one byte of uncompressed data from RLE-stream */
752 static gint
rle_fgetc(FILE * ifp)753 rle_fgetc (FILE *ifp)
754 {
755   int flag, runcnt, runval;
756 
757   if (rlebuf.n > 0)    /* Something in the buffer ? */
758     {
759       (rlebuf.n)--;
760       return rlebuf.val;
761     }
762 
763   /* Nothing in the buffer. We have to read something */
764   if ((flag = getc (ifp)) < 0) return -1;
765   if (flag != 0x0080) return flag;    /* Single byte run ? */
766 
767   if ((runcnt = getc (ifp)) < 0) return -1;
768   if (runcnt == 0) return 0x0080;     /* Single 0x80 ? */
769 
770   /* The run */
771   if ((runval = getc (ifp)) < 0) return -1;
772   rlebuf.n = runcnt;
773   rlebuf.val = runval;
774 
775   return runval;
776 }
777 
778 
779 /* Start writing Runlength Encoded Data */
780 static void
rle_startwrite(FILE * ofp)781 rle_startwrite (FILE *ofp)
782 {
783   /* Clear RLE-buffer */
784   rlebuf.val = rlebuf.n = 0;
785 }
786 
787 
788 /* Write uncompressed elements to RLE-stream */
789 static gint
rle_fwrite(gchar * ptr,gint sz,gint nelem,FILE * ofp)790 rle_fwrite (gchar *ptr,
791             gint   sz,
792             gint   nelem,
793             FILE  *ofp)
794 {
795   int     elem_write, cnt, val, err = 0;
796   guchar *pixels = (unsigned char *)ptr;
797 
798   for (elem_write = 0; elem_write < nelem; elem_write++)
799     {
800       for (cnt = 0; cnt < sz; cnt++)
801         {
802           val = rle_fputc (*(pixels++), ofp);
803           if (val < 0)
804             {
805               err = 1;
806               break;
807             }
808         }
809 
810       if (err)
811         break;
812     }
813 
814   return elem_write;
815 }
816 
817 
818 /* Write uncompressed character to RLE-stream */
819 static gint
rle_fputc(gint val,FILE * ofp)820 rle_fputc (gint  val,
821            FILE *ofp)
822 {
823   int retval;
824 
825   if (rlebuf.n == 0)    /* Nothing in the buffer ? Save the value */
826     {
827       rlebuf.n   = 1;
828       rlebuf.val = val;
829 
830       return val;
831     }
832 
833   /* Something in the buffer */
834 
835   if (rlebuf.val == val)   /* Same value in the buffer ? */
836     {
837       (rlebuf.n)++;
838       if (rlebuf.n == 257) /* Can not be encoded in a single run ? */
839         {
840           retval = rle_putrun (256, rlebuf.val, ofp);
841           if (retval < 0)
842             return retval;
843 
844           rlebuf.n -= 256;
845         }
846 
847       return val;
848     }
849 
850   /* Something different in the buffer ? Write out the run */
851 
852   retval = rle_putrun (rlebuf.n, rlebuf.val, ofp);
853   if (retval < 0)
854     return retval;
855 
856   /* Save the new value */
857   rlebuf.n   = 1;
858   rlebuf.val = val;
859 
860   return val;
861 }
862 
863 
864 /* Write out a run with 0 < n < 257 */
865 static gint
rle_putrun(gint n,gint val,FILE * ofp)866 rle_putrun (gint  n,
867             gint  val,
868             FILE *ofp)
869 {
870   int retval, flag = 0x80;
871 
872   /* Useful to write a 3 byte run ? */
873   if ((n > 2) || ((n == 2) && (val == flag)))
874     {
875       putc (flag, ofp);
876       putc (n-1, ofp);
877       retval = putc (val, ofp);
878     }
879   else if (n == 2) /* Write two single runs (could not be value 0x80) */
880     {
881       putc (val, ofp);
882       retval = putc (val, ofp);
883     }
884   else  /* Write a single run */
885     {
886       if (val == flag)
887         retval = putc (flag, ofp), putc (0x00, ofp);
888       else
889         retval = putc (val, ofp);
890     }
891 
892   return (retval < 0) ? retval : val;
893 }
894 
895 
896 /* End writing Runlength Encoded Data */
897 static void
rle_endwrite(FILE * ofp)898 rle_endwrite (FILE *ofp)
899 {
900   if (rlebuf.n > 0)
901     {
902       rle_putrun (rlebuf.n, rlebuf.val, ofp);
903       rlebuf.val = rlebuf.n = 0; /* Clear RLE-buffer */
904     }
905 }
906 
907 
908 static void
read_sun_header(FILE * ifp,L_SUNFILEHEADER * sunhdr)909 read_sun_header (FILE            *ifp,
910                  L_SUNFILEHEADER *sunhdr)
911 {
912   int       j, err;
913   L_CARD32 *cp;
914 
915   cp = (L_CARD32 *)sunhdr;
916 
917   /* Read in all 32-bit values of the header and check for byte order */
918   for (j = 0; j < sizeof (L_SUNFILEHEADER) / sizeof(sunhdr->l_ras_magic); j++)
919     {
920       *(cp++) = read_card32 (ifp, &err);
921       if (err)
922         break;
923     }
924 
925   if (err)
926     sunhdr->l_ras_magic = 0;  /* Not a valid SUN-raster file */
927 }
928 
929 
930 /* Write out a SUN-fileheader */
931 
932 static void
write_sun_header(FILE * ofp,L_SUNFILEHEADER * sunhdr)933 write_sun_header (FILE            *ofp,
934                   L_SUNFILEHEADER *sunhdr)
935 {
936   int       j, hdr_entries;
937   L_CARD32 *cp;
938 
939   hdr_entries = sizeof (L_SUNFILEHEADER) / sizeof(sunhdr->l_ras_magic);
940 
941   cp = (L_CARD32 *)sunhdr;
942 
943   /* Write out all 32-bit values of the header and check for byte order */
944   for (j = 0; j < hdr_entries; j++)
945     {
946       write_card32 (ofp, *(cp++));
947     }
948 }
949 
950 
951 /* Read the sun colormap */
952 
953 static void
read_sun_cols(FILE * ifp,L_SUNFILEHEADER * sunhdr,guchar * colormap)954 read_sun_cols (FILE            *ifp,
955                L_SUNFILEHEADER *sunhdr,
956                guchar          *colormap)
957 {
958   int ncols, err = 0;
959 
960   /* Read in SUN-raster Colormap */
961   ncols = sunhdr->l_ras_maplength / 3;
962   if (ncols <= 0)
963     err = 1;
964   else
965     err = (fread (colormap, 3, ncols, ifp) != ncols);
966 
967   if (err)
968     sunhdr->l_ras_magic = 0;  /* Not a valid SUN-raster file */
969 }
970 
971 
972 /* Write a sun colormap */
973 
974 static void
write_sun_cols(FILE * ofp,L_SUNFILEHEADER * sunhdr,guchar * colormap)975 write_sun_cols (FILE            *ofp,
976                 L_SUNFILEHEADER *sunhdr,
977                 guchar          *colormap)
978 {
979   int ncols;
980 
981   ncols = sunhdr->l_ras_maplength / 3;
982   fwrite (colormap, 3, ncols, ofp);
983 }
984 
985 
986 /* Set a GIMP colortable using the sun colormap */
987 
988 static void
set_color_table(gint32 image_ID,L_SUNFILEHEADER * sunhdr,const guchar * suncolmap)989 set_color_table (gint32           image_ID,
990                  L_SUNFILEHEADER *sunhdr,
991                  const guchar    *suncolmap)
992 {
993   guchar ColorMap[256 * 3];
994   gint   ncols, j;
995 
996   ncols = sunhdr->l_ras_maplength / 3;
997   if (ncols <= 0)
998     return;
999 
1000   for (j = 0; j < MIN (ncols, 256); j++)
1001     {
1002       ColorMap[j * 3 + 0] = suncolmap[j];
1003       ColorMap[j * 3 + 1] = suncolmap[j + ncols];
1004       ColorMap[j * 3 + 2] = suncolmap[j + 2 * ncols];
1005     }
1006 
1007 #ifdef DEBUG
1008   printf ("Set GIMP colortable:\n");
1009   for (j = 0; j < ncols; j++)
1010     printf ("%3d: 0x%02x 0x%02x 0x%02x\n", j,
1011             ColorMap[j*3], ColorMap[j*3+1], ColorMap[j*3+2]);
1012 #endif
1013 
1014   gimp_image_set_colormap (image_ID, ColorMap, ncols);
1015 }
1016 
1017 
1018 /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
1019 static gint32
create_new_image(const gchar * filename,guint width,guint height,GimpImageBaseType type,gint32 * layer_ID,GeglBuffer ** buffer)1020 create_new_image (const gchar        *filename,
1021                   guint               width,
1022                   guint               height,
1023                   GimpImageBaseType   type,
1024                   gint32             *layer_ID,
1025                   GeglBuffer        **buffer)
1026 {
1027   gint32        image_ID;
1028   GimpImageType gdtype;
1029 
1030   switch (type)
1031     {
1032     case GIMP_RGB:
1033       gdtype = GIMP_RGB_IMAGE;
1034       break;
1035     case GIMP_GRAY:
1036       gdtype = GIMP_GRAY_IMAGE;
1037       break;
1038     case GIMP_INDEXED:
1039       gdtype = GIMP_INDEXED_IMAGE;
1040       break;
1041     default:
1042       g_warning ("Unsupported image type");
1043       return -1;
1044     }
1045 
1046   image_ID = gimp_image_new (width, height, type);
1047   gimp_image_set_filename (image_ID, filename);
1048 
1049   *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
1050                               gdtype,
1051                               100,
1052                               gimp_image_get_default_new_layer_mode (image_ID));
1053   gimp_image_insert_layer (image_ID, *layer_ID, -1, 0);
1054 
1055   *buffer = gimp_drawable_get_buffer (*layer_ID);
1056 
1057   return image_ID;
1058 }
1059 
1060 
1061 /* Load SUN-raster-file with depth 1 */
1062 static gint32
load_sun_d1(const gchar * filename,FILE * ifp,L_SUNFILEHEADER * sunhdr,guchar * suncolmap)1063 load_sun_d1 (const gchar     *filename,
1064              FILE            *ifp,
1065              L_SUNFILEHEADER *sunhdr,
1066              guchar          *suncolmap)
1067 {
1068   int               pix8;
1069   int               width, height, linepad, scan_lines, tile_height;
1070   int               i, j;
1071   guchar           *dest, *data;
1072   gint32            layer_ID, image_ID;
1073   GeglBuffer       *buffer;
1074   guchar            bit2byte[256 * 8];
1075   L_SUNFILEHEADER   sun_bwhdr;
1076   guchar            sun_bwcolmap[6] = { 255,0,255,0,255,0 };
1077   int               err = 0;
1078   gboolean          rle = (sunhdr->l_ras_type == RAS_TYPE_RLE);
1079 
1080   width = sunhdr->l_ras_width;
1081   height = sunhdr->l_ras_height;
1082 
1083   image_ID = create_new_image (filename, width, height, GIMP_INDEXED,
1084                                &layer_ID, &buffer);
1085 
1086   tile_height = gimp_tile_height ();
1087   data = g_malloc (tile_height * width);
1088 
1089   if (suncolmap != NULL)   /* Set up the specified color map */
1090     {
1091       set_color_table (image_ID, sunhdr, suncolmap);
1092     }
1093   else   /* No colormap available. Set up a dummy b/w-colormap */
1094     {      /* Copy the original header and simulate b/w-colormap */
1095       memcpy ((char *)&sun_bwhdr,(char *)sunhdr,sizeof (L_SUNFILEHEADER));
1096       sun_bwhdr.l_ras_maptype = 2;
1097       sun_bwhdr.l_ras_maplength = 6;
1098       set_color_table (image_ID, &sun_bwhdr, sun_bwcolmap);
1099     }
1100 
1101   /* Get an array for mapping 8 bits in a byte to 8 bytes */
1102   dest = bit2byte;
1103   for (j = 0; j < 256; j++)
1104     for (i = 7; i >= 0; i--)
1105       *(dest++) = ((j & (1 << i)) != 0);
1106 
1107   linepad = (((sunhdr->l_ras_width+7)/8) % 2); /* Check for 16bit align */
1108 
1109   if (rle)
1110     rle_startread (ifp);
1111 
1112   dest = data;
1113   scan_lines = 0;
1114 
1115   for (i = 0; i < height; i++)
1116     {
1117       j = width;
1118       while (j >= 8)
1119         {
1120           pix8 = rle ? rle_getc (ifp) : getc (ifp);
1121           if (pix8 < 0) { err = 1; pix8 = 0; }
1122 
1123           memcpy (dest, bit2byte + pix8*8, 8);
1124           dest += 8;
1125           j -= 8;
1126         }
1127 
1128       if (j > 0)
1129         {
1130           pix8 = rle ? rle_getc (ifp) : getc (ifp);
1131           if (pix8 < 0) { err = 1; pix8 = 0; }
1132 
1133           memcpy (dest, bit2byte + pix8*8, j);
1134           dest += j;
1135         }
1136 
1137       if (linepad)
1138         err |= ((rle ? rle_getc (ifp) : getc (ifp)) < 0);
1139 
1140       scan_lines++;
1141 
1142       if ((i % 20) == 0)
1143         gimp_progress_update ((double)(i+1) / (double)height);
1144 
1145       if ((scan_lines == tile_height) || ((i+1) == height))
1146         {
1147           gegl_buffer_set (buffer, GEGL_RECTANGLE (0, i - scan_lines + 1,
1148                                                    width, scan_lines), 0,
1149                            NULL, data, GEGL_AUTO_ROWSTRIDE);
1150           scan_lines = 0;
1151           dest = data;
1152         }
1153     }
1154 
1155   g_free (data);
1156 
1157   if (err)
1158     g_message (_("EOF encountered on reading"));
1159 
1160   g_object_unref (buffer);
1161 
1162   return image_ID;
1163 }
1164 
1165 
1166 /* Load SUN-raster-file with depth 8 */
1167 
1168 static gint32
load_sun_d8(const gchar * filename,FILE * ifp,L_SUNFILEHEADER * sunhdr,guchar * suncolmap)1169 load_sun_d8 (const gchar     *filename,
1170              FILE            *ifp,
1171              L_SUNFILEHEADER *sunhdr,
1172              guchar          *suncolmap)
1173 {
1174   int         width, height, linepad, i, j;
1175   gboolean    grayscale;
1176   gint        ncols;
1177   int         scan_lines, tile_height;
1178   guchar     *dest, *data;
1179   gint32      layer_ID, image_ID;
1180   GeglBuffer *buffer;
1181   int         err = 0;
1182   gboolean    rle = (sunhdr->l_ras_type == RAS_TYPE_RLE);
1183 
1184   width  = sunhdr->l_ras_width;
1185   height = sunhdr->l_ras_height;
1186 
1187   /* This could also be a grayscale image. Check it */
1188   ncols = sunhdr->l_ras_maplength / 3;
1189 
1190   grayscale = TRUE;  /* Also grayscale if no colormap present */
1191 
1192   if ((ncols > 0) && (suncolmap != NULL))
1193     {
1194       for (j = 0; j < ncols; j++)
1195         {
1196           if ((suncolmap[j]             != j) ||
1197               (suncolmap[j + ncols]     != j) ||
1198               (suncolmap[j + 2 * ncols] != j))
1199             {
1200               grayscale = FALSE;
1201               break;
1202             }
1203         }
1204     }
1205 
1206   image_ID = create_new_image (filename, width, height,
1207                                grayscale ? GIMP_GRAY : GIMP_INDEXED,
1208                                &layer_ID, &buffer);
1209 
1210   tile_height = gimp_tile_height ();
1211   data = g_malloc (tile_height * width);
1212 
1213   if (!grayscale)
1214     set_color_table (image_ID, sunhdr, suncolmap);
1215 
1216   linepad = (sunhdr->l_ras_width % 2);
1217 
1218   if (rle)
1219     rle_startread (ifp);  /* Initialize RLE-buffer */
1220 
1221   dest = data;
1222   scan_lines = 0;
1223 
1224   for (i = 0; i < height; i++)
1225     {
1226       memset ((char *)dest, 0, width);
1227       err |= ((rle ? rle_fread ((char *)dest, 1, width, ifp)
1228                : fread ((char *)dest, 1, width, ifp)) != width);
1229 
1230       if (linepad)
1231         err |= ((rle ? rle_getc (ifp) : getc (ifp)) < 0);
1232 
1233       dest += width;
1234       scan_lines++;
1235 
1236       if ((i % 20) == 0)
1237         gimp_progress_update ((double)(i+1) / (double)height);
1238 
1239       if ((scan_lines == tile_height) || ((i+1) == height))
1240         {
1241           gegl_buffer_set (buffer, GEGL_RECTANGLE (0, i - scan_lines + 1,
1242                                                    width, scan_lines), 0,
1243                            NULL, data, GEGL_AUTO_ROWSTRIDE);
1244           scan_lines = 0;
1245           dest = data;
1246         }
1247     }
1248 
1249   g_free (data);
1250 
1251   if (err)
1252     g_message (_("EOF encountered on reading"));
1253 
1254   g_object_unref (buffer);
1255 
1256   return image_ID;
1257 }
1258 
1259 
1260 /* Load SUN-raster-file with depth 24 */
1261 static gint32
load_sun_d24(const gchar * filename,FILE * ifp,L_SUNFILEHEADER * sunhdr,guchar * suncolmap)1262 load_sun_d24 (const gchar      *filename,
1263               FILE             *ifp,
1264               L_SUNFILEHEADER  *sunhdr,
1265               guchar           *suncolmap)
1266 {
1267   guchar     *dest, blue;
1268   guchar     *data;
1269   int         width, height, linepad, tile_height, scan_lines;
1270   int         i, j;
1271   gint32      layer_ID, image_ID;
1272   GeglBuffer *buffer;
1273   int         err = 0;
1274   gboolean    rle = (sunhdr->l_ras_type == RAS_TYPE_RLE);
1275 
1276   width  = sunhdr->l_ras_width;
1277   height = sunhdr->l_ras_height;
1278 
1279   image_ID = create_new_image (filename, width, height, GIMP_RGB,
1280                                &layer_ID, &buffer);
1281 
1282   tile_height = gimp_tile_height ();
1283   data = g_malloc (tile_height * width * 3);
1284 
1285   linepad = ((sunhdr->l_ras_width*3) % 2);
1286 
1287   if (rle)
1288     rle_startread (ifp);  /* Initialize RLE-buffer */
1289 
1290   dest = data;
1291   scan_lines = 0;
1292 
1293   for (i = 0; i < height; i++)
1294     {
1295       memset ((char *)dest, 0, 3*width);
1296       err |= ((rle ? rle_fread ((char *)dest, 3, width, ifp)
1297                : fread ((char *)dest, 3, width, ifp)) != width);
1298 
1299       if (linepad)
1300         err |= ((rle ? rle_getc (ifp) : getc (ifp)) < 0);
1301 
1302       if (sunhdr->l_ras_type == 3) /* RGB-format ? That is what GIMP wants */
1303         {
1304           dest += width * 3;
1305         }
1306       else                         /* We have BGR format. Correct it */
1307         {
1308           for (j = 0; j < width; j++)
1309             {
1310               blue = *dest;
1311               *dest = *(dest+2);
1312               *(dest+2) = blue;
1313               dest += 3;
1314             }
1315         }
1316 
1317       scan_lines++;
1318 
1319       if ((i % 20) == 0)
1320         gimp_progress_update ((double)(i + 1) / (double)height);
1321 
1322       if ((scan_lines == tile_height) || ((i + 1) == height))
1323         {
1324           gegl_buffer_set (buffer, GEGL_RECTANGLE (0, i - scan_lines + 1,
1325                                                    width, scan_lines), 0,
1326                            NULL, data, GEGL_AUTO_ROWSTRIDE);
1327           scan_lines = 0;
1328           dest = data;
1329         }
1330     }
1331 
1332   g_free (data);
1333 
1334   if (err)
1335     g_message (_("EOF encountered on reading"));
1336 
1337   g_object_unref (buffer);
1338 
1339   return image_ID;
1340 }
1341 
1342 
1343 /* Load SUN-raster-file with depth 32 */
1344 
1345 static gint32
load_sun_d32(const gchar * filename,FILE * ifp,L_SUNFILEHEADER * sunhdr,guchar * suncolmap)1346 load_sun_d32 (const gchar     *filename,
1347               FILE            *ifp,
1348               L_SUNFILEHEADER *sunhdr,
1349               guchar          *suncolmap)
1350 {
1351   guchar     *dest, blue;
1352   guchar     *data;
1353   int         width, height, tile_height, scan_lines;
1354   int         i, j;
1355   gint32      layer_ID, image_ID;
1356   GeglBuffer *buffer;
1357   int         err = 0;
1358   int         cerr;
1359   gboolean    rle = (sunhdr->l_ras_type == RAS_TYPE_RLE);
1360 
1361   width  = sunhdr->l_ras_width;
1362   height = sunhdr->l_ras_height;
1363 
1364   /* initialize */
1365 
1366   cerr = 0;
1367 
1368   image_ID = create_new_image (filename, width, height, GIMP_RGB,
1369                                &layer_ID, &buffer);
1370 
1371   tile_height = gimp_tile_height ();
1372   data = g_malloc (tile_height * width * 3);
1373 
1374   if (rle)
1375     rle_startread (ifp);  /* Initialize RLE-buffer */
1376 
1377   dest = data;
1378   scan_lines = 0;
1379 
1380   for (i = 0; i < height; i++)
1381     {
1382       if (rle)
1383         {
1384           for (j = 0; j < width; j++)
1385             {
1386               rle_getc (ifp);   /* Skip unused byte */
1387               *(dest++) = rle_getc (ifp);
1388               *(dest++) = rle_getc (ifp);
1389               *(dest++) = (cerr = (rle_getc (ifp)));
1390             }
1391         }
1392       else
1393         {
1394           for (j = 0; j < width; j++)
1395             {
1396               getc (ifp);   /* Skip unused byte */
1397               *(dest++) = getc (ifp);
1398               *(dest++) = getc (ifp);
1399               *(dest++) = (cerr = (getc (ifp)));
1400             }
1401         }
1402       err |= (cerr < 0);
1403 
1404       if (sunhdr->l_ras_type != 3) /* BGR format ? Correct it */
1405         {
1406           for (j = 0; j < width; j++)
1407             {
1408               dest -= 3;
1409               blue = *dest;
1410               *dest = *(dest+2);
1411               *(dest+2) = blue;
1412             }
1413           dest += width*3;
1414         }
1415 
1416       scan_lines++;
1417 
1418       if ((i % 20) == 0)
1419         gimp_progress_update ((double)(i + 1) / (double)height);
1420 
1421       if ((scan_lines == tile_height) || ((i + 1) == height))
1422         {
1423           gegl_buffer_set (buffer, GEGL_RECTANGLE (0, i - scan_lines + 1,
1424                                                    width, scan_lines), 0,
1425                            NULL, data, GEGL_AUTO_ROWSTRIDE);
1426           scan_lines = 0;
1427           dest = data;
1428         }
1429     }
1430 
1431   g_free (data);
1432 
1433   if (err)
1434     g_message (_("EOF encountered on reading"));
1435 
1436   g_object_unref (buffer);
1437 
1438   return image_ID;
1439 }
1440 
1441 
1442 static gint
save_index(FILE * ofp,gint32 image_ID,gint32 drawable_ID,gboolean grey,gboolean rle)1443 save_index (FILE     *ofp,
1444             gint32    image_ID,
1445             gint32    drawable_ID,
1446             gboolean  grey,
1447             gboolean  rle)
1448 {
1449   int             height, width, linepad, i, j;
1450   int             ncols, bw, is_bw, is_wb, bpl;
1451   int             tile_height;
1452   long            tmp = 0;
1453   guchar         *cmap, *bwline = NULL;
1454   guchar         *data, *src;
1455   L_SUNFILEHEADER sunhdr;
1456   guchar          sun_colormap[256*3];
1457   static guchar   sun_bwmap[6] = { 0,   255, 0,   255, 0,   255 };
1458   static guchar   sun_wbmap[6] = { 255, 0,   255, 0,   255, 0   };
1459   unsigned char  *suncolmap = sun_colormap;
1460   GeglBuffer     *buffer;
1461   const Babl     *format;
1462   WRITE_FUN      *write_fun;
1463 
1464   buffer = gimp_drawable_get_buffer (drawable_ID);
1465 
1466   width  = gegl_buffer_get_width (buffer);
1467   height = gegl_buffer_get_height (buffer);
1468 
1469   tile_height = gimp_tile_height ();
1470 
1471   if (grey)
1472     format = babl_format ("Y' u8");
1473   else
1474     format = gegl_buffer_get_format (buffer);
1475 
1476   /* allocate a buffer for retrieving information from the buffer  */
1477   src = data = g_malloc (tile_height * width *
1478                          babl_format_get_bytes_per_pixel (format));
1479 
1480   /* Fill SUN-color map */
1481   if (grey)
1482     {
1483       ncols = 256;
1484 
1485       for (j = 0; j < ncols; j++)
1486         {
1487           suncolmap[j]             = j;
1488           suncolmap[j + ncols]     = j;
1489           suncolmap[j + ncols * 2] = j;
1490         }
1491     }
1492   else
1493     {
1494       cmap = gimp_image_get_colormap (image_ID, &ncols);
1495 
1496       for (j = 0; j < ncols; j++)
1497         {
1498           suncolmap[j]             = *(cmap++);
1499           suncolmap[j + ncols]     = *(cmap++);
1500           suncolmap[j + ncols * 2] = *(cmap++);
1501         }
1502     }
1503 
1504   bw = (ncols == 2);   /* Maybe this is a two-color image */
1505   if (bw)
1506     {
1507       bwline = g_malloc ((width + 7) / 8);
1508       if (bwline == NULL)
1509         bw = 0;
1510     }
1511 
1512   is_bw = is_wb = 0;
1513   if (bw)    /* The Sun-OS imagetool generates index 0 for white and */
1514     {          /* index 1 for black. Do the same without colortable. */
1515       is_bw = (memcmp (suncolmap, sun_bwmap, 6) == 0);
1516       is_wb = (memcmp (suncolmap, sun_wbmap, 6) == 0);
1517     }
1518 
1519   /* Number of data bytes per line */
1520   bpl = bw ?  (width+7)/8 : width;
1521   linepad = bpl % 2;
1522 
1523   /* Fill in the SUN header */
1524   sunhdr.l_ras_magic  = RAS_MAGIC;
1525   sunhdr.l_ras_width  = width;
1526   sunhdr.l_ras_height = height;
1527   sunhdr.l_ras_depth  = bw ? 1 : 8;
1528   sunhdr.l_ras_length = (bpl + linepad) * height;
1529   sunhdr.l_ras_type   = rle ? RAS_TYPE_RLE : RAS_TYPE_STD;
1530 
1531   if (is_bw || is_wb)   /* No colortable for real b/w images */
1532     {
1533       sunhdr.l_ras_maptype = 0;   /* No colormap */
1534       sunhdr.l_ras_maplength = 0; /* Length of colormap */
1535     }
1536   else
1537     {
1538       sunhdr.l_ras_maptype = 1;   /* RGB colormap */
1539       sunhdr.l_ras_maplength = ncols*3; /* Length of colormap */
1540     }
1541 
1542   write_sun_header (ofp, &sunhdr);
1543 
1544   if (sunhdr.l_ras_maplength > 0)
1545     write_sun_cols (ofp, &sunhdr, suncolmap);
1546 
1547 #define GET_INDEX_TILE(begin) \
1548   {int scan_lines; \
1549     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
1550     gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, scan_lines), 1.0, \
1551                      format, begin, \
1552                      GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); \
1553     src = begin; }
1554 
1555   if (rle)
1556     {
1557       write_fun = (WRITE_FUN *) &rle_fwrite;
1558       rle_startwrite (ofp);
1559     }
1560   else
1561     {
1562       write_fun = (WRITE_FUN *) &my_fwrite;
1563     }
1564 
1565   if (bw)  /* Two color image */
1566     {
1567       for (i = 0; i < height; i++)
1568         {
1569           if ((i % tile_height) == 0)
1570             GET_INDEX_TILE (data); /* Get more data */
1571 
1572           byte2bit (src, width, bwline, is_bw);
1573           (*write_fun) (bwline, bpl, 1, ofp);
1574           if (linepad)
1575             (*write_fun) ((char *)&tmp, linepad, 1, ofp);
1576           src += width;
1577 
1578           if ((i % 20) == 0)
1579             gimp_progress_update ((double) i / (double) height);
1580         }
1581     }
1582   else   /* Color or grey-image */
1583     {
1584       for (i = 0; i < height; i++)
1585         {
1586           if ((i % tile_height) == 0)
1587             GET_INDEX_TILE (data); /* Get more data */
1588 
1589           (*write_fun) ((char *)src, width, 1, ofp);
1590           if (linepad)
1591             (*write_fun) ((char *)&tmp, linepad, 1, ofp);
1592           src += width;
1593 
1594           if ((i % 20) == 0)
1595             gimp_progress_update ((double) i / (double) height);
1596         }
1597     }
1598 
1599 #undef GET_INDEX_TILE
1600 
1601   if (rle)
1602     rle_endwrite (ofp);
1603 
1604   g_free (data);
1605 
1606   if (bwline)
1607     g_free (bwline);
1608 
1609   g_object_unref (buffer);
1610 
1611   if (ferror (ofp))
1612     {
1613       g_message (_("Write error occurred"));
1614       return FALSE;
1615     }
1616 
1617   return TRUE;
1618 }
1619 
1620 
1621 static gint
save_rgb(FILE * ofp,gint32 image_ID,gint32 drawable_ID,gboolean rle)1622 save_rgb (FILE     *ofp,
1623           gint32    image_ID,
1624           gint32    drawable_ID,
1625           gboolean  rle)
1626 {
1627   int              height, width, tile_height, linepad;
1628   int              i, j, bpp;
1629   guchar          *data, *src;
1630   L_SUNFILEHEADER  sunhdr;
1631   GeglBuffer      *buffer;
1632   const Babl      *format;
1633 
1634   buffer = gimp_drawable_get_buffer (drawable_ID);
1635 
1636   width  = gegl_buffer_get_width  (buffer);
1637   height = gegl_buffer_get_height (buffer);
1638 
1639   tile_height = gimp_tile_height ();
1640 
1641   format = babl_format ("R'G'B' u8");
1642 
1643   /* allocate a buffer for retrieving information from the pixel region  */
1644   src = data = g_malloc (tile_height * width *
1645                          babl_format_get_bytes_per_pixel (format));
1646 
1647 /* #define SUNRAS_32 */
1648 #ifdef SUNRAS_32
1649   bpp = 4;
1650 #else
1651   bpp = 3;
1652 #endif
1653   linepad = (width * bpp) % 2;
1654 
1655   /* Fill in the SUN header */
1656   sunhdr.l_ras_magic     = RAS_MAGIC;
1657   sunhdr.l_ras_width     = width;
1658   sunhdr.l_ras_height    = height;
1659   sunhdr.l_ras_depth     = 8 * bpp;
1660   sunhdr.l_ras_length    = (width * bpp + linepad) * height;
1661   sunhdr.l_ras_type      = rle ? RAS_TYPE_RLE : RAS_TYPE_STD;
1662   sunhdr.l_ras_maptype   = 0;   /* No colormap */
1663   sunhdr.l_ras_maplength = 0; /* Length of colormap */
1664 
1665   write_sun_header (ofp, &sunhdr);
1666 
1667 #define GET_RGB_TILE(begin) \
1668   {int scan_lines; \
1669     scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
1670     gegl_buffer_get (buffer, GEGL_RECTANGLE (0, i, width, scan_lines), 1.0, \
1671                      format, begin, \
1672                      GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); \
1673     src = begin; }
1674 
1675   if (! rle)
1676     {
1677       for (i = 0; i < height; i++)
1678         {
1679           if ((i % tile_height) == 0)
1680             GET_RGB_TILE (data); /* Get more data */
1681 
1682           for (j = 0; j < width; j++)
1683             {
1684               if (bpp == 4) putc (0, ofp);   /* Dummy */
1685               putc (*(src + 2), ofp);        /* Blue */
1686               putc (*(src + 1), ofp);        /* Green */
1687               putc (*src,       ofp);        /* Red */
1688               src += 3;
1689             }
1690 
1691           for (j = 0; j < linepad; j++)
1692             putc (0, ofp);
1693 
1694           if ((i % 20) == 0)
1695             gimp_progress_update ((double) i / (double) height);
1696         }
1697     }
1698   else  /* Write runlength encoded */
1699     {
1700       rle_startwrite (ofp);
1701 
1702       for (i = 0; i < height; i++)
1703         {
1704           if ((i % tile_height) == 0)
1705             GET_RGB_TILE (data); /* Get more data */
1706 
1707           for (j = 0; j < width; j++)
1708             {
1709               if (bpp == 4) rle_putc (0, ofp);   /* Dummy */
1710               rle_putc (*(src + 2), ofp);        /* Blue */
1711               rle_putc (*(src + 1), ofp);        /* Green */
1712               rle_putc (*src,       ofp);        /* Red */
1713               src += 3;
1714             }
1715 
1716           for (j = 0; j < linepad; j++)
1717             rle_putc (0, ofp);
1718 
1719           if ((i % 20) == 0)
1720             gimp_progress_update ((double) i / (double) height);
1721         }
1722 
1723       rle_endwrite (ofp);
1724     }
1725 
1726 #undef GET_RGB_TILE
1727 
1728   g_free (data);
1729 
1730   g_object_unref (buffer);
1731 
1732   if (ferror (ofp))
1733     {
1734       g_message (_("Write error occurred"));
1735       return FALSE;
1736     }
1737 
1738   return TRUE;
1739 }
1740 
1741 
1742 /*  Save interface functions  */
1743 
1744 static gboolean
save_dialog(void)1745 save_dialog (void)
1746 {
1747   GtkWidget *dialog;
1748   GtkWidget *frame;
1749   gboolean   run;
1750 
1751   dialog = gimp_export_dialog_new (_("SUNRAS"), PLUG_IN_BINARY, SAVE_PROC);
1752 
1753   /*  file save type  */
1754   frame = gimp_int_radio_group_new (TRUE, _("Data Formatting"),
1755                                     G_CALLBACK (gimp_radio_button_update),
1756                                     &psvals.rle, psvals.rle,
1757 
1758                                     _("_RunLength Encoded"), TRUE,  NULL,
1759                                     _("_Standard"),          FALSE, NULL,
1760 
1761                                     NULL);
1762 
1763   gtk_container_set_border_width (GTK_CONTAINER (frame), 12);
1764   gtk_box_pack_start (GTK_BOX (gimp_export_dialog_get_content_area (dialog)),
1765                       frame, TRUE, TRUE, 0);
1766   gtk_widget_show (frame);
1767 
1768   gtk_widget_show (dialog);
1769 
1770   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1771 
1772   gtk_widget_destroy (dialog);
1773 
1774   return run;
1775 }
1776 
1777 static int
my_fwrite(void * ptr,int size,int nmemb,FILE * stream)1778 my_fwrite (void *ptr,
1779            int   size,
1780            int   nmemb,
1781            FILE *stream)
1782 {
1783   return fwrite (ptr, size, nmemb, stream);
1784 }
1785