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 / pix.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-22  |  16.6 KB  |  653 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * Alias|Wavefront pix/matte image reading and writing code 
  4.  * Copyright (C) 1997 Mike Taylor
  5.  * (email: mtaylor@aw.sgi.com, WWW: http://reality.sgi.com/mtaylor)
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  */
  22.  
  23. /* This plug-in was written using the online documentation from 
  24.  * Alias|Wavefront Inc's PowerAnimator product.
  25.  *
  26.  * Bug reports or suggestions should be e-mailed to mtaylor@aw.sgi.com
  27.  */
  28.  
  29. /* Event history:
  30.  * V 1.0, MT, 02-Jul-97: initial version of plug-in
  31.  * V 1.1, MT, 04-Dec-97: added .als file extension 
  32.  */
  33.  
  34. /* Features
  35.  *  - loads and saves
  36.  *    - 24-bit (.pix) 
  37.  *    - 8-bit (.matte, .alpha, or .mask) images
  38.  *
  39.  * NOTE: pix and matte files do not support alpha channels or indexed
  40.  *       colour, so neither does this plug-in
  41.  */
  42.  
  43. static char ident[] = "@(#) GIMP Alias|Wavefront pix image file-plugin v1.0  24-jun-97";
  44.  
  45. #include "config.h"
  46.  
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <stdio.h>
  50. #include <sys/types.h>
  51. #include <sys/stat.h>
  52.  
  53. #include <gtk/gtk.h>
  54.  
  55. #include <libgimp/gimp.h>
  56. #include <libgimp/gimpui.h>
  57.  
  58. #include "libgimp/stdplugins-intl.h"
  59.  
  60.  
  61. /* #define PIX_DEBUG */
  62.  
  63. #ifdef PIX_DEBUG
  64. #    define PIX_DEBUG_PRINT(a,b) fprintf(stderr,a,b)
  65. #else
  66. #    define PIX_DEBUG_PRINT(a,b) 
  67. #endif
  68.  
  69. /**************
  70.  * Prototypes *
  71.  **************/
  72.  
  73. /* Standard Plug-in Functions */
  74.  
  75. static void     query     (void);
  76. static void     run       (gchar    *name,
  77.                gint      nparams,
  78.                GimpParam   *param, 
  79.                gint     *nreturn_vals,
  80.                GimpParam  **return_vals);
  81.  
  82. /* Local Helper Functions */ 
  83.  
  84. static gint32   load_image (gchar   *filename);
  85. static gint     save_image (gchar   *filename,
  86.                 gint32   image_ID,
  87.                 gint32   drawable_ID);
  88.  
  89. static guint16  get_short  (FILE    *file);
  90. static void     put_short  (guint16  value,
  91.                 FILE    *file);
  92.  
  93. /******************
  94.  * Implementation *
  95.  ******************/
  96.  
  97. GimpPlugInInfo PLUG_IN_INFO =
  98. {
  99.   NULL,  /* init_proc  */
  100.   NULL,  /* quit_proc  */
  101.   query, /* query_proc */
  102.   run,   /* run_proc   */
  103. };
  104.  
  105. MAIN ()
  106.  
  107. static void
  108. query (void)
  109. {
  110.   /*
  111.    * Description:
  112.    *     Register the services provided by this plug-in 
  113.    */
  114.   static GimpParamDef load_args[] = 
  115.   {
  116.     { GIMP_PDB_INT32,  "run_mode",      "Interactive, non-interactive" },
  117.     { GIMP_PDB_STRING, "filename",      "The name of the file to load" },
  118.     { GIMP_PDB_STRING, "raw_filename",   "The name entered" }
  119.   };
  120.   static GimpParamDef load_return_vals[] = 
  121.   {
  122.     { GIMP_PDB_IMAGE, "image", "Output image" }
  123.   };
  124.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  125.   static gint nload_return_vals = (sizeof (load_return_vals) /
  126.                    sizeof (load_return_vals[0]));
  127.  
  128.   static GimpParamDef save_args[] = 
  129.   {
  130.     { GIMP_PDB_INT32,    "run_mode",     "Interactive, non-interactive" },
  131.     { GIMP_PDB_IMAGE,    "image",        "Input image" },
  132.     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save" },
  133.     { GIMP_PDB_STRING,   "filename",     "The name of the file to save the image in" },
  134.     { GIMP_PDB_STRING,   "raw_filename", "The name of the file to save the image in" }
  135.   };
  136.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  137.  
  138.   gimp_install_procedure ("file_pix_load",
  139.               "loads files of the PIX file format",
  140.               "loads files of the PIX file format",
  141.               "Michael Taylor",
  142.               "Michael Taylor",
  143.               "1997",
  144.               "<Load>/PIX",
  145.               NULL,
  146.               GIMP_PLUGIN,
  147.               nload_args, nload_return_vals,
  148.               load_args, load_return_vals);
  149.  
  150.   gimp_install_procedure ("file_pix_save",
  151.                           "save file in the Alias|Wavefront pix/matte file format",
  152.                           "save file in the Alias|Wavefront pix/matte file format",
  153.                           "Michael Taylor",
  154.                           "Michael Taylor",
  155.                           "1997",
  156.                           "<Save>/PIX",
  157.                           "RGB*, GRAY*",
  158.                           GIMP_PLUGIN,
  159.                           nsave_args, 0,
  160.                           save_args, NULL);
  161.  
  162.   gimp_register_load_handler ("file_pix_load",
  163.                   "pix,matte,mask,alpha,als",
  164.                   "");
  165.   gimp_register_save_handler ("file_pix_save",
  166.                   "pix,matte,mask,alpha,als",
  167.                   "");
  168. }
  169.  
  170. static void 
  171. run (gchar   *name, 
  172.      gint     nparams, 
  173.      GimpParam  *param, 
  174.      gint    *nreturn_vals,
  175.      GimpParam **return_vals)
  176. {
  177.   /* 
  178.    *  Description:
  179.    *      perform registered plug-in function 
  180.    *
  181.    *  Arguments:
  182.    *      name         - name of the function to perform
  183.    *      nparams      - number of parameters passed to the function
  184.    *      param        - parameters passed to the function
  185.    *      nreturn_vals - number of parameters returned by the function
  186.    *      return_vals  - parameters returned by the function
  187.    */
  188.   static GimpParam values[2];
  189.   GimpRunModeType  run_mode;
  190.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  191.   gint32        image_ID;
  192.   gint32        drawable_ID;
  193.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  194.  
  195.   run_mode = param[0].data.d_int32;
  196.  
  197.   *nreturn_vals = 1;
  198.   *return_vals  = values;
  199.   values[0].type          = GIMP_PDB_STATUS;
  200.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  201.  
  202.   if (strcmp (name, "file_pix_load") == 0) 
  203.     {
  204.       INIT_I18N();
  205.       /* Perform the image load */
  206.       image_ID = load_image (param[1].data.d_string);
  207.  
  208.       if (image_ID != -1) 
  209.     {
  210.       /* The image load was successful */
  211.       *nreturn_vals = 2;
  212.       values[1].type         = GIMP_PDB_IMAGE;
  213.       values[1].data.d_image = image_ID;
  214.     } 
  215.       else 
  216.     {
  217.       /* The image load falied */
  218.       status = GIMP_PDB_EXECUTION_ERROR;
  219.     }
  220.     } 
  221.   else if (strcmp (name, "file_pix_save") == 0) 
  222.     {
  223.       image_ID    = param[1].data.d_int32;
  224.       drawable_ID = param[2].data.d_int32;
  225.  
  226.       /*  eventually export the image */ 
  227.       switch (run_mode)
  228.     {
  229.     case GIMP_RUN_INTERACTIVE:
  230.     case GIMP_RUN_WITH_LAST_VALS:
  231.       INIT_I18N_UI();
  232.       gimp_ui_init ("pix", FALSE);
  233.       export = gimp_export_image (&image_ID, &drawable_ID, "PIX", 
  234.                       (GIMP_EXPORT_CAN_HANDLE_RGB |
  235.                        GIMP_EXPORT_CAN_HANDLE_GRAY));
  236.       if (export == GIMP_EXPORT_CANCEL)
  237.         {
  238.           values[0].data.d_status = GIMP_PDB_CANCEL;
  239.           return;
  240.         }
  241.       break;
  242.     default:
  243.       INIT_I18N();
  244.       break;
  245.     }
  246.  
  247.       if (status == GIMP_PDB_SUCCESS) 
  248.     {
  249.       if (! save_image (param[3].data.d_string, image_ID, drawable_ID))
  250.         {
  251.           status = GIMP_PDB_EXECUTION_ERROR;
  252.         }
  253.     }
  254.  
  255.       if (export == GIMP_EXPORT_EXPORT)
  256.     gimp_image_delete (image_ID);
  257.     }
  258.   else
  259.     {
  260.       status = GIMP_PDB_CALLING_ERROR;
  261.     }
  262.  
  263.   values[0].data.d_status = status;  
  264. }
  265.  
  266.     
  267. static guint16
  268. get_short (FILE *file)
  269. {
  270.   /* 
  271.    * Description:
  272.    *     Reads a 16-bit integer from a file in such a way that the machine's
  273.    *     bit ordering should not matter 
  274.    */
  275.   guchar buf[2];
  276.  
  277.   fread (buf, 2, 1, file);
  278.   return (buf[0] << 8) + (buf[1] << 0);
  279. }
  280.     
  281. static void
  282. put_short (guint16  value, 
  283.        FILE    *file)
  284. {
  285.   /* 
  286.    * Description:
  287.    *     Reads a 16-bit integer from a file in such a way that the machine's
  288.    *     bit ordering should not matter 
  289.    */
  290.   guchar buf[2];
  291.   buf[0] = (guchar) (value >> 8);
  292.   buf[1] = (guchar) (value % 256);
  293.  
  294.   fwrite (buf, 2, 1, file);
  295. }
  296.  
  297. static gint32
  298. load_image (gchar *filename)
  299. {
  300.   /*
  301.    *  Description:
  302.    *      load the given image into gimp
  303.    * 
  304.    *  Arguments:
  305.    *      filename      - name on the file to read
  306.    *
  307.    *  Return Value:
  308.    *      Image id for the loaded image
  309.    *      
  310.    */
  311.   gint       i, j, tile_height, row;    
  312.   FILE      *file = NULL;
  313.   gchar     *progMessage = ident;  /*  only to suppress compiler warnings  */
  314.   guchar    *dest; 
  315.   guchar    *dest_base;
  316.   GimpDrawable *drawable;
  317.   gint32     image_ID;
  318.   gint32     layer_ID;
  319.   GimpPixelRgn  pixel_rgn;
  320.   gushort    width, height, depth;
  321.  
  322.   GimpImageBaseType  imgtype;
  323.   GimpImageType gdtype;
  324.   
  325.   /* Set up progress display */
  326.   progMessage = g_strdup_printf (_("Loading %s:"), filename);
  327.   gimp_progress_init (progMessage);
  328.   free (progMessage);
  329.  
  330.   PIX_DEBUG_PRINT ("Opening file: %s\n", filename);
  331.  
  332.   /* Open the file */
  333.   file = fopen (filename, "r");
  334.   if (NULL == file)
  335.     {
  336.       return -1;
  337.     }
  338.   
  339.   /* Read header information */
  340.   width  = get_short (file);
  341.   height = get_short (file);
  342.   get_short (file); /* Discard obsolete fields */
  343.   get_short (file); /* Discard obsolete fields */
  344.   depth  = get_short (file);
  345.  
  346.   PIX_DEBUG_PRINT ("Width %hu\n", width);
  347.   PIX_DEBUG_PRINT ("Height %hu\n", height);
  348.  
  349.   if (depth == 8)
  350.     {
  351.       /* Loading a matte file */
  352.       imgtype = GIMP_GRAY;
  353.       gdtype = GIMP_GRAY_IMAGE;
  354.     }
  355.   else if (depth == 24)
  356.     {
  357.       /* Loading an RGB file */
  358.       imgtype = GIMP_RGB;
  359.       gdtype = GIMP_RGB_IMAGE;
  360.     }
  361.   else
  362.     {
  363.       /* Header is invalid */
  364.       fclose (file);
  365.       return -1;
  366.     }
  367.  
  368.   image_ID = gimp_image_new (width, height, imgtype);
  369.   gimp_image_set_filename (image_ID, filename);
  370.   layer_ID = gimp_layer_new (image_ID, _("Background"),
  371.                  width,
  372.                  height,
  373.                  gdtype, 100, GIMP_NORMAL_MODE);
  374.   gimp_image_add_layer (image_ID, layer_ID, 0);
  375.   drawable = gimp_drawable_get (layer_ID);
  376.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, 
  377.                drawable->height, TRUE, FALSE);
  378.  
  379.   tile_height = gimp_tile_height ();   
  380.  
  381.   if (depth == 24)
  382.     {
  383.       /* Read a 24-bit Pix image */
  384.       guchar record[4];
  385.       gint   readlen;
  386.       tile_height = gimp_tile_height ();
  387.  
  388.       dest_base = dest = g_new (guchar, 3 * width * tile_height); 
  389.  
  390.       for (i = 0; i < height;)
  391.     {
  392.       for (dest = dest_base, row = 0;
  393.            row < tile_height && i < height;
  394.            i += 1, row += 1)
  395.         {
  396.           guchar count;
  397.  
  398.           /* Read a row of the image */
  399.           j = 0;
  400.           while (j < width)
  401.         {
  402.           readlen = fread (record, 1, 4, file);
  403.           if (readlen < 4)
  404.             break;
  405.  
  406.           for (count = 0; count < record[0]; ++count)
  407.             {
  408.               dest[0]   = record[3];
  409.               dest[1]   = record[2];
  410.               dest[2]   = record[1];
  411.               dest += 3;
  412.               j++;
  413.               if (j >= width)
  414.             break;
  415.             }
  416.         }
  417.         }
  418.       gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, 
  419.                    width, row);
  420.       gimp_progress_update ((double) i / (double) height);
  421.     }
  422.  
  423.       free (dest_base);
  424.     }
  425.   else
  426.     {
  427.       /* Read an 8-bit Matte image */
  428.       guchar record[2];
  429.       gint   readlen;  
  430.  
  431.       dest_base = dest = g_new (guchar, width * tile_height); 
  432.       
  433.       for (i = 0; i < height;) 
  434.     {
  435.       for (dest = dest_base, row = 0; 
  436.            row < tile_height && i < height;
  437.            i += 1, row += 1)
  438.         {
  439.           guchar count;
  440.  
  441.           /* Read a row of the image */
  442.           j = 0;
  443.           while (j < width)
  444.         {
  445.           readlen = fread(record, 1, 2, file);
  446.           if (readlen < 2)
  447.             break;
  448.  
  449.           for (count = 0; count < record[0]; ++count)
  450.             {
  451.               dest[j]   = record[1];
  452.               j++;
  453.               if (j >= width)
  454.             break;
  455.             }
  456.         }
  457.           dest += width;
  458.         }
  459.       gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, 
  460.                    width, row);
  461.       gimp_progress_update ((double) i / (double) height);
  462.     }
  463.       g_free (dest_base);
  464.     }
  465.   
  466.   gimp_drawable_flush (drawable);
  467.   gimp_drawable_detach (drawable);
  468.   
  469.   fclose (file);
  470.   
  471.   return image_ID;
  472. }
  473.  
  474. static gint 
  475. save_image (gchar  *filename,  
  476.         gint32  image_ID, 
  477.         gint32  drawable_ID)
  478. {
  479. /* 
  480.  *  Description:
  481.  *      save the given file out as an alias pix or matte file
  482.  * 
  483.  *  Arguments: 
  484.  *      filename    - name of file to save to
  485.  *      image_ID    - ID of image to save
  486.  *      drawable_ID - current drawable
  487.  */
  488.   gint       depth, i, j, row, tile_height, writelen, rectHeight;
  489.   /* gboolean   savingAlpha = FALSE; */
  490.   gboolean   savingColor = TRUE;
  491.   guchar    *src; 
  492.   guchar    *src_base;
  493.   gchar     *progMessage;
  494.   GimpDrawable *drawable;
  495.   GimpPixelRgn  pixel_rgn;
  496.   FILE      *file;
  497.  
  498.   /* Get info about image */
  499.   drawable = gimp_drawable_get (drawable_ID);
  500.   
  501.   gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width,
  502.                drawable->height, FALSE, FALSE);
  503.  
  504.   switch (gimp_drawable_type(drawable_ID))
  505.     {
  506.     case GIMP_GRAY_IMAGE:
  507.       savingColor = FALSE; 
  508.       depth = 1;
  509.       break;
  510.     case GIMP_GRAYA_IMAGE:
  511.       savingColor = FALSE;
  512.       depth = 2;
  513.       break;
  514.     case GIMP_RGB_IMAGE:
  515.       savingColor = TRUE;
  516.       depth = 3;
  517.       break;
  518.     case GIMP_RGBA_IMAGE:
  519.       savingColor = TRUE;
  520.       depth = 4;
  521.       break;
  522.     default:
  523.       return FALSE;
  524.     };
  525.  
  526.   /* Open the output file. */
  527.   file = fopen (filename, "wb");
  528.   if (!file)
  529.     return FALSE;
  530.  
  531.   /* Set up progress display */
  532.   progMessage = g_strdup_printf (_("Saving %s:"), filename);
  533.   gimp_progress_init (progMessage);
  534.   free (progMessage);
  535.  
  536.   /* Write the image header */
  537.   PIX_DEBUG_PRINT ("Width %hu\n", drawable->width);
  538.   PIX_DEBUG_PRINT ("Height %hu\n", drawable->height);
  539.   put_short (drawable->width, file);
  540.   put_short (drawable->height, file);
  541.   put_short (0, file);
  542.   put_short (0, file);
  543.   if (savingColor)
  544.     {
  545.       put_short (24, file);
  546.     }
  547.   else
  548.     {
  549.       put_short (8, file);
  550.     }
  551.  
  552.   tile_height = gimp_tile_height ();
  553.   src_base    = g_new (guchar, tile_height * drawable->width * depth);
  554.  
  555.   if (savingColor)
  556.     {
  557.       /* Writing a 24-bit Pix image */
  558.       guchar record[4];
  559.  
  560.       for (i = 0; i < drawable->height;)
  561.     {
  562.       rectHeight = (tile_height < (drawable->height - i - 1)) ?
  563.         tile_height : (drawable->height - i - 1);
  564.       gimp_pixel_rgn_get_rect (&pixel_rgn, src_base, 0, i, 
  565.                    drawable->width, rectHeight);
  566.  
  567.       for (src = src_base, row = 0;
  568.            row < tile_height && i < drawable->height;
  569.            i += 1, row += 1)
  570.         {
  571.           /* Write a row of the image */
  572.           record[0] = 1;
  573.           record[3] = src[0];
  574.           record[2] = src[1];
  575.           record[1] = src[2];
  576.           src += depth;
  577.           for (j = 1; j < drawable->width; ++j)
  578.         {
  579.           if ((record[3] != src[0]) ||
  580.                (record[2] != src[1]) ||
  581.                (record[1] != src[2]) ||
  582.                (record[0] == 255))
  583.             {
  584.               /* Write current RLE record and start a new one */
  585.  
  586.               writelen = fwrite (record, 1, 4, file);
  587.               record[0] = 1;
  588.               record[3] = src[0];
  589.               record[2] = src[1];
  590.               record[1] = src[2];
  591.             }
  592.           else
  593.             {
  594.               /* increment run length in current record */
  595.               record[0]++;
  596.             }
  597.           src += depth;
  598.         }
  599.           /* Write last record in row */
  600.           writelen = fwrite (record, 1, 4, file);
  601.         }
  602.       gimp_progress_update ((double) i / (double) drawable->height);
  603.     }
  604.     }
  605.   else
  606.     {
  607.       /* Writing a 8-bit Matte (Mask) image */
  608.       guchar record[2];
  609.  
  610.       for (i = 0; i < drawable->height;)
  611.     {
  612.       rectHeight = (tile_height < (drawable->height - i - 1)) ?
  613.         tile_height : (drawable->height - i - 1);
  614.       gimp_pixel_rgn_get_rect (&pixel_rgn, src_base, 0, i, 
  615.                    drawable->width, rectHeight);
  616.  
  617.       for (src = src_base, row = 0;
  618.            row < tile_height && i < drawable->height;
  619.            i += 1, row += 1)
  620.         {
  621.           /* Write a row of the image */
  622.           record[0] = 1;
  623.           record[1] = src[0];
  624.           src += depth;
  625.           for (j = 1; j < drawable->width; ++j)
  626.         {
  627.           if ((record[1] != src[0]) || (record[0] == 255)) 
  628.             {
  629.               /* Write current RLE record and start a new one */
  630.               writelen = fwrite (record, 1, 2, file);
  631.               record[0] = 1;
  632.               record[1] = src[0];
  633.             }
  634.           else
  635.             {
  636.               /* increment run length in current record */
  637.               record[0] ++;
  638.             }
  639.           src += depth;
  640.         }
  641.           /* Write last record in row */
  642.           writelen = fwrite (record, 1, 2, file);
  643.         }
  644.       gimp_progress_update ((double) i / (double) drawable->height);
  645.     }
  646.     }
  647.  
  648.   g_free (src_base);
  649.   
  650.   fclose (file);
  651.   return TRUE;
  652. }
  653.