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 / pcx.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-22  |  17.2 KB  |  711 lines

  1. /* pcx.c GIMP plug-in for loading & saving PCX files */
  2.  
  3. /* This code is based in parts on code by Francisco Bustamante, but the
  4.    largest portion of the code has been rewritten and is now maintained
  5.    occasionally by Nick Lamb njl195@zepler.org.uk */
  6.  
  7. /* New for 1998 -- Load 1, 4, 8 & 24 bit PCX files */
  8. /*              -- Save 8 & 24 bit PCX files */
  9. /* 1998-01-19 - fixed some endianness problems (Raphael Quinet) */
  10. /* 1998-02-05 - merged patch with "official" tree, some tidying up (njl) */
  11. /* 1998-05-17 - changed email address, more tidying up (njl) */
  12. /* 1998-05-31 - g_message (njl) */
  13.  
  14. /* Please contact me if you can't use your PCXs with this tool, I want
  15.    The GIMP to have the best file filters on the planet */
  16.  
  17. #include "config.h"
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22.  
  23. #include <gtk/gtk.h>
  24.  
  25. #include <libgimp/gimp.h>
  26. #include <libgimp/gimpui.h>
  27.  
  28. #include "libgimp/stdplugins-intl.h"
  29.  
  30.  
  31. /* Declare plug-in functions.  */
  32.  
  33. static void query (void);
  34. static void run   (gchar   *name, 
  35.            gint     nparams, 
  36.            GimpParam  *param, 
  37.            gint    *nreturn_vals,
  38.            GimpParam **return_vals);
  39.  
  40. #if G_BYTE_ORDER == G_BIG_ENDIAN
  41. #define qtohl(x) \
  42.         ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
  43.                              (((unsigned long int)(x) & 0x0000ff00U) <<  8) | \
  44.                              (((unsigned long int)(x) & 0x00ff0000U) >>  8) | \
  45.                              (((unsigned long int)(x) & 0xff000000U) >> 24)))
  46. #define qtohs(x) \
  47.         ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
  48.                               (((unsigned short int)(x) & 0xff00) >> 8)))
  49. #else
  50. #define qtohl(x) (x)
  51. #define qtohs(x) (x)
  52. #endif
  53. #define htoql(x) qtohl(x)
  54. #define htoqs(x) qtohs(x)
  55.  
  56. GimpPlugInInfo PLUG_IN_INFO =
  57. {
  58.   NULL,  /* init_proc  */
  59.   NULL,  /* quit_proc  */
  60.   query, /* query_proc */
  61.   run,   /* run_proc   */
  62. };
  63.  
  64. MAIN ()
  65.  
  66. static void
  67. query (void)
  68. {
  69.   static GimpParamDef load_args[] =
  70.   {
  71.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  72.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  73.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  74.   };
  75.   static GimpParamDef load_return_vals[] =
  76.   {
  77.     { GIMP_PDB_IMAGE, "image", "Output image" }
  78.   };
  79.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  80.   static gint nload_return_vals = (sizeof (load_return_vals) /
  81.                    sizeof (load_return_vals[0]));
  82.  
  83.   static GimpParamDef save_args[] =
  84.   {
  85.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  86.     { GIMP_PDB_IMAGE, "image", "Input image" },
  87.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  88.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  89.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  90.   };
  91.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  92.  
  93.   gimp_install_procedure ("file_pcx_load",
  94.                           "Loads files in Zsoft PCX file format",
  95.                           "FIXME: write help for pcx_load",
  96.                           "Francisco Bustamante & Nick Lamb",
  97.                           "Nick Lamb <njl195@zepler.org.uk>",
  98.                           "January 1997",
  99.                           "<Load>/PCX",
  100.               NULL,
  101.                           GIMP_PLUGIN,
  102.                           nload_args, nload_return_vals,
  103.                           load_args, load_return_vals);
  104.  
  105.   gimp_install_procedure ("file_pcx_save",
  106.                           "Saves files in ZSoft PCX file format",
  107.                           "FIXME: write help for pcx_save",
  108.                           "Francisco Bustamante & Nick Lamb",
  109.                           "Nick Lamb <njl195@zepler.org.uk>",
  110.                           "January 1997",
  111.                           "<Save>/PCX",
  112.               "INDEXED, RGB, GRAY",
  113.                           GIMP_PLUGIN,
  114.                           nsave_args, 0,
  115.                           save_args, NULL);
  116.  
  117.   gimp_register_magic_load_handler ("file_pcx_load",
  118.                     "pcx,pcc",
  119.                     "",
  120.                     "0&,byte,10,2&,byte,1,3&,byte,>0,3,byte,<9");
  121.   gimp_register_save_handler       ("file_pcx_save",
  122.                     "pcx,pcc",
  123.                     "");
  124. }
  125.  
  126. /* Declare internal functions. */
  127.  
  128. static gint32 load_image (gchar  *filename);
  129. static void   load_1     (FILE   *fp,
  130.               gint    width,
  131.               gint    height,
  132.               gchar  *buffer,
  133.               gint    bytes);
  134. static void   load_4     (FILE   *fp,
  135.               gint    width,
  136.               gint    height,
  137.               gchar  *buffer,
  138.               gint    bytes);
  139. static void   load_8     (FILE   *fp,
  140.               gint    width,
  141.               gint    height,
  142.               gchar  *buffer,
  143.               gint    bytes);
  144. static void   load_24    (FILE   *fp,
  145.               gint    width,
  146.               gint    height,
  147.               gchar  *buffer,
  148.               gint    bytes);
  149. static void   readline   (FILE   *fp,
  150.               guchar *buffer,
  151.               gint    bytes);
  152.  
  153. static gint   save_image (gchar  *filename,
  154.               gint32  image,
  155.               gint32  layer);
  156. static void   save_8     (FILE   *fp,
  157.               gint    width,
  158.               gint    height,
  159.               guchar *buffer);
  160. static void   save_24    (FILE   *fp,
  161.               gint    width,
  162.               gint    height,
  163.               guchar *buffer);
  164. static void   writeline  (FILE   *fp,
  165.               guchar *buffer,
  166.               gint    bytes);
  167.  
  168. /* Plug-in implementation */
  169.  
  170. static void
  171. run (gchar   *name, 
  172.      gint     nparams, 
  173.      GimpParam  *param, 
  174.      gint    *nreturn_vals,
  175.      GimpParam **return_vals) 
  176. {
  177.   static GimpParam values[2];
  178.   GimpRunModeType  run_mode;
  179.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  180.   gint32        image_ID;
  181.   gint32        drawable_ID;
  182.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  183.  
  184.   run_mode = param[0].data.d_int32;
  185.  
  186.   *nreturn_vals = 1;
  187.   *return_vals  = values;
  188.   values[0].type          = GIMP_PDB_STATUS;
  189.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  190.  
  191.   if (strcmp (name, "file_pcx_load") == 0)
  192.     {
  193.       INIT_I18N();
  194.       image_ID = load_image (param[1].data.d_string);
  195.  
  196.       if (image_ID != -1)
  197.     {
  198.       *nreturn_vals = 2;
  199.       values[1].type = GIMP_PDB_IMAGE;
  200.       values[1].data.d_image = image_ID;
  201.     }
  202.       else
  203.     {
  204.       status = GIMP_PDB_EXECUTION_ERROR;
  205.     }
  206.     }
  207.   else if (strcmp (name, "file_pcx_save") == 0)
  208.     {
  209.       image_ID    = param[1].data.d_int32;
  210.       drawable_ID = param[2].data.d_int32;
  211.  
  212.       /*  eventually export the image */ 
  213.       switch (run_mode)
  214.     {
  215.     case GIMP_RUN_INTERACTIVE:
  216.     case GIMP_RUN_WITH_LAST_VALS:
  217.       INIT_I18N_UI();
  218.       gimp_ui_init ("pcx", FALSE);
  219.       export = gimp_export_image (&image_ID, &drawable_ID, "PCX", 
  220.                       (GIMP_EXPORT_CAN_HANDLE_RGB |
  221.                        GIMP_EXPORT_CAN_HANDLE_GRAY |
  222.                        GIMP_EXPORT_CAN_HANDLE_INDEXED));
  223.       if (export == GIMP_EXPORT_CANCEL)
  224.         {
  225.           values[0].data.d_status = GIMP_PDB_CANCEL;
  226.           return;
  227.         }
  228.       break;
  229.     default:
  230.       INIT_I18N();
  231.       break;
  232.     }
  233.  
  234.       switch (run_mode)
  235.     {
  236.     case GIMP_RUN_INTERACTIVE:
  237.       break;
  238.  
  239.     case GIMP_RUN_NONINTERACTIVE:
  240.       if (nparams != 5)
  241.         status = GIMP_PDB_CALLING_ERROR;
  242.       break;
  243.  
  244.     case GIMP_RUN_WITH_LAST_VALS:
  245.       break;
  246.  
  247.     default:
  248.       break;
  249.     }
  250.  
  251.       if (status == GIMP_PDB_SUCCESS)
  252.     {
  253.       if (! save_image (param[3].data.d_string, image_ID, drawable_ID))
  254.         {
  255.           status = GIMP_PDB_EXECUTION_ERROR;
  256.         }
  257.     }
  258.       
  259.       if (export == GIMP_EXPORT_EXPORT)
  260.     gimp_image_delete (image_ID);
  261.     }
  262.   else
  263.     {
  264.       status = GIMP_PDB_CALLING_ERROR;
  265.     }
  266.  
  267.   values[0].data.d_status = status;
  268. }
  269.  
  270. guchar mono[6]= { 0, 0, 0, 255, 255, 255 };
  271.  
  272. static struct
  273. {
  274.   guint8 manufacturer;
  275.   guint8 version;
  276.   guint8 compression;
  277.   guint8 bpp;
  278.   gint16 x1, y1;
  279.   gint16 x2, y2;
  280.   gint16 hdpi;
  281.   gint16 vdpi;
  282.   guint8 colormap[48];
  283.   guint8 reserved;
  284.   guint8 planes;
  285.   gint16 bytesperline;
  286.   gint16 color;
  287.   guint8 filler[58];
  288. } pcx_header;
  289.  
  290. static gint32
  291. load_image (gchar *filename) 
  292. {
  293.   FILE *fd;
  294.   GimpDrawable *drawable;
  295.   GimpPixelRgn pixel_rgn;
  296.   gchar *message;
  297.   gint offset_x, offset_y, height, width;
  298.   gint32 image, layer;
  299.   guchar *dest, cmap[768];
  300.  
  301.   message = g_strdup_printf (_("Loading %s:"), filename);
  302.   gimp_progress_init (message);
  303.   g_free (message);
  304.  
  305.   fd = fopen (filename, "rb");
  306.   if (!fd)
  307.     {
  308.       g_message ("PCX: Can't open\n%s", filename);
  309.       return -1;
  310.     }
  311.  
  312.   if (fread (&pcx_header, 128, 1, fd) == 0)
  313.     {
  314.       g_message ("PCX: Can't read header from\n%s", filename);
  315.       return -1;
  316.     }
  317.  
  318.   if (pcx_header.manufacturer != 10)
  319.     {
  320.       g_message ("%s\nis not a PCX file", filename);
  321.       return -1;
  322.     }
  323.  
  324.   offset_x = qtohs (pcx_header.x1);
  325.   offset_y = qtohs (pcx_header.y1);
  326.   width = qtohs (pcx_header.x2) - offset_x + 1;
  327.   height = qtohs (pcx_header.y2) - offset_y + 1;
  328.  
  329.   if (pcx_header.planes == 3 && pcx_header.bpp == 8)
  330.     {
  331.       image= gimp_image_new (width, height, GIMP_RGB);
  332.       layer= gimp_layer_new (image, _("Background"), width, height,
  333.                  GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE);
  334.     }
  335.   else
  336.     {
  337.       image= gimp_image_new (width, height, GIMP_INDEXED);
  338.       layer= gimp_layer_new (image, _("Background"), width, height,
  339.                  GIMP_INDEXED_IMAGE, 100, GIMP_NORMAL_MODE);
  340.     }
  341.   gimp_image_set_filename (image, filename);
  342.   gimp_image_add_layer (image, layer, 0);
  343.   gimp_layer_set_offsets (layer, offset_x, offset_y);
  344.   drawable = gimp_drawable_get (layer);
  345.  
  346.   if (pcx_header.planes == 1 && pcx_header.bpp == 1)
  347.     {
  348.       dest = (guchar *) g_malloc (width * height);
  349.       load_1 (fd, width, height, dest, qtohs (pcx_header.bytesperline));
  350.       gimp_image_set_cmap (image, mono, 2);
  351.     }
  352.   else if (pcx_header.planes == 4 && pcx_header.bpp == 1)
  353.     {
  354.       dest = (guchar *) g_malloc (width * height);
  355.       load_4(fd, width, height, dest, qtohs (pcx_header.bytesperline));
  356.       gimp_image_set_cmap (image, pcx_header.colormap, 16);
  357.     }
  358.   else if (pcx_header.planes == 1 && pcx_header.bpp == 8)
  359.     {
  360.       dest = (guchar *) g_malloc (width * height);
  361.       load_8(fd, width, height, dest, qtohs (pcx_header.bytesperline));
  362.       fseek(fd, -768L, SEEK_END);
  363.       fread(cmap, 768, 1, fd);
  364.       gimp_image_set_cmap (image, cmap, 256);
  365.     }
  366.   else if (pcx_header.planes == 3 && pcx_header.bpp == 8)
  367.     {
  368.       dest = (guchar *) g_malloc (width * height * 3);
  369.       load_24(fd, width, height, dest, qtohs (pcx_header.bytesperline));
  370.     }
  371.   else
  372.     {
  373.       g_message ("Unusual PCX flavour, giving up");
  374.       return -1;
  375.     }
  376.  
  377.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, TRUE, FALSE);
  378.   gimp_pixel_rgn_set_rect (&pixel_rgn, dest, 0, 0, width, height);
  379.  
  380.   g_free (dest);
  381.  
  382.   gimp_drawable_flush (drawable);
  383.   gimp_drawable_detach (drawable);
  384.  
  385.   return image;
  386. }
  387.  
  388. static void
  389. load_8 (FILE  *fp, 
  390.     gint   width, 
  391.     gint   height, 
  392.     gchar *buffer, 
  393.     gint   bytes) 
  394. {
  395.   int row;
  396.   guchar *line;
  397.   line = (guchar *) g_malloc (bytes);
  398.  
  399.   for (row = 0; row < height; buffer += width, ++row) 
  400.     {
  401.       readline (fp, line, bytes);
  402.       memcpy (buffer, line, width);
  403.       gimp_progress_update ((double) row / (double) height);
  404.     }
  405.  
  406.   g_free (line);
  407. }
  408.  
  409. static void
  410. load_24 (FILE  *fp, 
  411.      gint   width, 
  412.      gint   height, 
  413.      gchar *buffer, 
  414.      gint   bytes) 
  415. {
  416.   int x, y, c;
  417.   guchar *line;
  418.   line = (guchar *) g_malloc (bytes * 3);
  419.  
  420.   for (y = 0; y < height; buffer += width * 3, ++y) 
  421.     {
  422.       for (c = 0; c < 3; ++c) 
  423.     {
  424.       readline (fp, line, bytes);
  425.       for (x = 0; x < width; ++x) 
  426.         {
  427.           buffer[x * 3 + c] = line[x];
  428.         }
  429.     }
  430.       gimp_progress_update ((double) y / (double) height);
  431.     }
  432.  
  433.   g_free (line);
  434. }
  435.  
  436. static void
  437. load_1 (FILE  *fp, 
  438.     gint   width, 
  439.     gint   height, 
  440.     gchar *buffer, 
  441.     gint   bytes) 
  442. {
  443.   int x, y;
  444.   guchar *line;
  445.   line = (guchar *) g_malloc (bytes);
  446.  
  447.   for (y = 0; y < height; buffer += width, ++y) 
  448.     {
  449.       readline (fp, line, bytes);
  450.       for (x = 0; x < width; ++x) 
  451.     {
  452.       if (line[x / 8] & (128 >> (x % 8)))
  453.         buffer[x] = 1;
  454.       else
  455.         buffer[x] = 0;
  456.     }
  457.       gimp_progress_update ((double) y / (double) height);
  458.     }
  459.  
  460.   g_free (line);
  461. }
  462.  
  463. static void
  464. load_4 (FILE  *fp, 
  465.     gint   width, 
  466.     gint   height, 
  467.     gchar *buffer, 
  468.     gint   bytes) 
  469. {
  470.   int x, y, c;
  471.   guchar *line;
  472.   line= (guchar *) g_malloc (bytes);
  473.  
  474.   for (y = 0; y < height; buffer += width, ++y) 
  475.     {
  476.       for (x = 0; x < width; ++x) buffer[x] = 0;
  477.       for (c = 0; c < 4; ++c) 
  478.     {
  479.       readline(fp, line, bytes);
  480.       for (x = 0; x < width; ++x) 
  481.         {
  482.           if (line[x / 8] & (128 >> (x % 8)))
  483.         buffer[x] += (1 << c);
  484.         }
  485.     }
  486.       gimp_progress_update ((double) y / (double) height);
  487.     }
  488.  
  489.   g_free (line);
  490. }
  491.  
  492. static void
  493. readline (FILE   *fp, 
  494.       guchar *buffer, 
  495.       gint    bytes) 
  496. {
  497.   static guchar count = 0, value = 0;
  498.  
  499.   if (pcx_header.compression) 
  500.     {
  501.       while (bytes--) 
  502.     {
  503.       if (count == 0) 
  504.         {
  505.           value = fgetc (fp);
  506.           if (value < 0xc0) 
  507.         {
  508.           count = 1;
  509.         } 
  510.           else 
  511.         {
  512.           count = value - 0xc0;
  513.           value = fgetc (fp);
  514.         }
  515.         }
  516.       count--;
  517.       *(buffer++) = value;
  518.     }
  519.     } 
  520.   else 
  521.     {
  522.       fread (buffer, bytes, 1, fp);
  523.     }
  524. }
  525.  
  526. static gint
  527. save_image (gchar   *filename, 
  528.         gint32  image, 
  529.         gint32  layer) 
  530. {
  531.   FILE *fp;
  532.   GimpPixelRgn pixel_rgn;
  533.   GimpDrawable *drawable;
  534.   GimpImageType drawable_type;
  535.   guchar *cmap= 0, *pixels;
  536.   gint offset_x, offset_y, width, height;
  537.   gchar *message;
  538.   int colors, i;
  539.  
  540.   drawable = gimp_drawable_get (layer);
  541.   drawable_type = gimp_drawable_type (layer);
  542.   gimp_drawable_offsets (layer, &offset_x, &offset_y);
  543.   width = drawable->width;
  544.   height = drawable->height;
  545.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, FALSE, FALSE);
  546.  
  547.   message = g_strdup_printf (_("Saving %s:"), filename);
  548.   gimp_progress_init (message);
  549.   g_free (message);
  550.  
  551.   pcx_header.manufacturer = 0x0a;
  552.   pcx_header.version = 5;
  553.   pcx_header.compression = 1;
  554.  
  555.   switch (drawable_type) 
  556.     {
  557.     case GIMP_INDEXED_IMAGE:
  558.       cmap = gimp_image_get_cmap (image, &colors);
  559.       pcx_header.bpp = 8;
  560.       pcx_header.bytesperline = htoqs (width);
  561.       pcx_header.planes = 1;
  562.       pcx_header.color = htoqs (1);
  563.       break;
  564.  
  565.     case GIMP_RGB_IMAGE:
  566.       pcx_header.bpp = 8;
  567.       pcx_header.planes = 3;
  568.       pcx_header.color = htoqs (1);
  569.       pcx_header.bytesperline = htoqs (width);
  570.       break;
  571.  
  572.     case GIMP_GRAY_IMAGE:
  573.       pcx_header.bpp = 8;
  574.       pcx_header.planes = 1;
  575.       pcx_header.color = htoqs (2);
  576.       pcx_header.bytesperline = htoqs (width);
  577.       break;
  578.  
  579.     default:
  580.       g_message ("PCX Can't save this image type\nFlatten your image");
  581.       return FALSE;
  582.       break;
  583.   }
  584.  
  585.   if ((fp = fopen(filename, "wb")) == NULL) 
  586.     {
  587.       g_message ("PCX Can't open \n%s", filename);
  588.       return FALSE;
  589.     }
  590.  
  591.   pixels = (guchar *) g_malloc (width * height * pcx_header.planes);
  592.   gimp_pixel_rgn_get_rect (&pixel_rgn, pixels, 0, 0, width, height);
  593.  
  594.   pcx_header.x1 = htoqs (offset_x);
  595.   pcx_header.y1 = htoqs (offset_y);
  596.   pcx_header.x2 = htoqs (offset_x + width - 1);
  597.   pcx_header.y2 = htoqs (offset_y + height - 1);
  598.  
  599.   pcx_header.hdpi = htoqs (300);
  600.   pcx_header.vdpi = htoqs (300);
  601.   pcx_header.reserved = 0;
  602.  
  603.   fwrite (&pcx_header, 128, 1, fp);
  604.  
  605.   switch (drawable_type) 
  606.     {
  607.     case GIMP_INDEXED_IMAGE:
  608.       save_8 (fp, width, height, pixels);
  609.       fputc (0x0c, fp);
  610.       fwrite (cmap, colors, 3, fp);
  611.       for (i = colors; i < 256; i++) 
  612.     {
  613.       fputc (0, fp); fputc (0, fp); fputc (0, fp);
  614.     }
  615.       break;
  616.     case GIMP_RGB_IMAGE:
  617.       save_24 (fp, width, height, pixels);
  618.       break;
  619.     case GIMP_GRAY_IMAGE:
  620.       save_8 (fp, width, height, pixels);
  621.       fputc (0x0c, fp);
  622.       for (i = 0; i < 256; i++) 
  623.     {
  624.       fputc ((guchar) i, fp); fputc ((guchar) i, fp); fputc ((guchar) i, fp);
  625.     }
  626.       break;
  627.     default:
  628.       g_message ("Can't save this image as PCX\nFlatten your image");
  629.       return FALSE;
  630.       break;
  631.     }
  632.  
  633.   gimp_drawable_detach (drawable);
  634.   g_free (pixels);
  635.  
  636.   fclose (fp);
  637.   return TRUE;
  638. }
  639.  
  640. static void
  641. save_8 (FILE   *fp, 
  642.     gint    width, 
  643.     gint    height, 
  644.     guchar *buffer) 
  645. {
  646.   int row;
  647.  
  648.   for (row = 0; row < height; ++row) 
  649.     {
  650.       writeline (fp, buffer, width);
  651.       buffer += width;
  652.       gimp_progress_update ((double) row / (double) height);
  653.     }
  654. }
  655.  
  656. static void
  657. save_24 (FILE   *fp, 
  658.      gint    width, 
  659.      gint    height, 
  660.      guchar *buffer) 
  661. {
  662.   int x, y, c;
  663.   guchar *line;
  664.   line = (guchar *) g_malloc (width);
  665.  
  666.   for (y = 0; y < height; ++y) 
  667.     {
  668.       for (c = 0; c < 3; ++c) 
  669.     {
  670.       for (x = 0; x < width; ++x) 
  671.         {
  672.           line[x] = buffer[(3*x) + c];
  673.         }
  674.       writeline (fp, line, width);
  675.     }
  676.       buffer += width * 3;
  677.     gimp_progress_update ((double) y / (double) height);
  678.     }
  679.   g_free (line);
  680. }
  681.  
  682. static void
  683. writeline (FILE   *fp, 
  684.        guchar *buffer, 
  685.        gint    bytes) 
  686. {
  687.   guchar value, count;
  688.   guchar *finish = buffer+ bytes;
  689.  
  690.   while (buffer < finish) 
  691.     {
  692.       value = *(buffer++);
  693.       count = 1;
  694.       
  695.       while (buffer < finish && count < 63 && *buffer == value) 
  696.     {
  697.       count++; buffer++;
  698.     }
  699.  
  700.       if (value < 0xc0 && count == 1) 
  701.     {
  702.       fputc (value, fp);
  703.     } 
  704.       else 
  705.     {
  706.       fputc (0xc0 + count, fp);
  707.       fputc (value, fp);
  708.     }
  709.     }
  710. }
  711.