sgi.c 22.8 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
/*
2
 * SGI image file plug-in for GIMP.
Elliot Lee's avatar
Elliot Lee committed
3
 *
4
 * Copyright 1997-1998 Michael Sweet (mike@easysw.com)
Elliot Lee's avatar
Elliot Lee committed
5
 *
6
7
8
9
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
Elliot Lee's avatar
Elliot Lee committed
10
 *
11
12
13
14
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
Elliot Lee's avatar
Elliot Lee committed
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/>.
Elliot Lee's avatar
Elliot Lee committed
18
19
20
21
22
23
24
 *
 * Contents:
 *
 *   main()                      - Main entry - just call gimp_main()...
 *   query()                     - Respond to a plug-in query...
 *   run()                       - Run the plug-in...
 *   load_image()                - Load a PNG image into a new image window.
25
26
27
 *   save_image()                - Export the specified image to a PNG file.
 *   save_ok_callback()          - Destroy the export dialog and export the image.
 *   save_dialog()               - Pop up the export dialog.
Elliot Lee's avatar
Elliot Lee committed
28
29
30
 *
 */

Sven Neumann's avatar
Sven Neumann committed
31
32
#include "config.h"

33
#include <string.h>
34

Elliot Lee's avatar
Elliot Lee committed
35
#include <libgimp/gimp.h>
36
#include <libgimp/gimpui.h>
37

38
#include "sgi-lib.h"
39

40
#include "libgimp/stdplugins-intl.h"
41

Elliot Lee's avatar
Elliot Lee committed
42

43
44
#define LOAD_PROC        "file-sgi-load"
#define SAVE_PROC        "file-sgi-save"
45
#define PLUG_IN_BINARY   "file-sgi"
46
#define PLUG_IN_VERSION  "1.1.1 - 17 May 1998"
Elliot Lee's avatar
Elliot Lee committed
47
48


49
50
typedef struct _Sgi      Sgi;
typedef struct _SgiClass SgiClass;
Elliot Lee's avatar
Elliot Lee committed
51

52
53
54
55
struct _Sgi
{
  GimpPlugIn      parent_instance;
};
56

57
58
59
60
struct _SgiClass
{
  GimpPlugInClass parent_class;
};
Elliot Lee's avatar
Elliot Lee committed
61
62


63
64
#define SGI_TYPE  (sgi_get_type ())
#define SGI (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SGI_TYPE, Sgi))
Elliot Lee's avatar
Elliot Lee committed
65

66
GType                   sgi_get_type         (void) G_GNUC_CONST;
Elliot Lee's avatar
Elliot Lee committed
67

68
69
70
71
72
73
74
75
76
77
78
static GList          * sgi_query_procedures (GimpPlugIn           *plug_in);
static GimpProcedure  * sgi_create_procedure (GimpPlugIn           *plug_in,
                                              const gchar          *name);

static GimpValueArray * sgi_load             (GimpProcedure        *procedure,
                                              GimpRunMode           run_mode,
                                              GFile                *file,
                                              const GimpValueArray *args,
                                              gpointer              run_data);
static GimpValueArray * sgi_save             (GimpProcedure        *procedure,
                                              GimpRunMode           run_mode,
79
                                              GimpImage            *image,
80
81
                                              gint                  n_drawables,
                                              GimpDrawable        **drawables,
82
83
84
85
                                              GFile                *file,
                                              const GimpValueArray *args,
                                              gpointer              run_data);

86
static GimpImage      * load_image           (GFile                *file,
87
                                              GError              **error);
88
static gint             save_image           (GFile                *file,
89
90
                                              GimpImage            *image,
                                              GimpDrawable         *drawable,
91
                                              GObject              *config,
92
93
                                              GError              **error);

94
95
static gboolean         save_dialog          (GimpProcedure        *procedure,
                                              GObject              *config);
96
97
98


