home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / tga.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-19  |  30.5 KB  |  1,232 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * $Id: tga.c,v 1.23 2000/11/18 04:24:25 nicklamb Exp $
  5.  * TrueVision Targa loading and saving file filter for the Gimp.
  6.  * Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit
  7.  *
  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:
  12.  *
  13.  *   <URL:ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/>
  14.  *
  15.  * It does not contain any code written for other TGA file loaders.
  16.  * Not even the RLE handling. ;)
  17.  *
  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.
  22.  *
  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.
  27.  *
  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.
  31.  */
  32.  
  33. /*
  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!
  38.  *
  39.  * Release 1.2, 1997-09-24, Gordon Matzigkeit <gord@gnu.ai.mit.edu>:
  40.  *   - Bug fixes and source cleanups.
  41.  *
  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.
  45.  *
  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.
  52.  *
  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.
  56.  *
  57.  *
  58.  * TODO:
  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.
  65.  */
  66.  
  67. /* Set these for debugging. */
  68. /* #define PROFILE 1 */
  69.  
  70. #include "config.h"
  71.  
  72. #ifdef PROFILE
  73. # include <sys/times.h>
  74. #endif
  75.  
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #ifdef HAVE_UNISTD_H
  80. #include <unistd.h>
  81. #endif
  82.  
  83. #include <gtk/gtk.h>
  84.  
  85. #include <libgimp/gimp.h>
  86. #include <libgimp/gimpui.h>
  87.  
  88. #include "libgimp/stdplugins-intl.h"
  89.  
  90.  
  91. /* Round up a division to the nearest integer. */
  92. #define ROUNDUP_DIVIDE(n,d) (((n) + (d - 1)) / (d))
  93.  
  94. typedef struct _TgaSaveVals
  95. {
  96.   gint rle;
  97. } TgaSaveVals;
  98.  
  99. static TgaSaveVals tsvals =
  100. {
  101.   1,    /* rle */
  102. };
  103.  
  104. typedef struct _TgaSaveInterface
  105. {
  106.   gint run;
  107. } TgaSaveInterface;
  108.  
  109. static TgaSaveInterface tsint =
  110. {
  111.   FALSE                /*  run  */
  112. };
  113.  
  114.  
  115.  /* TRUEVISION-XFILE magic signature string */
  116. static guchar magic[18] =
  117. {
  118.   0x54, 0x52, 0x55, 0x45, 0x56, 0x49, 0x53, 0x49, 0x4f,
  119.   0x4e, 0x2d, 0x58, 0x46, 0x49, 0x4c, 0x45, 0x2e, 0x0
  120. };
  121.  
  122. typedef struct tga_info_struct
  123. {
  124.   guint8 idLength;
  125.   guint8 colorMapType;
  126.  
  127.   guint8 imageType;
  128.   /* Known image types. */
  129. #define TGA_TYPE_MAPPED      1
  130. #define TGA_TYPE_COLOR       2
  131. #define TGA_TYPE_GRAY        3
  132.  
  133.   guint8 imageCompression;
  134.   /* Only known compression is RLE */
  135. #define TGA_COMP_NONE        0 
  136. #define TGA_COMP_RLE         1 
  137.  
  138.   /* Color Map Specification. */
  139.   /* We need to separately specify high and low bytes to avoid endianness
  140.      and alignment problems. */
  141.  
  142.   guint16 colorMapIndex;
  143.   guint16 colorMapLength;
  144.   guint8 colorMapSize;
  145.  
  146.   /* Image Specification. */
  147.   guint16 xOrigin;
  148.   guint16 yOrigin;
  149.  
  150.   guint16 width;
  151.   guint16 height;
  152.  
  153.   guint8 bpp;
  154.   guint8 bytes;
  155.  
  156.   guint8 alphaBits;
  157.   guint8 flipHoriz;
  158.   guint8 flipVert;
  159.  
  160.   /* Extensions (version 2) */
  161.  
  162. /* Not all the structures described in the standard are transcribed here
  163.    only those which seem applicable to Gimp */
  164.  
  165.   gchar authorName[41];
  166.   gchar comment[324];
  167.   guint month, day, year, hour, minute, second;
  168.   gchar jobName[41];
  169.   gchar softwareID[41];
  170.   guint pixelWidth, pixelHeight;  /* write dpi? */
  171.   gdouble gamma;
  172. } tga_info;
  173.  
  174.  
  175. /* Declare some local functions.
  176.  */
  177. static void   query               (void);
  178. static void   run                 (gchar      *name,
  179.                    gint        nparams,
  180.                    GimpParam  *param,
  181.                    gint       *nreturn_vals,
  182.                    GimpParam **return_vals);
  183.  
  184. static gint32 load_image           (gchar     *filename);
  185. static gint   save_image           (gchar     *filename,
  186.                     gint32     image_ID,
  187.                     gint32     drawable_ID);
  188.  
  189. static gint   save_dialog          (void);
  190. static void   save_ok_callback     (GtkWidget *widget,
  191.                     gpointer   data);
  192.  
  193. static gint32 ReadImage            (FILE      *fp,
  194.                     tga_info  *info,
  195.                     gchar     *filename);
  196.  
  197.  
  198. GimpPlugInInfo PLUG_IN_INFO =
  199. {
  200.   NULL,  /* init_proc  */
  201.   NULL,  /* quit_proc  */
  202.   query, /* query_proc */
  203.   run,   /* run_proc   */
  204. };
  205.  
  206.  
  207. MAIN ()
  208.  
  209. static void
  210. query (void)
  211. {
  212.   static GimpParamDef load_args[] =
  213.   {
  214.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  215.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  216.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  217.   };
  218.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  219.  
  220.   static GimpParamDef load_return_vals[] =
  221.   {
  222.     { GIMP_PDB_IMAGE, "image", "Output image" }
  223.   };
  224.   static gint nload_return_vals = (sizeof (load_return_vals) /
  225.                    sizeof (load_return_vals[0]));
  226.  
  227.   static GimpParamDef save_args[] =
  228.   {
  229.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  230.     { GIMP_PDB_IMAGE, "image", "Input image" },
  231.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  232.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  233.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" },
  234.     { GIMP_PDB_INT32, "rle", "Use RLE compression" }
  235.  
  236.   } ;
  237.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  238.  
  239.   gimp_install_procedure ("file_tga_load",
  240.                           "Loads files of Targa file format",
  241.                           "FIXME: write help for tga_load",
  242.                           "Raphael FRANCOIS, Gordon Matzigkeit",
  243.                           "Raphael FRANCOIS, Gordon Matzigkeit",
  244.                           "1997",
  245.                           "<Load>/TGA",
  246.                           NULL,
  247.                           GIMP_PLUGIN,
  248.                           nload_args, nload_return_vals,
  249.                           load_args, load_return_vals);
  250.  
  251.   gimp_install_procedure ("file_tga_save",
  252.                           "saves files in the Targa file format",
  253.                           "FIXME: write help for tga_save",
  254.               "Raphael FRANCOIS, Gordon Matzigkeit",
  255.                           "Raphael FRANCOIS, Gordon Matzigkeit",
  256.                           "1997",
  257.                           "<Save>/TGA",
  258.               "RGB*, GRAY*, INDEXED*",
  259.                           GIMP_PLUGIN,
  260.                           nsave_args, 0,
  261.                           save_args, NULL);
  262.  
  263.   gimp_register_load_handler ("file_tga_load", "tga", "");
  264.         
  265.   gimp_register_save_handler ("file_tga_save", "tga", "");
  266. }
  267.  
  268. static void
  269. run (gchar      *name,
  270.      gint        nparams,
  271.      GimpParam  *param,
  272.      gint       *nreturn_vals,
  273.      GimpParam **return_vals)
  274. {
  275.   static GimpParam     values[2];
  276.   GimpRunModeType      run_mode;
  277.   GimpPDBStatusType    status = GIMP_PDB_SUCCESS;
  278.   gint32               image_ID;
  279.   gint32               drawable_ID;
  280.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  281.  
  282. #ifdef PROFILE
  283.   struct tms tbuf1, tbuf2;
  284. #endif
  285.  
  286.   run_mode = param[0].data.d_int32;
  287.  
  288.   *nreturn_vals = 1;
  289.   *return_vals  = values;
  290.   values[0].type          = GIMP_PDB_STATUS;
  291.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  292.  
  293.   if (strcmp (name, "file_tga_load") == 0)
  294.     {
  295.       INIT_I18N();
  296.  
  297. #ifdef PROFILE
  298.       times (&tbuf1);
  299. #endif
  300.  
  301.       image_ID = load_image (param[1].data.d_string);
  302.  
  303.       if (image_ID != -1)
  304.         {
  305.           *nreturn_vals = 2;
  306.           values[1].type         = GIMP_PDB_IMAGE;
  307.           values[1].data.d_image = image_ID;
  308.         }
  309.       else
  310.         {
  311.           status = GIMP_PDB_EXECUTION_ERROR;
  312.         }
  313.     }
  314.   else if (strcmp (name, "file_tga_save") == 0)
  315.     {
  316.       INIT_I18N_UI();
  317.       gimp_ui_init ("tga", FALSE);
  318.  
  319.       image_ID     = param[1].data.d_int32;
  320.       drawable_ID  = param[2].data.d_int32;
  321.  
  322.       /*  eventually export the image */ 
  323.       switch (run_mode)
  324.     {
  325.     case GIMP_RUN_INTERACTIVE:
  326.     case GIMP_RUN_WITH_LAST_VALS:
  327.       export = gimp_export_image (&image_ID, &drawable_ID, "TGA", 
  328.                       (GIMP_EXPORT_CAN_HANDLE_RGB |
  329.                        GIMP_EXPORT_CAN_HANDLE_GRAY |
  330.                        GIMP_EXPORT_CAN_HANDLE_INDEXED | 
  331.                        GIMP_EXPORT_CAN_HANDLE_ALPHA ));
  332.       if (export == GIMP_EXPORT_CANCEL)
  333.         {
  334.           values[0].data.d_status = GIMP_PDB_CANCEL;
  335.           return;
  336.         }
  337.       break;
  338.     default:
  339.       break;
  340.     }
  341.  
  342.       switch (run_mode)
  343.     {
  344.     case GIMP_RUN_INTERACTIVE:
  345.       /*  Possibly retrieve data  */
  346.       gimp_get_data ("file_tga_save", &tsvals);
  347.  
  348.       /*  First acquire information with a dialog  */
  349.       if (! save_dialog ())
  350.         status = GIMP_PDB_CANCEL;
  351.       break;
  352.  
  353.     case GIMP_RUN_NONINTERACTIVE:
  354.       /*  Make sure all the arguments are there!  */
  355.       if (nparams != 6)
  356.         {
  357.           status = GIMP_PDB_CALLING_ERROR;
  358.         }
  359.       else
  360.         {
  361.           tsvals.rle = (param[5].data.d_int32) ? TRUE : FALSE;
  362.         }
  363.       break;
  364.  
  365.     case GIMP_RUN_WITH_LAST_VALS:
  366.       /*  Possibly retrieve data  */
  367.       gimp_get_data ("file_tga_save", &tsvals);
  368.       break;
  369.  
  370.     default:
  371.       break;
  372.     }
  373.  
  374. #ifdef PROFILE
  375.       times (&tbuf1);
  376. #endif
  377.  
  378.       if (status == GIMP_PDB_SUCCESS)
  379.     {
  380.       if (save_image (param[3].data.d_string, image_ID, drawable_ID))
  381.         {
  382.           /*  Store psvals data  */
  383.           gimp_set_data ("file_tga_save", &tsvals, sizeof (tsvals));
  384.         }
  385.       else
  386.         {
  387.           status = GIMP_PDB_EXECUTION_ERROR;
  388.         }
  389.     }
  390.  
  391.       if (export == GIMP_EXPORT_EXPORT)
  392.     gimp_image_delete (image_ID);
  393.     }
  394.   else
  395.     {
  396.       status = GIMP_PDB_CALLING_ERROR;
  397.     }
  398.  
  399.   values[0].data.d_status = status;
  400.  
  401. #ifdef PROFILE
  402.   times (&tbuf2);
  403.   printf ("TGA: %s profile: %ld user %ld system\n", name,
  404.       (long) tbuf2.tms_utime - tbuf1.tms_utime,
  405.       (long) tbuf2.tms_stime - tbuf2.tms_stime);
  406. #endif
  407. }
  408.  
  409. static gint32
  410. load_image (gchar *filename)
  411. {
  412.   FILE     *fp;
  413.   gchar    *name_buf;
  414.   tga_info  info;
  415.   guchar    header[18];
  416.   guchar    footer[26];
  417.   guchar    extension[495];
  418.   long      offset;
  419.  
  420.   gint32 image_ID = -1;
  421.  
  422.   fp = fopen (filename, "rb");
  423.   if (!fp)
  424.     {
  425.       g_message (_("TGA: can't open \"%s\"\n"), filename);
  426.       return -1;
  427.     }
  428.  
  429.   name_buf = g_strdup_printf( _("Loading %s:"), filename);
  430.   gimp_progress_init (name_buf);
  431.   g_free (name_buf);
  432.  
  433.   if (!fseek (fp, -26L, SEEK_END)) { /* Is file big enough for a footer? */
  434.     if (fread (footer, sizeof (footer), 1, fp) != 1) {
  435.       g_message (_("TGA: Cannot read footer from \"%s\"\n"), filename);
  436.       return -1;
  437.     } else if (memcmp (footer + 8, magic, sizeof (magic)) == 0) {
  438.  
  439.        /* Check the signature. */
  440.  
  441.       offset= footer[0] + (footer[1] * 256) + (footer[2] * 65536)
  442.                         + (footer[3] * 16777216);
  443.  
  444.       if (fseek (fp, offset, SEEK_SET) ||
  445.           fread (extension, sizeof (extension), 1, fp) != 1) {
  446.         g_message (_("TGA: Cannot read extension from \"%s\"\n"), filename);
  447.         return -1;
  448.       }
  449.  
  450.       /* Eventually actually handle version 2 TGA here */
  451.     }
  452.   }
  453.  
  454.   if (fseek (fp, 0, SEEK_SET) ||
  455.       fread (header, sizeof (header), 1, fp) != 1)
  456.     {
  457.       g_message ("TGA: Cannot read header from \"%s\"\n", filename);
  458.       return -1;
  459.     }
  460.  
  461.   switch (header[2])
  462.     {
  463.     case 1:
  464.       info.imageType = TGA_TYPE_MAPPED;
  465.       info.imageCompression = TGA_COMP_NONE;
  466.       break;
  467.     case 2:
  468.       info.imageType = TGA_TYPE_COLOR;
  469.       info.imageCompression = TGA_COMP_NONE;
  470.       break;
  471.     case 3:
  472.       info.imageType = TGA_TYPE_GRAY;
  473.       info.imageCompression = TGA_COMP_NONE;
  474.       break;
  475.  
  476.     case 9:
  477.       info.imageType = TGA_TYPE_MAPPED;
  478.       info.imageCompression = TGA_COMP_RLE;
  479.       break;
  480.     case 10:
  481.       info.imageType = TGA_TYPE_COLOR;
  482.       info.imageCompression = TGA_COMP_RLE;
  483.       break;
  484.     case 11:
  485.       info.imageType = TGA_TYPE_GRAY;
  486.       info.imageCompression = TGA_COMP_RLE;
  487.       break;
  488.  
  489.     default:
  490.       info.imageType = 0;
  491.     }
  492.  
  493.   info.idLength     = header[0];
  494.   info.colorMapType = header[1];
  495.  
  496.   info.colorMapIndex  = header[3] + header[4] * 256;
  497.   info.colorMapLength = header[5] + header[6] * 256;
  498.   info.colorMapSize   = header[7];
  499.  
  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;
  504.   
  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;
  510.  
  511.   switch (info.imageType)
  512.     {
  513.       case TGA_TYPE_MAPPED:
  514.         if (info.bpp != 8)
  515.           {
  516.             g_message ("TGA: Unhandled sub-format in \"%s\"\n", filename);
  517.             return -1;
  518.           }
  519.         break;
  520.       case TGA_TYPE_COLOR:
  521.         if (info.alphaBits == 0 && info.bpp == 32)
  522.           {
  523.             g_message ("TGA: Possibly incorrect alpha in \"%s\"\n", filename);
  524.             info.alphaBits = 8;
  525.           }
  526.         if (info.bpp != 16 && info.bpp != 24
  527.                      && (info.alphaBits != 8 || info.bpp != 32))
  528.           {
  529.             g_message ("TGA: Unhandled sub-format in \"%s\"\n", filename);
  530.             return -1;
  531.           }
  532.         break;
  533.       case TGA_TYPE_GRAY:
  534.         if (info.alphaBits == 0 && info.bpp == 16)
  535.           {
  536.             g_message ("TGA: Possibly incorrect alpha in \"%s\"\n", filename);
  537.             info.alphaBits = 8;
  538.           }
  539.         if (info.bpp != 8 && (info.alphaBits != 8 || info.bpp != 16))
  540.           {
  541.             g_message ("TGA: Unhandled sub-format in \"%s\"\n", filename);
  542.             return -1;
  543.           }
  544.         break;
  545.  
  546.       default:
  547.         g_message ("TGA: Unknown image type for \"%s\"\n", filename);
  548.         return -1;
  549.     }
  550.  
  551.   /* Plausible but unhandled formats */
  552.   if (info.bytes * 8 != info.bpp)
  553.     {
  554.       g_message ("TGA: No support yet for TGA with these parameters\n");
  555.       return -1;
  556.     }
  557.  
  558.   /* Check that we have a color map only when we need it. */
  559.   if (info.imageType == TGA_TYPE_MAPPED && info.colorMapType != 1)
  560.     {
  561.       g_message ("TGA: indexed image has invalid color map type %d\n",
  562.                   info.colorMapType);
  563.       return -1;
  564.     }
  565.   else if (info.imageType != TGA_TYPE_MAPPED && info.colorMapType != 0)
  566.     {
  567.       g_message ("TGA: non-indexed image has invalid color map type %d\n",
  568.                   info.colorMapType);
  569.       return -1;
  570.     }
  571.  
  572.   /* Skip the image ID field. */
  573.   if (info.idLength && fseek (fp, info.idLength, SEEK_CUR))
  574.     {
  575.       g_message ("TGA: File is truncated or corrupted \"%s\"\n", filename);
  576.       return -1;
  577.     }
  578.  
  579.   image_ID = ReadImage (fp, &info, filename);
  580.   fclose (fp);
  581.   return image_ID;
  582. }
  583.  
  584. static void
  585. rle_write (FILE   *fp,
  586.        guchar *buffer,
  587.        guint   width,
  588.        guint   bytes)
  589. {
  590.   gint    repeat = 0;
  591.   gint    direct = 0;
  592.   guchar *from   = buffer;
  593.   gint    x;
  594.   
  595.   for (x = 1; x < width; ++x)
  596.     {
  597.       if (memcmp (buffer, buffer + bytes, bytes))
  598.     {
  599.       /* next pixel is different */
  600.       if (repeat)
  601.         {
  602.           putc (128 + repeat, fp);
  603.           fwrite (from, bytes, 1, fp);
  604.           from = buffer+ bytes; /* point to first different pixel */
  605.           repeat = 0;
  606.           direct = 0;
  607.         }
  608.       else
  609.         {
  610.           direct += 1;
  611.         }
  612.     }
  613.       else
  614.     {
  615.       /* next pixel is the same */
  616.       if (direct)
  617.         {
  618.           putc (direct - 1, fp);
  619.           fwrite (from, bytes, direct, fp);
  620.           from = buffer; /* point to first identical pixel */
  621.           direct = 0;
  622.           repeat = 1;
  623.         }
  624.       else
  625.         {
  626.           repeat += 1;
  627.         }
  628.     }
  629.  
  630.       if (repeat == 128)
  631.     {
  632.       putc (255, fp);
  633.       fwrite (from, bytes, 1, fp);
  634.       from = buffer+ bytes;
  635.       direct = 0;
  636.       repeat = 0;
  637.     }
  638.       else if (direct == 128)
  639.     {
  640.       putc (127, fp);
  641.       fwrite (from, bytes, direct, fp);
  642.       from = buffer+ bytes;
  643.       direct = 0;
  644.       repeat = 0;
  645.     }
  646.  
  647.       buffer += bytes;
  648.     }
  649.  
  650.   if (repeat > 0)
  651.     {
  652.       putc (128 + repeat, fp);
  653.       fwrite (from, bytes, 1, fp);
  654.     }
  655.   else
  656.     {
  657.       putc (direct, fp);
  658.       fwrite (from, bytes, direct + 1, fp);
  659.     }
  660. }
  661.  
  662. static gint
  663. rle_read (FILE     *fp,
  664.       guchar   *buffer,
  665.       tga_info *info)
  666. {
  667.   static gint   repeat = 0;
  668.   static gint   direct = 0;
  669.   static guchar sample[4];
  670.   gint head;
  671.   gint x, k;
  672.  
  673.   for (x = 0; x < info->width; x++)
  674.     {
  675.       if (repeat == 0 && direct == 0)
  676.     {
  677.       head = getc (fp);
  678.  
  679.       if (head == EOF)
  680.         {
  681.           return EOF;
  682.         }
  683.       else if (head >= 128)
  684.         {
  685.           repeat = head - 127;
  686.  
  687.           if (fread (sample, info->bytes, 1, fp) < 1)
  688.         return EOF;
  689.         }
  690.       else
  691.         {
  692.           direct = head + 1;
  693.         }
  694.     }
  695.  
  696.       if (repeat > 0)
  697.     {
  698.       for (k = 0; k < info->bytes; ++k)
  699.         {
  700.           buffer[k] = sample[k];
  701.         }
  702.  
  703.       repeat--;
  704.     }
  705.       else /* direct > 0 */
  706.     {
  707.       if (fread (buffer, info->bytes, 1, fp) < 1)
  708.         return EOF;
  709.  
  710.       direct--;
  711.     }
  712.  
  713.       buffer += info->bytes;
  714.     }
  715.  
  716.   return 0;
  717. }
  718.  
  719. static void
  720. flip_line (guchar   *buffer,
  721.        tga_info *info)
  722. {
  723.   guchar  temp;
  724.   guchar *alt;
  725.   gint    x, s;
  726.  
  727.   alt = buffer + (info->bytes * (info->width - 1));
  728.  
  729.   for (x = 0; x * 2 <= info->width; x++)
  730.     {
  731.       for (s = 0; s < info->bytes; ++s)
  732.     {
  733.       temp = buffer[s];
  734.       buffer[s] = alt[s];
  735.       alt[s] = temp;
  736.     }
  737.  
  738.       buffer += info->bytes;
  739.       alt -= info->bytes;
  740.     }
  741. }
  742.  
  743. /* Some people write 16-bit RGB TGA files. The spec would probably
  744.    allow 27-bit RGB too, for what it's worth, but I won't fix that
  745.    unless someone actually provides an existence proof */
  746.  
  747. static void
  748. upsample (guchar *dest,
  749.       guchar *src,
  750.       guint   width,
  751.       guint   bytes)
  752. {
  753.   gint x;
  754.  
  755.   for (x = 0; x < width; x++)
  756.     {
  757.       dest[0] =  ((src[1] << 1) & 0xf8);
  758.       dest[0] += (dest[0] >> 5);
  759.  
  760.       dest[1] =  ((src[0] & 0xe0) >> 2) + ((src[1] & 0x03) << 6);
  761.       dest[1] += (dest[1] >> 5);
  762.  
  763.       dest[2] =  ((src[0] << 3) & 0xf8);
  764.       dest[2] += (dest[2] >> 5);
  765.  
  766.       dest += 3;
  767.       src += bytes;
  768.     }
  769. }
  770.  
  771. static void
  772. bgr2rgb (guchar *dest,
  773.      guchar *src,
  774.      guint   width,
  775.      guint   bytes,
  776.      guint   alpha)
  777. {
  778.   guint x;
  779.  
  780.   if (alpha)
  781.     {
  782.       for (x = 0; x < width; x++)
  783.     {
  784.       *(dest++) = src[2];
  785.       *(dest++) = src[1];
  786.       *(dest++) = src[0];
  787.       *(dest++) = src[3];
  788.  
  789.       src += bytes;
  790.     }
  791.     }
  792.   else
  793.     {
  794.       for (x = 0; x < width; x++)
  795.     {
  796.       *(dest++) = src[2];
  797.       *(dest++) = src[1];
  798.       *(dest++) = src[0];
  799.  
  800.       src += bytes;
  801.     }
  802.     }
  803. }
  804.  
  805. static void
  806. read_line (FILE         *fp,
  807.        guchar       *row,
  808.        guchar       *buffer,
  809.        tga_info     *info,
  810.        GimpDrawable *drawable)
  811. {
  812.   if (info->imageCompression == TGA_COMP_RLE)
  813.     {
  814.       rle_read (fp, buffer, info);
  815.     }
  816.   else
  817.     {
  818.       fread (buffer, info->bytes, info->width, fp);
  819.     }
  820.  
  821.   if (info->flipHoriz)
  822.     {
  823.       flip_line (buffer, info);
  824.     }
  825.  
  826.   if (info->imageType == TGA_TYPE_COLOR)
  827.     {
  828.       if (info->bpp == 16)
  829.     {
  830.       upsample (row, buffer, info->width, info->bytes);
  831.     }
  832.       else
  833.     {
  834.       bgr2rgb (row, buffer,info->width,info->bytes,info->alphaBits);
  835.     }
  836.     }
  837.   else
  838.     {
  839.       memcpy (row, buffer, info->width * drawable->bpp);
  840.     }
  841. }
  842.  
  843. static gint32
  844. ReadImage (FILE     *fp,
  845.        tga_info *info,
  846.        gchar    *filename)
  847. {
  848.   static gint32 image_ID;
  849.   gint32        layer_ID;
  850.  
  851.   GimpPixelRgn       pixel_rgn;
  852.   GimpDrawable      *drawable;
  853.   guchar            *data, *buffer, *row;
  854.   GimpImageType      dtype = 0;
  855.   GimpImageBaseType  itype = 0;
  856.   gint               i, y;
  857.  
  858.   gint max_tileheight, tileheight;
  859.  
  860.   guint  cmap_bytes;
  861.   guchar tga_cmap[4 * 256], gimp_cmap[3 * 256];
  862.  
  863.   switch (info->imageType)
  864.     {
  865.     case TGA_TYPE_MAPPED:
  866.       itype = GIMP_INDEXED;
  867.  
  868.       if (info->alphaBits)
  869.     dtype = GIMP_INDEXEDA_IMAGE;
  870.       else
  871.     dtype = GIMP_INDEXED_IMAGE;
  872.       break;
  873.  
  874.     case TGA_TYPE_GRAY:
  875.       itype = GIMP_GRAY;
  876.  
  877.       if (info->alphaBits)
  878.     dtype = GIMP_GRAYA_IMAGE;
  879.       else
  880.     dtype = GIMP_GRAY_IMAGE;
  881.       break;
  882.  
  883.     case TGA_TYPE_COLOR:
  884.       itype = GIMP_RGB;
  885.  
  886.       if (info->alphaBits)
  887.     dtype = GIMP_RGBA_IMAGE;
  888.       else
  889.     dtype = GIMP_RGB_IMAGE;
  890.       break;
  891.     }
  892.  
  893.   /* Handle colormap */
  894.  
  895.   if (info->colorMapType == 1)
  896.     {
  897.       cmap_bytes= (info->colorMapSize + 7 ) / 8;
  898.       if (cmap_bytes <= 4 &&
  899.           fread (tga_cmap, info->colorMapLength * cmap_bytes, 1, fp) == 1)
  900.         {
  901.           if (info->colorMapSize == 32)
  902.             bgr2rgb(gimp_cmap, tga_cmap, info->colorMapLength, cmap_bytes, 1);
  903.           else if (info->colorMapSize == 24)
  904.             bgr2rgb(gimp_cmap, tga_cmap, info->colorMapLength, cmap_bytes, 0);
  905.           else if (info->colorMapSize == 16)
  906.             upsample(gimp_cmap, tga_cmap, info->colorMapLength, cmap_bytes);
  907.  
  908.         }
  909.       else
  910.         {
  911.           g_message ("TGA: File is truncated or corrupted \"%s\"\n", filename);
  912.           return -1;
  913.         }
  914.     }
  915.  
  916.   image_ID = gimp_image_new (info->width, info->height, itype);
  917.   gimp_image_set_filename (image_ID, filename);
  918.  
  919.   if (info->colorMapType == 1)
  920.     gimp_image_set_cmap(image_ID, gimp_cmap, info->colorMapLength);
  921.  
  922.   layer_ID = gimp_layer_new (image_ID,
  923.                  _("Background"),
  924.                  info->width, info->height,
  925.                  dtype, 100,
  926.                  GIMP_NORMAL_MODE);
  927.  
  928.   gimp_image_add_layer (image_ID, layer_ID, 0);
  929.  
  930.   drawable = gimp_drawable_get (layer_ID);
  931.  
  932.   /* Prepare the pixel region. */
  933.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
  934.                         info->width, info->height, TRUE, FALSE);
  935.  
  936.   /* Allocate the data. */
  937.   max_tileheight = gimp_tile_height ();
  938.   data = (guchar *) g_malloc (info->width * max_tileheight * drawable->bpp);
  939.   buffer = (guchar *) g_malloc (info->width * info->bytes);
  940.  
  941.   if (info->flipVert)
  942.     {
  943.       for (i = 0; i < info->height; i += tileheight)
  944.         {
  945.           tileheight = i ? max_tileheight : (info->height % max_tileheight);
  946.           if (tileheight == 0) tileheight= max_tileheight;
  947.  
  948.           for (y= 1; y <= tileheight; ++y)
  949.             {
  950.               row= data + (info->width * drawable->bpp * (tileheight - y));
  951.               read_line(fp, row, buffer, info, drawable);
  952.             }
  953.  
  954.             gimp_progress_update((double) (i + tileheight)
  955.                                / (double) info->height);
  956.             gimp_pixel_rgn_set_rect(&pixel_rgn, data, 0, 
  957.                                info->height - i - tileheight,  
  958.                                info->width, tileheight);
  959.         }
  960.     }
  961.   else
  962.     {
  963.       for (i = 0; i < info->height; i += max_tileheight)
  964.         {
  965.           tileheight = MIN (max_tileheight, info->height - i);
  966.  
  967.           for (y= 0; y < tileheight; ++y)
  968.             {
  969.               row= data + (info->width * drawable->bpp * y);
  970.               read_line(fp, row, buffer, info, drawable);
  971.             }
  972.  
  973.             gimp_progress_update((double) (i + tileheight)
  974.                                / (double) info->height);
  975.             gimp_pixel_rgn_set_rect(&pixel_rgn, data, 0, i, 
  976.                                info->width, tileheight);
  977.         }
  978.     }
  979.  
  980.   g_free (data);
  981.   g_free (buffer);
  982.  
  983.   gimp_drawable_flush (drawable);
  984.   gimp_drawable_detach (drawable);
  985.  
  986.   return image_ID;
  987. }  /*read_image*/
  988.  
  989.  
  990. static gint
  991. save_image (gchar  *filename,
  992.         gint32  image_ID,
  993.         gint32  drawable_ID)
  994. {
  995.   GimpPixelRgn   pixel_rgn;
  996.   GimpDrawable  *drawable;
  997.   GimpImageType  dtype;
  998.   gint           width;
  999.   gint           height;
  1000.  
  1001.   FILE     *fp;
  1002.   guchar   *name_buf;
  1003.   gint      tileheight;
  1004.   gint      out_bpp = 0;
  1005.   gboolean  status  = TRUE;
  1006.   gint      i, row;
  1007.  
  1008.   guchar  header[18];
  1009.   guchar  footer[26];
  1010.   guchar *pixels;
  1011.   guchar *data;
  1012.  
  1013.   guint   num_colors;
  1014.   guchar *gimp_cmap = NULL;
  1015.  
  1016.   drawable = gimp_drawable_get (drawable_ID);
  1017.   dtype    = gimp_drawable_type (drawable_ID);
  1018.  
  1019.   width  = drawable->width;
  1020.   height = drawable->height;
  1021.  
  1022.   name_buf = g_strdup_printf (_("Saving %s:"), filename);
  1023.   gimp_progress_init ((gchar *)name_buf);
  1024.   g_free (name_buf);
  1025.  
  1026.   if ((fp = fopen (filename, "wb")) == NULL)
  1027.     {
  1028.       g_message ("TGA: can't create \"%s\"\n", filename);
  1029.       return FALSE;
  1030.     }
  1031.  
  1032.   header[0] = 0; /* No image identifier / description */
  1033.  
  1034.   if (dtype == GIMP_INDEXED_IMAGE || dtype == GIMP_INDEXEDA_IMAGE)
  1035.     {
  1036.       gimp_cmap = gimp_image_get_cmap (image_ID, &num_colors);
  1037.  
  1038.       header[1] = 1; /* cmap type */
  1039.       header[2] = (tsvals.rle) ? 9 : 1;
  1040.       header[3] = header[4]= 0; /* no offset */
  1041.       header[5] = num_colors % 256;
  1042.       header[6] = num_colors / 256; 
  1043.       header[7] = 24; /* cmap size / bits */
  1044.     }
  1045.   else
  1046.     {
  1047.       header[1]= 0;
  1048.  
  1049.       if (dtype == GIMP_RGB_IMAGE || dtype == GIMP_RGBA_IMAGE)
  1050.     {
  1051.       header[2]= (tsvals.rle) ? 10 : 2;
  1052.     }
  1053.       else
  1054.     {
  1055.       header[2]= (tsvals.rle) ? 11 : 3;
  1056.     }
  1057.  
  1058.       header[3] = header[4] = header[5] = header[6] = header[7] = 0;
  1059.     }
  1060.  
  1061.   header[8]  = header[9]  = 0; /* xorigin */
  1062.   header[10] = header[11] = 0; /* yorigin */
  1063.  
  1064.   header[12] = width % 256;
  1065.   header[13] = width / 256;
  1066.  
  1067.   header[14] = height % 256;
  1068.   header[15] = height / 256;
  1069.  
  1070.   switch (dtype)
  1071.     {
  1072.     case GIMP_INDEXED_IMAGE:
  1073.     case GIMP_GRAY_IMAGE:
  1074.     case GIMP_INDEXEDA_IMAGE:
  1075.       out_bpp = 1;
  1076.       header[16] = 8; /* bpp */
  1077.       header[17] = 0x20; /* alpha + orientation */
  1078.       break;
  1079.  
  1080.     case GIMP_GRAYA_IMAGE:
  1081.       out_bpp = 2;
  1082.       header[16] = 16; /* bpp */
  1083.       header[17] = 0x28; /* alpha + orientation */
  1084.       break;
  1085.  
  1086.     case GIMP_RGB_IMAGE:
  1087.       out_bpp = 3;
  1088.       header[16] = 24; /* bpp */
  1089.       header[17] = 0x20; /* alpha + orientation */
  1090.       break;
  1091.  
  1092.     case GIMP_RGBA_IMAGE:
  1093.       out_bpp = 4;
  1094.       header[16] = 32; /* bpp */
  1095.       header[17] = 0x28; /* alpha + orientation */
  1096.       break;
  1097.     }
  1098.  
  1099.   /* write header to front of file */
  1100.   fwrite (header, sizeof (header), 1, fp);
  1101.  
  1102.   if (dtype == GIMP_INDEXED_IMAGE || dtype == GIMP_INDEXEDA_IMAGE)
  1103.     {
  1104.       /* write out palette */
  1105.       for (i= 0; i < num_colors; ++i)
  1106.     {
  1107.       fputc (gimp_cmap[(i * 3) + 2], fp);
  1108.       fputc (gimp_cmap[(i * 3) + 1], fp);
  1109.       fputc (gimp_cmap[(i * 3) + 0], fp);
  1110.     }
  1111.     }
  1112.  
  1113.   /* Allocate a new set of pixels. */
  1114.   tileheight = gimp_tile_height ();
  1115.  
  1116.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
  1117.  
  1118.   pixels = g_new (guchar, width * drawable->bpp);
  1119.   data   = g_new (guchar, width * out_bpp);
  1120.  
  1121.   for (row = 0; row < height; ++row)
  1122.     {
  1123.       gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, row, width, 1);
  1124.  
  1125.       if (dtype == GIMP_RGB_IMAGE)
  1126.     {
  1127.       bgr2rgb(data, pixels, width, drawable->bpp, 0);
  1128.     }
  1129.       else if (dtype == GIMP_RGBA_IMAGE)
  1130.     {
  1131.       bgr2rgb(data, pixels, width, drawable->bpp, 1);
  1132.     }
  1133.       else if (dtype == GIMP_INDEXEDA_IMAGE)
  1134.     {
  1135.       for (i = 0; i < width; ++i)
  1136.         {
  1137.           data[i]= pixels[i*2];
  1138.         }
  1139.     }
  1140.       else
  1141.     {
  1142.       memcpy (data, pixels, width * drawable->bpp);
  1143.     }
  1144.  
  1145.       if (tsvals.rle)
  1146.     {
  1147.       rle_write (fp, data, width, out_bpp);
  1148.     }
  1149.       else
  1150.     {
  1151.       fwrite (data, width * out_bpp, 1, fp);
  1152.     }
  1153.  
  1154.       gimp_progress_update ((gdouble) row / (gdouble) height);
  1155.     }
  1156.  
  1157.   gimp_drawable_detach (drawable);
  1158.   g_free (data);
  1159.  
  1160.   /* footer must be the last thing written to file */
  1161.   memset (footer, 0, 8); /* No extensions, no developer directory */
  1162.   memcpy (footer + 8, magic, sizeof (magic)); /* magic signature */
  1163.   fwrite (footer, sizeof (footer), 1, fp);
  1164.  
  1165.   fclose (fp);
  1166.  
  1167.   return status;
  1168. }
  1169.  
  1170. static gint
  1171. save_dialog (void)
  1172. {
  1173.   GtkWidget *dlg;
  1174.   GtkWidget *toggle;
  1175.   GtkWidget *frame;
  1176.   GtkWidget *vbox;
  1177.  
  1178.   dlg = gimp_dialog_new (_("Save as TGA"), "tga",
  1179.              gimp_standard_help_func, "filters/tga.html",
  1180.              GTK_WIN_POS_MOUSE,
  1181.              FALSE, TRUE, FALSE,
  1182.  
  1183.              _("OK"), save_ok_callback,
  1184.              NULL, NULL, NULL, TRUE, FALSE,
  1185.              _("Cancel"), gtk_widget_destroy,
  1186.              NULL, 1, NULL, FALSE, TRUE,
  1187.  
  1188.              NULL);
  1189.  
  1190.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  1191.               GTK_SIGNAL_FUNC (gtk_main_quit),
  1192.               NULL);
  1193.  
  1194.   /* regular tga parameter settings */
  1195.   frame = gtk_frame_new (_("Targa Options"));
  1196.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  1197.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  1198.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0);
  1199.  
  1200.   vbox = gtk_vbox_new (FALSE, 2);
  1201.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  1202.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  1203.  
  1204.   /*  rle  */
  1205.   toggle = gtk_check_button_new_with_label (_("RLE compression"));
  1206.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  1207.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  1208.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1209.               &tsvals.rle);
  1210.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), tsvals.rle);
  1211.   gtk_widget_show (toggle);
  1212.  
  1213.   gtk_widget_show (vbox);
  1214.   gtk_widget_show (frame);
  1215.  
  1216.   gtk_widget_show (dlg);
  1217.  
  1218.   gtk_main ();
  1219.   gdk_flush ();
  1220.  
  1221.   return tsint.run;
  1222. }
  1223.  
  1224. static void
  1225. save_ok_callback (GtkWidget *widget,
  1226.           gpointer   data)
  1227. {
  1228.   tsint.run = TRUE;
  1229.  
  1230.   gtk_widget_destroy (GTK_WIDGET (data));
  1231. }
  1232.