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