G_DEFINE_TYPE (Sgi, sgi, GIMP_TYPE_PLUG_IN)
Elliot Lee's avatar
Elliot Lee committed
99

100
GIMP_MAIN (SGI_TYPE)
101
DEFINE_STD_SET_I18N
102
103


Elliot Lee's avatar
Elliot Lee committed
104
static void
105
sgi_class_init (SgiClass *klass)
Elliot Lee's avatar
Elliot Lee committed
106
{
107
108
109
110
  GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);

  plug_in_class->query_procedures = sgi_query_procedures;
  plug_in_class->create_procedure = sgi_create_procedure;
111
  plug_in_class->set_i18n         = STD_SET_I18N;
Elliot Lee's avatar
Elliot Lee committed
112
113
114
}

static void
115
sgi_init (Sgi *sgi)
Elliot Lee's avatar
Elliot Lee committed
116
{
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
}

static GList *
sgi_query_procedures (GimpPlugIn *plug_in)
{
  GList *list = NULL;

  list = g_list_append (list, g_strdup (LOAD_PROC));
  list = g_list_append (list, g_strdup (SAVE_PROC));

  return list;
}

static GimpProcedure *
sgi_create_procedure (GimpPlugIn  *plug_in,
                      const gchar *name)
{
  GimpProcedure *procedure = NULL;

  if (! strcmp (name, LOAD_PROC))
    {
138
139
      procedure = gimp_load_procedure_new (plug_in, name,
                                           GIMP_PDB_PROC_TYPE_PLUGIN,
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
                                           sgi_load, NULL, NULL);

      gimp_procedure_set_menu_label (procedure,
                                     N_("Silicon Graphics IRIS image"));

      gimp_procedure_set_documentation (procedure,
                                        "Loads files in SGI image file format",
                                        "This plug-in loads SGI image files.",
                                        name);
      gimp_procedure_set_attribution (procedure,
                                      "Michael Sweet <mike@easysw.com>",
                                      "Copyright 1997-1998 by Michael Sweet",
                                      PLUG_IN_VERSION);

      gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
                                          "image/x-sgi");
      gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
                                          "sgi,rgb,rgba,bw,icon");
      gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
                                      "0,short,474");
    }
  else if (! strcmp (name, SAVE_PROC))
    {
163
164
      procedure = gimp_save_procedure_new (plug_in, name,
                                           GIMP_PDB_PROC_TYPE_PLUGIN,
165
166
167
168
169
170
                                           sgi_save, NULL, NULL);

      gimp_procedure_set_image_types (procedure, "*");

      gimp_procedure_set_menu_label (procedure,
                                     N_("Silicon Graphics IRIS image"));
171
      gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

      gimp_procedure_set_documentation (procedure,
                                        "Exports files in SGI image file format",
                                        "This plug-in exports SGI image files.",
                                        name);
      gimp_procedure_set_attribution (procedure,
                                      "Michael Sweet <mike@easysw.com>",
                                      "Copyright 1997-1998 by Michael Sweet",
                                      PLUG_IN_VERSION);

      gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
                                          "image/x-sgi");
      gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
                                          "sgi,rgb,rgba,bw,icon");

187
188
189
      GIMP_PROC_ARG_INT (procedure, "compression",
                         "Compression",
                         "Compression level (0 = none, 1 = RLE, 2 = ARLE)",
190
191
                         0, 2, SGI_COMP_RLE,
                         GIMP_PARAM_READWRITE);
192
193
194
195
196
197
198
199
200
201
202
203
204
    }

  return procedure;
}

