1
/* The GIMP -- an image manipulation program
2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* $Id: tga.c,v 1.50 2004/11/02 12:00:24 mitch Exp $
5
* TrueVision Targa loading and saving file filter for the Gimp.
6
* Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit
8
* The Targa reading and writing code was written from scratch by
9
* Raphael FRANCOIS <fraph@ibm.net> and Gordon Matzigkeit
10
* <gord@gnu.ai.mit.edu> based on the TrueVision TGA File Format
11
* Specification, Version 2.0:
13
* <URL:ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/>
15
* It does not contain any code written for other TGA file loaders.
16
* Not even the RLE handling. ;)
18
* This program is free software; you can redistribute it and/or modify
19
* it under the terms of the GNU General Public License as published by
20
* the Free Software Foundation; either version 2 of the License, or
21
* (at your option) any later version.
23
* This program is distributed in the hope that it will be useful,
24
* but WITHOUT ANY WARRANTY; without even the implied warranty of
25
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
* GNU General Public License for more details.
28
* You should have received a copy of the GNU General Public License
29
* along with this program; if not, write to the Free Software
30
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34
* Modified August-November 2000, Nick Lamb <njl195@zepler.org.uk>
35
* - Clean-up more code, avoid structure implementation dependency,
36
* - Load more types of images reliably, reject others firmly
37
* - This is not perfect, but I think it's much better. Test please!
39
* Release 1.2, 1997-09-24, Gordon Matzigkeit <gord@gnu.ai.mit.edu>:
40
* - Bug fixes and source cleanups.
42
* Release 1.1, 1997-09-19, Gordon Matzigkeit <gord@gnu.ai.mit.edu>:
43
* - Preserve alpha channels. For indexed images, this can only be
44
* done if there is at least one free colormap entry.
46
* Release 1.0, 1997-09-06, Gordon Matzigkeit <gord@gnu.ai.mit.edu>:
47
* - Handle loading all image types from the 2.0 specification.
48
* - Fix many alignment and endianness problems.
49
* - Use tiles for lower memory consumption and better speed.
50
* - Rewrite RLE code for clarity and speed.
51
* - Handle saving with RLE.
53
* Release 0.9, 1997-06-18, Raphael FRANCOIS <fraph@ibm.net>:
54
* - Can load 24 and 32-bit Truecolor images, with and without RLE.
55
* - Saving currently only works without RLE.
59
* - The GIMP stores the indexed alpha channel as a separate byte,
60
* one for each pixel. The TGA file format spec requires that the
61
* alpha channel be stored as part of the colormap, not with each
62
* individual pixel. This means that we have no good way of
63
* saving and loading INDEXEDA images that use alpha channel values
64
* other than 0 and 255. Find a workaround.
67
/* Set these for debugging. */
68
/* #define PROFILE 1 */
73
# include <sys/times.h>
86
#include <libgimp/gimp.h>
87
#include <libgimp/gimpui.h>
89
#include "libgimp/stdplugins-intl.h"
92
/* Round up a division to the nearest integer. */
93
#define ROUNDUP_DIVIDE(n,d) (((n) + (d - 1)) / (d))
95
typedef struct _TgaSaveVals
101
static TgaSaveVals tsvals =
104
1, /* origin = bottom left */
108
/* TRUEVISION-XFILE magic signature string */
109
static guchar magic[18] =
111
0x54, 0x52, 0x55, 0x45, 0x56, 0x49, 0x53, 0x49, 0x4f,
112
0x4e, 0x2d, 0x58, 0x46, 0x49, 0x4c, 0x45, 0x2e, 0x0
115
typedef struct tga_info_struct
121
/* Known image types. */
122
#define TGA_TYPE_MAPPED 1
123
#define TGA_TYPE_COLOR 2
124
#define TGA_TYPE_GRAY 3
126
guint8 imageCompression;
127
/* Only known compression is RLE */
128
#define TGA_COMP_NONE 0
129
#define TGA_COMP_RLE 1
131
/* Color Map Specification. */
132
/* We need to separately specify high and low bytes to avoid endianness
133
and alignment problems. */
135
guint16 colorMapIndex;
136
guint16 colorMapLength;
139
/* Image Specification. */
153
/* Extensions (version 2) */
155
/* Not all the structures described in the standard are transcribed here
156
only those which seem applicable to Gimp */
158
gchar authorName[41];
160
guint month, day, year, hour, minute, second;
162
gchar softwareID[41];
163
guint pixelWidth, pixelHeight; /* write dpi? */
168
/* Declare some local functions.
170
static void query (void);
171
static void run (const gchar *name,
173
const GimpParam *param,
175
GimpParam **return_vals);
177
static gint32 load_image (const gchar *filename);
178
static gint save_image (const gchar *filename,
182
static gboolean save_dialog (void);
184
static gint32 ReadImage (FILE *fp,
186
const gchar *filename);
189
GimpPlugInInfo PLUG_IN_INFO =
191
NULL, /* init_proc */
192
NULL, /* quit_proc */
193
query, /* query_proc */
203
static GimpParamDef load_args[] =
205
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
206
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
207
{ GIMP_PDB_STRING, "raw_filename", "The name entered" }
210
static GimpParamDef load_return_vals[] =
212
{ GIMP_PDB_IMAGE, "image", "Output image" }
215
static GimpParamDef save_args[] =
217
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
218
{ GIMP_PDB_IMAGE, "image", "Input image" },
219
{ GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
220
{ GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
221
{ GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" },
222
{ GIMP_PDB_INT32, "rle", "Use RLE compression" },
223
{ GIMP_PDB_INT32, "origin", "Image origin (0 = top-left, 1 = bottom-left)"}
227
gimp_install_procedure ("file_tga_load",
228
"Loads files of Targa file format",
229
"FIXME: write help for tga_load",
230
"Raphael FRANCOIS, Gordon Matzigkeit",
231
"Raphael FRANCOIS, Gordon Matzigkeit",
236
G_N_ELEMENTS (load_args),
237
G_N_ELEMENTS (load_return_vals),
238
load_args, load_return_vals);
240
gimp_register_file_handler_mime ("file_tga_load", "image/x-tga");
241
gimp_register_load_handler ("file_tga_load", "tga", "");
243
gimp_install_procedure ("file_tga_save",
244
"saves files in the Targa file format",
245
"FIXME: write help for tga_save",
246
"Raphael FRANCOIS, Gordon Matzigkeit",
247
"Raphael FRANCOIS, Gordon Matzigkeit",
250
"RGB*, GRAY*, INDEXED*",
252
G_N_ELEMENTS (save_args), 0,
255
gimp_register_file_handler_mime ("file_tga_save", "image/x-tga");
256
gimp_register_save_handler ("file_tga_save", "tga", "");
260
run (const gchar *name,
262
const GimpParam *param,
264
GimpParam **return_vals)
266
static GimpParam values[2];
267
GimpRunMode run_mode;
268
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
271
GimpExportReturn export = GIMP_EXPORT_CANCEL;
274
struct tms tbuf1, tbuf2;
277
run_mode = param[0].data.d_int32;
282
*return_vals = values;
283
values[0].type = GIMP_PDB_STATUS;
284
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
286
if (strcmp (name, "file_tga_load") == 0)
292
image_ID = load_image (param[1].data.d_string);
297
values[1].type = GIMP_PDB_IMAGE;
298
values[1].data.d_image = image_ID;
302
status = GIMP_PDB_EXECUTION_ERROR;
305
else if (strcmp (name, "file_tga_save") == 0)
307
gimp_ui_init ("tga", FALSE);
309
image_ID = param[1].data.d_int32;
310
drawable_ID = param[2].data.d_int32;
312
/* eventually export the image */
315
case GIMP_RUN_INTERACTIVE:
316
case GIMP_RUN_WITH_LAST_VALS:
317
export = gimp_export_image (&image_ID, &drawable_ID, "TGA",
318
(GIMP_EXPORT_CAN_HANDLE_RGB |
319
GIMP_EXPORT_CAN_HANDLE_GRAY |
320
GIMP_EXPORT_CAN_HANDLE_INDEXED |
321
GIMP_EXPORT_CAN_HANDLE_ALPHA ));
322
if (export == GIMP_EXPORT_CANCEL)
324
values[0].data.d_status = GIMP_PDB_CANCEL;
334
case GIMP_RUN_INTERACTIVE:
335
/* Possibly retrieve data */
336
gimp_get_data ("file_tga_save", &tsvals);
338
/* First acquire information with a dialog */
339
if (! save_dialog ())
340
status = GIMP_PDB_CANCEL;
343
case GIMP_RUN_NONINTERACTIVE:
344
/* Make sure all the arguments are there! */
347
status = GIMP_PDB_CALLING_ERROR;
351
tsvals.rle = (param[5].data.d_int32) ? TRUE : FALSE;
355
case GIMP_RUN_WITH_LAST_VALS:
356
/* Possibly retrieve data */
357
gimp_get_data ("file_tga_save", &tsvals);
368
if (status == GIMP_PDB_SUCCESS)
370
if (save_image (param[3].data.d_string, image_ID, drawable_ID))
372
/* Store psvals data */
373
gimp_set_data ("file_tga_save", &tsvals, sizeof (tsvals));
377
status = GIMP_PDB_EXECUTION_ERROR;
381
if (export == GIMP_EXPORT_EXPORT)
382
gimp_image_delete (image_ID);
386
status = GIMP_PDB_CALLING_ERROR;
389
values[0].data.d_status = status;
393
printf ("TGA: %s profile: %ld user %ld system\n", name,
394
(long) tbuf2.tms_utime - tbuf1.tms_utime,
395
(long) tbuf2.tms_stime - tbuf2.tms_stime);
400
load_image (const gchar *filename)
407
guchar extension[495];
410
gint32 image_ID = -1;
412
fp = fopen (filename, "rb");
415
g_message (_("Could not open '%s' for reading: %s"),
416
gimp_filename_to_utf8 (filename), g_strerror (errno));
420
name_buf = g_strdup_printf (_("Opening '%s'..."),
421
gimp_filename_to_utf8 (filename));
422
gimp_progress_init (name_buf);
425
if (!fseek (fp, -26L, SEEK_END)) { /* Is file big enough for a footer? */
426
if (fread (footer, sizeof (footer), 1, fp) != 1)
428
g_message (_("Cannot read footer from '%s'"),
429
gimp_filename_to_utf8 (filename));
432
else if (memcmp (footer + 8, magic, sizeof (magic)) == 0)
434
/* Check the signature. */
436
offset= footer[0] + (footer[1] * 256) + (footer[2] * 65536)
437
+ (footer[3] * 16777216);
441
if (fseek (fp, offset, SEEK_SET) ||
442
fread (extension, sizeof (extension), 1, fp) != 1)
444
g_message (_("Cannot read extension from '%s'"),
445
gimp_filename_to_utf8 (filename));
448
/* Eventually actually handle version 2 TGA here */
453
if (fseek (fp, 0, SEEK_SET) ||
454
fread (header, sizeof (header), 1, fp) != 1)
456
g_message ("Cannot read header from '%s'",
457
gimp_filename_to_utf8 (filename));
464
info.imageType = TGA_TYPE_MAPPED;
465
info.imageCompression = TGA_COMP_NONE;
468
info.imageType = TGA_TYPE_COLOR;
469
info.imageCompression = TGA_COMP_NONE;
472
info.imageType = TGA_TYPE_GRAY;
473
info.imageCompression = TGA_COMP_NONE;
477
info.imageType = TGA_TYPE_MAPPED;
478
info.imageCompression = TGA_COMP_RLE;
481
info.imageType = TGA_TYPE_COLOR;
482
info.imageCompression = TGA_COMP_RLE;
485
info.imageType = TGA_TYPE_GRAY;
486
info.imageCompression = TGA_COMP_RLE;
493
info.idLength = header[0];
494
info.colorMapType = header[1];
496
info.colorMapIndex = header[3] + header[4] * 256;
497
info.colorMapLength = header[5] + header[6] * 256;
498
info.colorMapSize = header[7];
500
info.xOrigin = header[8] + header[9] * 256;
501
info.yOrigin = header[10] + header[11] * 256;
502
info.width = header[12] + header[13] * 256;
503
info.height = header[14] + header[15] * 256;
505
info.bpp = header[16];
506
info.bytes = (info.bpp + 7) / 8;
507
info.alphaBits = header[17] & 0x0f; /* Just the low 4 bits */
508
info.flipHoriz = (header[17] & 0x10) ? 1 : 0;
509
info.flipVert = (header[17] & 0x20) ? 0 : 1;
511
switch (info.imageType)
513
case TGA_TYPE_MAPPED:
516
g_message ("Unhandled sub-format in '%s'",
517
gimp_filename_to_utf8 (filename));
522
if (info.bpp != 15 && info.bpp != 16 && info.bpp != 24
525
g_message ("Unhandled sub-format in '%s'",
526
gimp_filename_to_utf8 (filename));
531
if (info.bpp != 8 && (info.alphaBits != 8 || (info.bpp != 16 && info.bpp != 15)))
533
g_message ("Unhandled sub-format in '%s'",
534
gimp_filename_to_utf8 (filename));
540
g_message ("Unknown image type for '%s'",
541
gimp_filename_to_utf8 (filename));
545
/* Plausible but unhandled formats */
546
if (info.bytes * 8 != info.bpp && !(info.bytes == 2 && info.bpp == 15))
548
g_message ("No support yet for TGA with these parameters");
552
/* Check that we have a color map only when we need it. */
553
if (info.imageType == TGA_TYPE_MAPPED && info.colorMapType != 1)
555
g_message ("Indexed image has invalid color map type %d",
559
else if (info.imageType != TGA_TYPE_MAPPED && info.colorMapType != 0)
561
g_message ("Non-indexed image has invalid color map type %d",
566
/* Skip the image ID field. */
567
if (info.idLength && fseek (fp, info.idLength, SEEK_CUR))
569
g_message ("File '%s' is truncated or corrupted",
570
gimp_filename_to_utf8 (filename));
574
image_ID = ReadImage (fp, &info, filename);
587
guchar *from = buffer;
590
for (x = 1; x < width; ++x)
592
if (memcmp (buffer, buffer + bytes, bytes))
594
/* next pixel is different */
597
putc (128 + repeat, fp);
598
fwrite (from, bytes, 1, fp);
599
from = buffer+ bytes; /* point to first different pixel */
610
/* next pixel is the same */
613
putc (direct - 1, fp);
614
fwrite (from, bytes, direct, fp);
615
from = buffer; /* point to first identical pixel */
628
fwrite (from, bytes, 1, fp);
629
from = buffer+ bytes;
633
else if (direct == 128)
636
fwrite (from, bytes, direct, fp);
637
from = buffer+ bytes;
647
putc (128 + repeat, fp);
648
fwrite (from, bytes, 1, fp);
653
fwrite (from, bytes, direct + 1, fp);
662
static gint repeat = 0;
663
static gint direct = 0;
664
static guchar sample[4];
668
for (x = 0; x < info->width; x++)
670
if (repeat == 0 && direct == 0)
678
else if (head >= 128)
682
if (fread (sample, info->bytes, 1, fp) < 1)
693
for (k = 0; k < info->bytes; ++k)
695
buffer[k] = sample[k];
700
else /* direct > 0 */
702
if (fread (buffer, info->bytes, 1, fp) < 1)
708
buffer += info->bytes;
715
flip_line (guchar *buffer,
722
alt = buffer + (info->bytes * (info->width - 1));
724
for (x = 0; x * 2 <= info->width; x++)
726
for (s = 0; s < info->bytes; ++s)
733
buffer += info->bytes;
738
/* Some people write 16-bit RGB TGA files. The spec would probably
739
allow 27-bit RGB too, for what it's worth, but I won't fix that
740
unless someone actually provides an existence proof */
743
upsample (guchar *dest,
751
for (x = 0; x < width; x++)
753
dest[0] = ((src[1] << 1) & 0xf8);
754
dest[0] += (dest[0] >> 5);
756
dest[1] = ((src[0] & 0xe0) >> 2) + ((src[1] & 0x03) << 6);
757
dest[1] += (dest[1] >> 5);
759
dest[2] = ((src[0] << 3) & 0xf8);
760
dest[2] += (dest[2] >> 5);
765
dest[3] = (src[1] & 0x80)? 0: 255;
777
bgr2rgb (guchar *dest,
787
for (x = 0; x < width; x++)
799
for (x = 0; x < width; x++)
815
GimpDrawable *drawable)
817
if (info->imageCompression == TGA_COMP_RLE)
819
rle_read (fp, buffer, info);
823
fread (buffer, info->bytes, info->width, fp);
828
flip_line (buffer, info);
831
if (info->imageType == TGA_TYPE_COLOR)
833
if (info->bpp == 16 || info->bpp == 15)
835
upsample (row, buffer, info->width, info->bytes, info->alphaBits);
839
bgr2rgb (row, buffer,info->width,info->bytes,info->alphaBits);
844
memcpy (row, buffer, info->width * drawable->bpp);
851
const gchar *filename)
853
static gint32 image_ID;
856
GimpPixelRgn pixel_rgn;
857
GimpDrawable *drawable;
858
guchar *data, *buffer, *row;
859
GimpImageType dtype = 0;
860
GimpImageBaseType itype = 0;
863
gint max_tileheight, tileheight;
866
guchar tga_cmap[4 * 256], gimp_cmap[3 * 256];
868
switch (info->imageType)
870
case TGA_TYPE_MAPPED:
871
itype = GIMP_INDEXED;
874
dtype = GIMP_INDEXEDA_IMAGE;
876
dtype = GIMP_INDEXED_IMAGE;
883
dtype = GIMP_GRAYA_IMAGE;
885
dtype = GIMP_GRAY_IMAGE;
892
dtype = GIMP_RGBA_IMAGE;
894
dtype = GIMP_RGB_IMAGE;
898
/* Handle colormap */
900
if (info->colorMapType == 1)
902
cmap_bytes= (info->colorMapSize + 7 ) / 8;
903
if (cmap_bytes <= 4 &&
904
fread (tga_cmap, info->colorMapLength * cmap_bytes, 1, fp) == 1)
906
if (info->colorMapSize == 32)
907
bgr2rgb(gimp_cmap, tga_cmap, info->colorMapLength, cmap_bytes, 1);
908
else if (info->colorMapSize == 24)
909
bgr2rgb(gimp_cmap, tga_cmap, info->colorMapLength, cmap_bytes, 0);
910
else if (info->colorMapSize == 16 || info->colorMapSize == 15)
911
upsample(gimp_cmap, tga_cmap, info->colorMapLength, cmap_bytes, info->alphaBits);
916
g_message ("File '%s' is truncated or corrupted",
917
gimp_filename_to_utf8 (filename));
922
image_ID = gimp_image_new (info->width, info->height, itype);
923
gimp_image_set_filename (image_ID, filename);
925
if (info->colorMapType == 1)
926
gimp_image_set_colormap(image_ID, gimp_cmap, info->colorMapLength);
928
layer_ID = gimp_layer_new (image_ID,
930
info->width, info->height,
934
gimp_image_add_layer (image_ID, layer_ID, 0);
936
drawable = gimp_drawable_get (layer_ID);
938
/* Prepare the pixel region. */
939
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
940
info->width, info->height, TRUE, FALSE);
942
/* Allocate the data. */
943
max_tileheight = gimp_tile_height ();
944
data = (guchar *) g_malloc (info->width * max_tileheight * drawable->bpp);
945
buffer = (guchar *) g_malloc (info->width * info->bytes);
949
for (i = 0; i < info->height; i += tileheight)
951
tileheight = i ? max_tileheight : (info->height % max_tileheight);
952
if (tileheight == 0) tileheight= max_tileheight;
954
for (y= 1; y <= tileheight; ++y)
956
row= data + (info->width * drawable->bpp * (tileheight - y));
957
read_line(fp, row, buffer, info, drawable);
960
gimp_progress_update ((double) (i + tileheight) /
961
(double) info->height);
962
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0,
963
info->height - i - tileheight,
964
info->width, tileheight);
969
for (i = 0; i < info->height; i += max_tileheight)
971
tileheight = MIN (max_tileheight, info->height - i);
973
for (y= 0; y < tileheight; ++y)
975
row= data + (info->width * drawable->bpp * y);
976
read_line(fp, row, buffer, info, drawable);
979
gimp_progress_update ((double) (i + tileheight) /
980
(double) info->height);
981
gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, i,
982
info->width, tileheight);
989
gimp_drawable_flush (drawable);
990
gimp_drawable_detach (drawable);
997
save_image (const gchar *filename,
1001
GimpPixelRgn pixel_rgn;
1002
GimpDrawable *drawable;
1003
GimpImageType dtype;
1011
gboolean status = TRUE;
1020
guchar *gimp_cmap = NULL;
1022
drawable = gimp_drawable_get (drawable_ID);
1023
dtype = gimp_drawable_type (drawable_ID);
1025
width = drawable->width;
1026
height = drawable->height;
1028
if ((fp = fopen (filename, "wb")) == NULL)
1030
g_message (_("Could not open '%s' for writing: %s"),
1031
gimp_filename_to_utf8 (filename), g_strerror (errno));
1035
name_buf = g_strdup_printf (_("Saving '%s'..."),
1036
gimp_filename_to_utf8 (filename));
1037
gimp_progress_init (name_buf);
1040
header[0] = 0; /* No image identifier / description */
1042
if (dtype == GIMP_INDEXED_IMAGE || dtype == GIMP_INDEXEDA_IMAGE)
1044
gimp_cmap = gimp_image_get_colormap (image_ID, &num_colors);
1046
header[1] = 1; /* cmap type */
1047
header[2] = (tsvals.rle) ? 9 : 1;
1048
header[3] = header[4]= 0; /* no offset */
1049
header[5] = num_colors % 256;
1050
header[6] = num_colors / 256;
1051
header[7] = 24; /* cmap size / bits */
1057
if (dtype == GIMP_RGB_IMAGE || dtype == GIMP_RGBA_IMAGE)
1059
header[2]= (tsvals.rle) ? 10 : 2;
1063
header[2]= (tsvals.rle) ? 11 : 3;
1066
header[3] = header[4] = header[5] = header[6] = header[7] = 0;
1069
header[8] = header[9] = 0; /* xorigin */
1070
header[10] = header[11] = 0; /* yorigin */
1072
header[12] = width % 256;
1073
header[13] = width / 256;
1075
header[14] = height % 256;
1076
header[15] = height / 256;
1080
case GIMP_INDEXED_IMAGE:
1081
case GIMP_GRAY_IMAGE:
1082
case GIMP_INDEXEDA_IMAGE:
1084
header[16] = 8; /* bpp */
1085
header[17] = (tsvals.origin) ? 0 : 0x20; /* alpha + orientation */
1088
case GIMP_GRAYA_IMAGE:
1090
header[16] = 16; /* bpp */
1091
header[17] = (tsvals.origin) ? 8 : 0x28; /* alpha + orientation */
1094
case GIMP_RGB_IMAGE:
1096
header[16] = 24; /* bpp */
1097
header[17] = (tsvals.origin) ? 0 : 0x20; /* alpha + orientation */
1100
case GIMP_RGBA_IMAGE:
1102
header[16] = 32; /* bpp */
1103
header[17] = (tsvals.origin) ? 8 : 0x28; /* alpha + orientation */
1107
/* write header to front of file */
1108
fwrite (header, sizeof (header), 1, fp);
1110
if (dtype == GIMP_INDEXED_IMAGE || dtype == GIMP_INDEXEDA_IMAGE)
1112
/* write out palette */
1113
for (i= 0; i < num_colors; ++i)
1115
fputc (gimp_cmap[(i * 3) + 2], fp);
1116
fputc (gimp_cmap[(i * 3) + 1], fp);
1117
fputc (gimp_cmap[(i * 3) + 0], fp);
1121
/* Allocate a new set of pixels. */
1122
tileheight = gimp_tile_height ();
1124
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
1126
pixels = g_new (guchar, width * drawable->bpp);
1127
data = g_new (guchar, width * out_bpp);
1129
for (row = 0; row < height; ++row)
1133
gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, height-(row+1), width, 1);
1137
gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, row, width, 1);
1140
if (dtype == GIMP_RGB_IMAGE)
1142
bgr2rgb(data, pixels, width, drawable->bpp, 0);
1144
else if (dtype == GIMP_RGBA_IMAGE)
1146
bgr2rgb(data, pixels, width, drawable->bpp, 1);
1148
else if (dtype == GIMP_INDEXEDA_IMAGE)
1150
for (i = 0; i < width; ++i)
1152
data[i]= pixels[i*2];
1157
memcpy (data, pixels, width * drawable->bpp);
1162
rle_write (fp, data, width, out_bpp);
1166
fwrite (data, width * out_bpp, 1, fp);
1169
gimp_progress_update ((gdouble) row / (gdouble) height);
1172
gimp_drawable_detach (drawable);
1175
/* footer must be the last thing written to file */
1176
memset (footer, 0, 8); /* No extensions, no developer directory */
1177
memcpy (footer + 8, magic, sizeof (magic)); /* magic signature */
1178
fwrite (footer, sizeof (footer), 1, fp);
1194
dlg = gimp_dialog_new (_("Save as TGA"), "tga",
1196
gimp_standard_help_func, "file-tga-save",
1198
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1199
GTK_STOCK_OK, GTK_RESPONSE_OK,
1203
vbox = gtk_vbox_new (FALSE, 12);
1204
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1205
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 0);
1206
gtk_widget_show (vbox);
1209
toggle = gtk_check_button_new_with_mnemonic (_("_RLE compression"));
1210
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
1211
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), tsvals.rle);
1212
gtk_widget_show (toggle);
1214
g_signal_connect (toggle, "toggled",
1215
G_CALLBACK (gimp_toggle_button_update),
1219
origin = gtk_check_button_new_with_mnemonic (_("Or_igin at bottom left"));
1220
gtk_box_pack_start (GTK_BOX (vbox), origin, FALSE, FALSE, 0);
1221
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (origin), tsvals.origin);
1222
gtk_widget_show (origin);
1224
g_signal_connect (origin, "toggled",
1225
G_CALLBACK (gimp_toggle_button_update),
1228
gtk_widget_show (dlg);
1230
run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK);
1232
gtk_widget_destroy (dlg);