static GimpValueArray *
sgi_load (GimpProcedure        *procedure,
          GimpRunMode           run_mode,
          GFile                *file,
          const GimpValueArray *args,
          gpointer              run_data)
{
  GimpValueArray *return_vals;
205
  GimpImage      *image;
206
  GError         *error = NULL;
Elliot Lee's avatar
Elliot Lee committed
207

208
209
  gegl_init (NULL, NULL);

210
  image = load_image (file, &error);
211

212
  if (! image)
213
214
215
216
217
218
219
220
    return gimp_procedure_new_return_values (procedure,
                                             GIMP_PDB_EXECUTION_ERROR,
                                             error);

  return_vals = gimp_procedure_new_return_values (procedure,
                                                  GIMP_PDB_SUCCESS,
                                                  NULL);

221
  GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
222
223
224

  return return_vals;
}
Elliot Lee's avatar
Elliot Lee committed
225

226
227
228
static GimpValueArray *
sgi_save (GimpProcedure        *procedure,
          GimpRunMode           run_mode,
229
          GimpImage            *image,
230
231
          gint                  n_drawables,
          GimpDrawable        **drawables,
232
233
234
235
          GFile                *file,
          const GimpValueArray *args,
          gpointer              run_data)
{
236
237
238
239
  GimpProcedureConfig *config;
  GimpPDBStatusType    status = GIMP_PDB_SUCCESS;
  GimpExportReturn     export = GIMP_EXPORT_CANCEL;
  GError              *error  = NULL;
240

241
  gegl_init (NULL, NULL);
Elliot Lee's avatar
Elliot Lee committed
242

243
244
  config = gimp_procedure_create_config (procedure);
  gimp_procedure_config_begin_run (config, image, run_mode, args);
245

246
  switch (run_mode)
247
    {
248
249
    case GIMP_RUN_INTERACTIVE:
    case GIMP_RUN_WITH_LAST_VALS:
250
      gimp_ui_init (PLUG_IN_BINARY);
251

252
      export = gimp_export_image (&image, &n_drawables, &drawables, "SGI",
253
254
255
256
257
258
259
260
261
262
                                  GIMP_EXPORT_CAN_HANDLE_RGB     |
                                  GIMP_EXPORT_CAN_HANDLE_GRAY    |
                                  GIMP_EXPORT_CAN_HANDLE_INDEXED |
                                  GIMP_EXPORT_CAN_HANDLE_ALPHA);

      if (export == GIMP_EXPORT_CANCEL)
        return gimp_procedure_new_return_values (procedure,
                                                 GIMP_PDB_CANCEL,
                                                 NULL);
      break;
Elliot Lee's avatar
Elliot Lee committed
263

264
265
    default:
      break;
Elliot Lee's avatar
Elliot Lee committed
266
    }
267

268
269
270
271
272
273
274
275
276
277
  if (n_drawables != 1)
    {
      g_set_error (&error, G_FILE_ERROR, 0,
                   _("SGI format does not support multiple layers."));

      return gimp_procedure_new_return_values (procedure,
                                               GIMP_PDB_CALLING_ERROR,
                                               error);
    }

278
279
280
  if (run_mode == GIMP_RUN_INTERACTIVE)
    {
      if (! save_dialog (procedure, G_OBJECT (config)))
281
        status = GIMP_PDB_CANCEL;
282
    }
Elliot Lee's avatar
Elliot Lee committed
283

284
285
  if (status == GIMP_PDB_SUCCESS)
    {
286
287
      if (! save_image (file, image, drawables[0],
                        G_OBJECT (config), &error))
288
        {
289
          status = GIMP_PDB_EXECUTION_ERROR;
290
        }
291
292
    }

293
  gimp_procedure_config_end_run (config, status);
294
295
  g_object_unref (config);

296
  if (export == GIMP_EXPORT_EXPORT)
297
298
299
300
    {
      gimp_image_delete (image);
      g_free (drawables);
    }
301

302
  return gimp_procedure_new_return_values (procedure, status, error);
Elliot Lee's avatar
Elliot Lee committed
303
304
}

305
static GimpImage *
306
307
load_image (GFile   *file,
            GError **error)
Elliot Lee's avatar
Elliot Lee committed
308
{
309
  gint           i,           /* Looping var */
310
311
312
313
314
315
316
317
                 x,           /* Current X coordinate */
                 y,           /* Current Y coordinate */
                 image_type,  /* Type of image */
                 layer_type,  /* Type of drawable/layer */
                 tile_height, /* Height of tile in GIMP */
                 count,       /* Count of rows to put in image */
                 bytes;       /* Number of channels to use */
  sgi_t         *sgip;        /* File pointer */
318
319
  GimpImage     *image;       /* Image */
  GimpLayer     *layer;       /* Layer */
320
  GeglBuffer    *buffer;      /* Buffer for layer */
321
322
323
  guchar       **pixels,      /* Pixel rows */
                *pptr;        /* Current pixel */
  gushort      **rows;        /* SGI image data */
324
325
  GimpPrecision  precision;
  const Babl    *bablfmt = NULL;
Elliot Lee's avatar
Elliot Lee committed
326
327
328
329
330

 /*
  * Open the file for reading...
  */

331
  gimp_progress_init_printf (_("Opening '%s'"),
332
                             gimp_file_get_utf8_name (file));
333

334
  sgip = sgiOpen (g_file_peek_path (file), SGI_READ, 0, 0, 0, 0, 0);
335
336

  if (! sgip)
337
    {
338
339
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Could not open '%s' for reading."),
340
                   gimp_file_get_utf8_name (file));
Sabri Ünal's avatar
Sabri Ünal committed
341
      free (sgip);
342
      return NULL;
343
    };
Elliot Lee's avatar
Elliot Lee committed
344

345
346
347
  /*
   * Get the image dimensions and create the image...
   */
348

349
350
351
352
  /* Sanitize dimensions (note that they are unsigned short and can
   * thus never be larger than GIMP_MAX_IMAGE_SIZE
   */
  if (sgip->xsize == 0 /*|| sgip->xsize > GIMP_MAX_IMAGE_SIZE*/)
Nils Philippsen's avatar
Nils Philippsen committed
353
354
355
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
              _("Invalid width: %hu"), sgip->xsize);
Sabri Ünal's avatar
Sabri Ünal committed
356
      free (sgip);
357
      return NULL;
Nils Philippsen's avatar
Nils Philippsen committed
358
359
    }

360
  if (sgip->ysize == 0 /*|| sgip->ysize > GIMP_MAX_IMAGE_SIZE*/)
Nils Philippsen's avatar
Nils Philippsen committed
361
362
363
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
              _("Invalid height: %hu"), sgip->ysize);
Sabri Ünal's avatar
Sabri Ünal committed
364
      free (sgip);
365
      return NULL;
Nils Philippsen's avatar
Nils Philippsen committed
366
367
    }

368
  if (sgip->zsize == 0 /*|| sgip->zsize > GIMP_MAX_IMAGE_SIZE*/)
Nils Philippsen's avatar
Nils Philippsen committed
369
370
371
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
              _("Invalid number of channels: %hu"), sgip->zsize);
Sabri Ünal's avatar
Sabri Ünal committed
372
      free (sgip);
373
      return NULL;
Nils Philippsen's avatar
Nils Philippsen committed
374
375
    }

376
  bytes = sgip->zsize;
Sven Neumann's avatar
Sven Neumann committed
377

Elliot Lee's avatar
Elliot Lee committed
378
  switch (sgip->zsize)
379
    {
380
    case 1 :    /* Grayscale */
381
382
      image_type = GIMP_GRAY;
      layer_type = GIMP_GRAY_IMAGE;
383
384
385
386
387
388
389
390
391
392
      if (sgip->bpp == 1)
        {
          precision = GIMP_PRECISION_U8_NON_LINEAR;
          bablfmt = babl_format ("Y' u8");
        }
      else
        {
          precision = GIMP_PRECISION_U16_NON_LINEAR;
          bablfmt = babl_format ("Y' u16");
        }
393
      break;
Elliot Lee's avatar
Elliot Lee committed
394

395
    case 2 :    /* Grayscale + alpha */
396
397
      image_type = GIMP_GRAY;
      layer_type = GIMP_GRAYA_IMAGE;
398
399
400
401
402
403
404
405
406
407
      if (sgip->bpp == 1)
        {
          precision = GIMP_PRECISION_U8_NON_LINEAR;
          bablfmt = babl_format ("Y'A u8");
        }
      else
        {
          precision = GIMP_PRECISION_U16_NON_LINEAR;
          bablfmt = babl_format ("Y'A u16");
        }
408
      break;
Elliot Lee's avatar
Elliot Lee committed
409

410
    case 3 :    /* RGB */
411
412
      image_type = GIMP_RGB;
      layer_type = GIMP_RGB_IMAGE;
413
414
415
416
417
418
419
420
421
422
      if (sgip->bpp == 1)
        {
          precision = GIMP_PRECISION_U8_NON_LINEAR;
          bablfmt = babl_format ("R'G'B' u8");
        }
      else
        {
          precision = GIMP_PRECISION_U16_NON_LINEAR;
          bablfmt = babl_format ("R'G'B' u16");
        }
423
      break;
Elliot Lee's avatar
Elliot Lee committed
424

425
    case 4 :    /* RGBA */
426
427
      image_type = GIMP_RGB;
      layer_type = GIMP_RGBA_IMAGE;
428
429
430
431
432
433
434
435
436
437
      if (sgip->bpp == 1)
        {
          precision = GIMP_PRECISION_U8_NON_LINEAR;
          bablfmt = babl_format ("R'G'B'A u8");
        }
      else
        {
          precision = GIMP_PRECISION_U16_NON_LINEAR;
          bablfmt = babl_format ("R'G'B'A u16");
        }
438
      break;
Sven Neumann's avatar
Sven Neumann committed
439

440
441
442
443
    default:
      image_type = GIMP_RGB;
      layer_type = GIMP_RGBA_IMAGE;
      bytes = 4;
444
445
446
447
448
449
450
451
452
453
      if (sgip->bpp == 1)
        {
          precision = GIMP_PRECISION_U8_NON_LINEAR;
          bablfmt = babl_format ("R'G'B'A u8");
        }
      else
        {
          precision = GIMP_PRECISION_U16_NON_LINEAR;
          bablfmt = babl_format ("R'G'B'A u16");
        }
454
      break;
455
    }
Elliot Lee's avatar
Elliot Lee committed
456

457
458
  image = gimp_image_new_with_precision (sgip->xsize, sgip->ysize,
                                         image_type, precision);
459
  if (! image)
460
    {
461
462
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   "Could not allocate new image: %s",
463
                   gimp_pdb_get_last_error (gimp_get_pdb ()));
Sabri Ünal's avatar
Sabri Ünal committed
464
      free (sgip);
465
      return NULL;
466
    }
Elliot Lee's avatar
Elliot Lee committed
467

468
  gimp_image_set_file (image, file);
Elliot Lee's avatar
Elliot Lee committed
469

470
471
472
  /*
   * Create the "background" layer to hold the image...
   */
Elliot Lee's avatar
Elliot Lee committed
473

Sven Neumann's avatar
Sven Neumann committed
474
  layer = gimp_layer_new (image, _("Background"), sgip->xsize, sgip->ysize,
475
                          layer_type,
476
477
                          100,
                          gimp_image_get_default_new_layer_mode (image));
478
  gimp_image_insert_layer (image, layer, NULL, 0);
Elliot Lee's avatar
Elliot Lee committed
479

480
481
482
  /*
   * Get the drawable and set the pixel region for our load...
   */
Elliot Lee's avatar
Elliot Lee committed
483

484
  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
Elliot Lee's avatar
Elliot Lee committed
485

486
487
488
  /*
   * Temporary buffers...
   */
Elliot Lee's avatar
Elliot Lee committed
489

490
491
  tile_height = gimp_tile_height ();
  pixels      = g_new (guchar *, tile_height);
492
  pixels[0]   = g_new (guchar, ((gsize) tile_height) * sgip->xsize * sgip->bpp * bytes);
Elliot Lee's avatar
Elliot Lee committed
493

494
  for (i = 1; i < tile_height; i ++)
495
    pixels[i] = pixels[0] + sgip->xsize * sgip->bpp * bytes * i;
Elliot Lee's avatar
Elliot Lee committed
496

497
  rows    = g_new (unsigned short *, sgip->zsize);
498
  rows[0] = g_new (unsigned short, ((gsize) sgip->xsize) * sgip->zsize);
Elliot Lee's avatar
Elliot Lee committed
499
500
501
502

  for (i = 1; i < sgip->zsize; i ++)
    rows[i] = rows[0] + i * sgip->xsize;

503
504
505
  /*
   * Load the image...
   */
Elliot Lee's avatar
Elliot Lee committed
506
507
508
509
510

  for (y = 0, count = 0;
       y < sgip->ysize;
       y ++, count ++)
    {
511
      if (count >= tile_height)
512
        {
513
514
          gegl_buffer_set (buffer, GEGL_RECTANGLE (0, y - count,
                                                   sgip->xsize, count), 0,
515
                           bablfmt, pixels[0], GEGL_AUTO_ROWSTRIDE);
516

517
          count = 0;
Elliot Lee's avatar
Elliot Lee committed
518

519
520
          gimp_progress_update ((double) y / (double) sgip->ysize);
        }
Elliot Lee's avatar
Elliot Lee committed
521

522
      for (i = 0; i < sgip->zsize; i ++)
523
        if (sgiGetRow (sgip, rows[i], sgip->ysize - 1 - y, i) < 0)
524
525
          g_printerr ("sgiGetRow(sgip, rows[i], %d, %d) failed!\n",
                      sgip->ysize - 1 - y, i);
Elliot Lee's avatar
Elliot Lee committed
526

527
      if (sgip->bpp == 1)
528
529
530
531
532
533
534
535
536
        {
          /*
           * 8-bit (unsigned) pixels...
           */

          for (x = 0, pptr = pixels[count]; x < sgip->xsize; x ++)
            for (i = 0; i < bytes; i ++, pptr ++)
              *pptr = rows[i][x];
        }
537
      else
538
539
540
541
542
        {
          /*
           * 16-bit (unsigned) pixels...
           */

543
544
545
546
547
          guint16 *pixels16;

          for (x = 0, pixels16 = (guint16 *) pixels[count]; x < sgip->xsize; x ++)
            for (i = 0; i < bytes; i ++, pixels16 ++)
              *pixels16 = rows[i][x];
548
        }
549
    }
Elliot Lee's avatar
Elliot Lee committed
550

551
552
553
  /*
   * Do the last n rows (count always > 0)
   */
Elliot Lee's avatar
Elliot Lee committed
554

555
556
  gegl_buffer_set (buffer, GEGL_RECTANGLE (0, y - count,
                                           sgip->xsize, count), 0,
557
                   bablfmt, pixels[0], GEGL_AUTO_ROWSTRIDE);
Elliot Lee's avatar
Elliot Lee committed
558

559
560
561
  /*
   * Done with the file...
   */
Elliot Lee's avatar
Elliot Lee committed
562

563
  sgiClose (sgip);
Elliot Lee's avatar
Elliot Lee committed
564

565
  g_free (pixels[0]);
566
567
568
  g_free (pixels);
  g_free (rows[0]);
  g_free (rows);
Elliot Lee's avatar
Elliot Lee committed
569

570
  g_object_unref (buffer);
Elliot Lee's avatar
Elliot Lee committed
571

572
  gimp_progress_update (1.0);
Elliot Lee's avatar
Elliot Lee committed
573

574
  return image;
Elliot Lee's avatar
Elliot Lee committed
575
576
577
}

static gint
578
save_image (GFile        *file,
579
580
            GimpImage    *image,
            GimpDrawable *drawable,
581
            GObject      *config,
582
            GError      **error)
Elliot Lee's avatar
Elliot Lee committed
583
{
584
585
586
587
588
589
590
591
592
  gint         compression;
  gint         i, j;        /* Looping var */
  gint         x;           /* Current X coordinate */
  gint         y;           /* Current Y coordinate */
  gint         width;       /* Drawable width */
  gint         height;      /* Drawable height */
  gint         tile_height; /* Height of tile in GIMP */
  gint         count;       /* Count of rows to put in image */
  gint         zsize;       /* Number of channels in file */
593
594
595
  sgi_t       *sgip;        /* File pointer */
  GeglBuffer  *buffer;      /* Buffer for layer */
  const Babl  *format;
596
597
  guchar     **pixels;      /* Pixel rows */
  guchar      *pptr;        /* Current pixel */
598
  gushort    **rows;        /* SGI image data */
Elliot Lee's avatar
Elliot Lee committed
599

600
601
602
603
  g_object_get (config,
                "compression", &compression,
                NULL);

604
605
606
  /*
   * Get the drawable for the current image...
   */
Elliot Lee's avatar
Elliot Lee committed
607

608
609
  width  = gimp_drawable_get_width  (drawable);
  height = gimp_drawable_get_height (drawable);
Elliot Lee's avatar
Elliot Lee committed
610

611
  buffer = gimp_drawable_get_buffer (drawable);
Elliot Lee's avatar
Elliot Lee committed
612

613
  switch (gimp_drawable_type (drawable))
Sven Neumann's avatar
Sven Neumann committed
614
    {
615
    case GIMP_GRAY_IMAGE:
616
      zsize = 1;
617
      format = babl_format ("Y' u8");
618
      break;
619

620
    case GIMP_GRAYA_IMAGE:
621
      zsize = 2;
622
      format = babl_format ("Y'A u8");
623
      break;
624

625
626
    case GIMP_RGB_IMAGE:
    case GIMP_INDEXED_IMAGE:
627
      zsize = 3;
628
      format = babl_format ("R'G'B' u8");
629
      break;
630

631
632
633
    case GIMP_RGBA_IMAGE:
    case GIMP_INDEXEDA_IMAGE:
      format = babl_format ("R'G'B'A u8");
634
635
      zsize = 4;
      break;
636

Sven Neumann's avatar
Sven Neumann committed
637
    default:
638
      return FALSE;
639
    }
Elliot Lee's avatar
Elliot Lee committed
640

641
642
643
  /*
   * Open the file for writing...
   */
Elliot Lee's avatar
Elliot Lee committed
644

645
  gimp_progress_init_printf (_("Exporting '%s'"),
646
                             gimp_file_get_utf8_name (file));
647

648
  sgip = sgiOpen (g_file_peek_path (file), SGI_WRITE, compression, 1,
649
                  width, height, zsize);
650
651

  if (! sgip)
652
    {
653
654
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   _("Could not open '%s' for writing."),
655
                   gimp_file_get_utf8_name (file));
656
657
      return FALSE;
    };
Elliot Lee's avatar
Elliot Lee committed
658

659
660
661
  /*
   * Allocate memory for "tile_height" rows...
   */
Elliot Lee's avatar
Elliot Lee committed
662

663
664
  tile_height = gimp_tile_height ();
  pixels      = g_new (guchar *, tile_height);
665
  pixels[0]   = g_new (guchar, ((gsize) tile_height) * width * zsize);
Elliot Lee's avatar
Elliot Lee committed
666

667
  for (i = 1; i < tile_height; i ++)
668
    pixels[i]= pixels[0] + width * zsize * i;
Elliot Lee's avatar
Elliot Lee committed
669

670
  rows    = g_new (gushort *, sgip->zsize);
671
  rows[0] = g_new (gushort, ((gsize) sgip->xsize) * sgip->zsize);
Elliot Lee's avatar
Elliot Lee committed
672
673
674
675

  for (i = 1; i < sgip->zsize; i ++)
    rows[i] = rows[0] + i * sgip->xsize;

676
677
678
  /*
   * Save the image...
   */
Elliot Lee's avatar
Elliot Lee committed
679

680
  for (y = 0; y < height; y += count)
681
682
683
684
    {
      /*
       * Grab more pixel data...
       */
Elliot Lee's avatar
Elliot Lee committed
685

686
687
      if ((y + tile_height) >= height)
        count = height - y;
688
      else
689
        count = tile_height;
Elliot Lee's avatar
Elliot Lee committed
690

691
692
693
      gegl_buffer_get (buffer, GEGL_RECTANGLE (0, y, width, count), 1.0,
                       format, pixels[0],
                       GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
Elliot Lee's avatar
Elliot Lee committed
694

695
696
697
      /*
       * Convert to shorts and write each color plane separately...
       */
Elliot Lee's avatar
Elliot Lee committed
698

699
      for (i = 0, pptr = pixels[0]; i < count; i ++)
700
        {
701
          for (x = 0; x < width; x ++)
702
703
            for (j = 0; j < zsize; j ++, pptr ++)
              rows[j][x] = *pptr;
704

705
          for (j = 0; j < zsize; j ++)
706
            sgiPutRow (sgip, rows[j], height - 1 - y - i, j);
707
        };
Elliot Lee's avatar
Elliot Lee committed
708

709
      gimp_progress_update ((double) y / (double) height);
710
    }
Elliot Lee's avatar
Elliot Lee committed
711

712
713
714
  /*
   * Done with the file...
   */
Elliot Lee's avatar
Elliot Lee committed
715

716
  sgiClose (sgip);
Elliot Lee's avatar
Elliot Lee committed
717

718
  g_free (pixels[0]);
719
720
721
  g_free (pixels);
  g_free (rows[0]);
  g_free (rows);
Elliot Lee's avatar
Elliot Lee committed
722

723
724
725
726
  g_object_unref (buffer);

  gimp_progress_update (1.0);

727
  return TRUE;
Elliot Lee's avatar
Elliot Lee committed
728
729
}

730
static gboolean
731
732
save_dialog (GimpProcedure *procedure,
             GObject       *config)
Elliot Lee's avatar
Elliot Lee committed
733
{
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
  GtkWidget    *dialog;
  GtkWidget    *grid;
  GtkListStore *store;
  GtkWidget    *combo;
  gboolean      run;

  dialog = gimp_procedure_dialog_new (procedure,
                                      GIMP_PROCEDURE_CONFIG (config),
                                      _("Export Image as SGI"));

  grid = gtk_grid_new ();
  gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
  gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
                      grid, TRUE, TRUE, 0);
  gtk_widget_show (grid);

  store = gimp_int_store_new (_("No compression"),
                              SGI_COMP_NONE,
                              _("RLE compression"),
                              SGI_COMP_RLE,
                              _("Aggressive RLE (not supported by SGI)"),
                              SGI_COMP_ARLE,
                              NULL);
  combo = gimp_prop_int_combo_box_new (config, "compression",
                                       GIMP_INT_STORE (store));
  g_object_unref (store);

  gimp_grid_attach_aligned (GTK_GRID (grid), 0, 0,
                            _("Compression _type:"), 1.0, 0.5,
                            combo, 1);
Elliot Lee's avatar
Elliot Lee committed
765

766
  gtk_widget_show (dialog);
Elliot Lee's avatar
Elliot Lee committed
767

768
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
769

770
  gtk_widget_destroy (dialog);
Elliot Lee's avatar
Elliot Lee committed
771

772
  return run;
Elliot Lee's avatar
Elliot Lee committed
773
}