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 / hrz.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  13.6 KB  |  549 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * HRZ reading and writing code Copyright (C) 1996 Albert Cahalan
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. /* $Id: hrz.c,v 1.20 2000/12/17 20:07:15 tml Exp $ */
  21.  
  22. /*
  23.  * Albert Cahalan <acahalan at cs.uml.edu>, 1997  -  Initial HRZ support.
  24.  * Based on PNM code by Erik Nygren (nygren@mit.edu)
  25.  *
  26.  * Bug reports are wanted. I'd like to remove useless code.
  27.  *
  28.  * The HRZ file is always 256x240 with RGB values from 0 to 63.
  29.  * No compression, no header, just the raw RGB data.
  30.  * It is (was?) used for amatuer radio slow-scan TV.
  31.  * That makes the size 256*240*3 = 184320 bytes.
  32.  */
  33.  
  34. #include "config.h"
  35.  
  36. #include <setjmp.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #ifdef HAVE_UNISTD_H
  41. #include <unistd.h>
  42. #endif
  43. #include <ctype.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #ifdef HAVE_MMAP
  48. #include <sys/mman.h>
  49. #endif
  50.  
  51. #ifdef G_OS_WIN32
  52. #include <io.h>
  53. #endif
  54.  
  55. #ifndef _O_BINARY
  56. #define _O_BINARY 0
  57. #endif
  58.  
  59. #include <libgimp/gimp.h>
  60. #include <libgimp/gimpui.h>
  61.  
  62. #include "libgimp/stdplugins-intl.h"
  63.  
  64.  
  65. /* Declare local data types
  66.  */
  67.  
  68. typedef struct
  69. {
  70.   gint  run;  /*  run  */
  71. } HRZSaveInterface;
  72.  
  73.  
  74. /* Declare some local functions.
  75.  */
  76. static void   query       (void);
  77. static void   run         (gchar   *name,
  78.                gint     nparams,
  79.                GimpParam  *param,
  80.                gint    *nreturn_vals,
  81.                GimpParam **return_vals);
  82. static gint32 load_image  (gchar   *filename);
  83. static gint   save_image  (gchar   *filename,
  84.                gint32   image_ID,
  85.                gint32   drawable_ID);
  86.  
  87. /*
  88. static gint   save_dialog      (void);
  89. static void   save_ok_callback (GtkWidget *widget,
  90.                 gpointer   data);
  91. */
  92.  
  93. #define hrzscanner_eof(s) ((s)->eof)
  94. #define hrzscanner_fp(s)  ((s)->fp)
  95.  
  96. /* Checks for a fatal error */
  97. #define CHECK_FOR_ERROR(predicate, jmpbuf, errmsg) \
  98.         if ((predicate)) \
  99.         { /*gimp_message((errmsg));*/ longjmp((jmpbuf),1); }
  100.  
  101. GimpPlugInInfo PLUG_IN_INFO =
  102. {
  103.   NULL,  /* init_proc  */
  104.   NULL,  /* quit_proc  */
  105.   query, /* query_proc */
  106.   run,   /* run_proc   */
  107. };
  108.  
  109. /*
  110. static HRZSaveInterface psint =
  111. {
  112.   FALSE     / * run * /
  113. };
  114. */
  115.  
  116.  
  117. MAIN ()
  118.  
  119. static void
  120. query (void)
  121. {
  122.   static GimpParamDef load_args[] =
  123.   {
  124.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  125.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  126.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to load" }
  127.   };
  128.   static GimpParamDef load_return_vals[] =
  129.   {
  130.     { GIMP_PDB_IMAGE, "image", "Output image" }
  131.   };
  132.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  133.   static gint nload_return_vals = (sizeof (load_return_vals) /
  134.                    sizeof (load_return_vals[0]));
  135.  
  136.   static GimpParamDef save_args[] =
  137.   {
  138.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  139.     { GIMP_PDB_IMAGE, "image", "Input image" },
  140.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  141.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  142.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" }
  143.   };
  144.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  145.  
  146.   gimp_install_procedure ("file_hrz_load",
  147.                           "loads files of the hrz file format",
  148.                           "FIXME: write help for hrz_load",
  149.                           "Albert Cahalan",
  150.                           "Albert Cahalan",
  151.                           "1997",
  152.                           "<Load>/HRZ",
  153.               NULL,
  154.                           GIMP_PLUGIN,
  155.                           nload_args, nload_return_vals,
  156.                           load_args, load_return_vals);
  157.  
  158.   gimp_install_procedure ("file_hrz_save",
  159.                           "saves files in the hrz file format",
  160.                           "HRZ saving handles all image types except those with alpha channels.",
  161.                           "Albert Cahalan",
  162.                           "Albert Cahalan",
  163.                           "1997",
  164.                           "<Save>/HRZ",
  165.               "RGB, GRAY",
  166.                           GIMP_PLUGIN,
  167.                           nsave_args, 0,
  168.                           save_args, NULL);
  169.  
  170.   gimp_register_magic_load_handler ("file_hrz_load",
  171.                     "hrz",
  172.                     "",
  173.                     "0,size,184320");
  174.   gimp_register_save_handler       ("file_hrz_save",
  175.                     "hrz",
  176.                     "");
  177. }
  178.  
  179. static void
  180. run (gchar   *name,
  181.      gint     nparams,
  182.      GimpParam  *param,
  183.      gint    *nreturn_vals,
  184.      GimpParam **return_vals)
  185. {
  186.   static GimpParam values[2];
  187.   GimpRunModeType  run_mode;
  188.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  189.   gint32        image_ID;
  190.   gint32        drawable_ID;
  191.   GimpExportReturnType export = GIMP_EXPORT_CANCEL;
  192.  
  193.   run_mode = param[0].data.d_int32;
  194.  
  195.   *nreturn_vals = 1;
  196.   *return_vals  = values;
  197.   values[0].type          = GIMP_PDB_STATUS;
  198.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  199.  
  200.   if (strcmp (name, "file_hrz_load") == 0)
  201.     {
  202.       INIT_I18N();
  203.       image_ID = load_image (param[1].data.d_string);
  204.  
  205.       if (image_ID != -1)
  206.     {
  207.       *nreturn_vals = 2;
  208.       values[1].type         = GIMP_PDB_IMAGE;
  209.       values[1].data.d_image = image_ID;
  210.     }
  211.       else
  212.     {
  213.       status = GIMP_PDB_EXECUTION_ERROR;
  214.     }
  215.     }
  216.   else if (strcmp (name, "file_hrz_save") == 0)
  217.     {
  218.       image_ID    = param[1].data.d_int32;
  219.       drawable_ID = param[2].data.d_int32;
  220.  
  221.       /*  eventually export the image */ 
  222.       switch (run_mode)
  223.     {
  224.     case GIMP_RUN_INTERACTIVE:
  225.     case GIMP_RUN_WITH_LAST_VALS:
  226.       INIT_I18N_UI();
  227.       gimp_ui_init ("hrz", FALSE);
  228.       export = gimp_export_image (&image_ID, &drawable_ID, "HRZ", 
  229.                       (GIMP_EXPORT_CAN_HANDLE_RGB |
  230.                        GIMP_EXPORT_CAN_HANDLE_GRAY));
  231.       if (export == GIMP_EXPORT_CANCEL)
  232.         {
  233.           values[0].data.d_status = GIMP_PDB_CANCEL;
  234.           return;
  235.         }
  236.       break;
  237.     default:
  238.       INIT_I18N();
  239.       break;
  240.     }
  241.  
  242.       switch (run_mode)
  243.     {
  244.     case GIMP_RUN_INTERACTIVE:
  245.       /*  First acquire information with a dialog  */
  246.       /*  Save dialog has no options (yet???)
  247.       if (! save_dialog ())
  248.         status = GIMP_PDB_CANCEL;
  249.       */
  250.       break;
  251.  
  252.     case GIMP_RUN_NONINTERACTIVE:
  253.       /*  Make sure all the arguments are there!  */
  254.       if (nparams != 4)
  255.         status = GIMP_PDB_CALLING_ERROR;
  256.       break;
  257.  
  258.     case GIMP_RUN_WITH_LAST_VALS:
  259.       break;
  260.  
  261.     default:
  262.       break;
  263.     }
  264.  
  265.       if (status == GIMP_PDB_SUCCESS)
  266.     {
  267.       if (! save_image (param[3].data.d_string, image_ID, drawable_ID))
  268.         {
  269.           status = GIMP_PDB_EXECUTION_ERROR;
  270.         }
  271.     }
  272.  
  273.       if (export == GIMP_EXPORT_EXPORT)
  274.     gimp_image_delete (image_ID);
  275.     }
  276.   else
  277.     {
  278.       status = GIMP_PDB_CALLING_ERROR;
  279.     }
  280.  
  281.   values[0].data.d_status = status;
  282. }
  283.  
  284. /************ load HRZ image row *********************/
  285. void
  286. do_hrz_load (void      *mapped,
  287.          GimpPixelRgn *pixel_rgn)
  288. {
  289.   guchar *data, *d;
  290.   gint    x, y;
  291.   gint    start, end, scanlines;
  292.  
  293.   data = g_malloc (gimp_tile_height () * 256 * 3);
  294.  
  295.   for (y = 0; y < 240; )
  296.     {
  297.       start = y;
  298.       end = y + gimp_tile_height ();
  299.       end = MIN (end, 240);
  300.       scanlines = end - start;
  301.       d = data;
  302.  
  303.       memcpy (d, ((guchar *) mapped) + 256 * 3 * y,
  304.           256 * 3 * scanlines); /* this is gross */
  305.  
  306.       /* scale 0..63 into 0..255 properly */
  307.       for (x = 0; x < 256 * 3 * scanlines; x++)
  308.     d[x] = (d[x]>>4) | (d[x]<<2);
  309.  
  310.       d += 256 * 3 * y;
  311.  
  312.       gimp_progress_update ((double) y / 240.0);
  313.       gimp_pixel_rgn_set_rect (pixel_rgn, data, 0, y, 256, scanlines);
  314.       y += scanlines;
  315.     }
  316.  
  317.   g_free (data);
  318. }
  319.  
  320. /********************* Load HRZ image **********************/
  321. static gint32
  322. load_image (gchar *filename)
  323. {
  324.   GimpPixelRgn pixel_rgn;
  325.   gint32 image_ID;
  326.   gint32 layer_ID;
  327.   GimpDrawable *drawable;
  328.   gint filedes;
  329.   gchar *temp;
  330.   void *mapped;  /* memory mapped file data */
  331.   struct stat statbuf;  /* must check file size */
  332.  
  333.   temp = g_strdup_printf (_("Loading %s:"), filename);
  334.   gimp_progress_init (temp);
  335.   g_free (temp);
  336.  
  337.   /* open the file */
  338.   filedes = open (filename, O_RDONLY | _O_BINARY);
  339.  
  340.   if (filedes == -1)
  341.     {
  342.       /* errno is set to indicate the error, but the user won't know :-( */
  343.       /*gimp_message("hrz filter: can't open file\n");*/
  344.       return -1;
  345.     }
  346.   /* stat the file to see if it is the right size */
  347.   fstat (filedes, &statbuf);
  348.   if (statbuf.st_size != 256*240*3)
  349.     {
  350.       g_message ("hrz: file is not HRZ type");
  351.       return -1;
  352.     }
  353. #ifdef HAVE_MMAP
  354.   mapped = mmap(NULL, 256*240*3, PROT_READ, MAP_PRIVATE, filedes, 0);
  355.   if (mapped == (void *)(-1))
  356.     {
  357.       g_message ("hrz: could not map file");
  358.       return -1;
  359.     }
  360. #else
  361.   mapped = g_malloc(256*240*3);
  362.   if (read (filedes, mapped, 256*240*3) != 256*240*3)
  363.     {
  364.       g_message ("hrz: file read error");
  365.       return -1;
  366.     }
  367. #endif
  368.   close (filedes);  /* not needed anymore, data is memory mapped */
  369.  
  370.   /* Create new image of proper size; associate filename */
  371.   image_ID = gimp_image_new (256, 240, GIMP_RGB);
  372.   gimp_image_set_filename (image_ID, filename);
  373.  
  374.   layer_ID = gimp_layer_new (image_ID, _("Background"),
  375.                  256, 240,
  376.                  GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE);
  377.   gimp_image_add_layer (image_ID, layer_ID, 0);
  378.  
  379.   drawable = gimp_drawable_get (layer_ID);
  380.   gimp_pixel_rgn_init (&pixel_rgn, drawable,
  381.                0, 0, drawable->width, drawable->height, TRUE, FALSE);
  382.  
  383.   do_hrz_load (mapped, &pixel_rgn);
  384.  
  385.   /* close the file */
  386. #ifdef HAVE_MMAP
  387.   munmap (mapped, 256*240*3);
  388. #else
  389.   g_free (mapped);
  390. #endif
  391.  
  392.   /* Tell the GIMP to display the image.
  393.    */
  394.   gimp_drawable_flush (drawable);
  395.  
  396.   return image_ID;
  397. }
  398.  
  399. /************** Writes out RGB raw rows ************/
  400. static void
  401. saverow (FILE   *fp,
  402.      guchar *data)
  403. {
  404.   gint loop = 256*3;
  405.   guchar *walk = data;
  406.   while (loop--)
  407.     {
  408.       *walk = (*walk >> 2);
  409.       walk++;
  410.     }
  411.   fwrite (data, 1, 256 * 3, fp);
  412. }
  413.  
  414. /********************* save image *********************/
  415. static gint
  416. save_image (gchar  *filename,
  417.         gint32  image_ID,
  418.         gint32  drawable_ID)
  419. {
  420.   GimpPixelRgn pixel_rgn;
  421.   GimpDrawable *drawable;
  422.   GimpImageType drawable_type;
  423.   guchar *data;
  424.   guchar *d;          /* FIX */
  425.   guchar *rowbuf;
  426.   gchar *temp;
  427.   gint np = 3;
  428.   gint xres, yres;
  429.   gint ypos, yend;
  430.   FILE *fp;
  431.  
  432.   /* initialize */
  433.  
  434.   d = NULL;
  435.  
  436.   drawable = gimp_drawable_get (drawable_ID);
  437.   drawable_type = gimp_drawable_type (drawable_ID);
  438.   gimp_pixel_rgn_init (&pixel_rgn, drawable,
  439.                0, 0, drawable->width, drawable->height, FALSE, FALSE);
  440.  
  441.   /*  Make sure we're not saving an image with an alpha channel  */
  442.   if (gimp_drawable_has_alpha (drawable_ID))
  443.     {
  444.       /* gimp_message ("HRZ save cannot handle images with alpha channels.");  */
  445.       return FALSE;
  446.     }
  447.  
  448.   /* open the file */
  449.   fp = fopen (filename, "wb");
  450.   if (fp == NULL)
  451.     {
  452.       /* Ought to pass errno back... */
  453.       g_message ("hrz: can't open \"%s\"\n", filename);
  454.       return FALSE;
  455.     }
  456.  
  457.   xres = drawable->width;
  458.   yres = drawable->height;
  459.  
  460.   if ((xres != 256) || (yres != 240))
  461.     {
  462.       g_message ("hrz: Image must be 256x240 for HRZ format.");
  463.       return FALSE;
  464.     }
  465.   if (drawable_type == GIMP_INDEXED_IMAGE)
  466.     {
  467.       g_message ("hrz: Image must be RGB or GRAY for HRZ format.");
  468.       return FALSE;
  469.     }
  470.  
  471.   temp = g_strdup_printf (_("Saving %s:"), filename);
  472.   gimp_progress_init (temp);
  473.   g_free (temp);
  474.  
  475.   /* allocate a buffer for retrieving information from the pixel region  */
  476.   data = (guchar *) g_malloc (gimp_tile_height () * drawable->width *
  477.                   drawable->bpp);
  478.  
  479.   rowbuf = g_malloc (256 * 3);
  480.  
  481.   /* Write the body out */
  482.   for (ypos = 0; ypos < yres; ypos++)
  483.     {
  484.       if ((ypos % gimp_tile_height ()) == 0)
  485.     {
  486.       yend = ypos + gimp_tile_height ();
  487.       yend = MIN (yend, yres);
  488.       gimp_pixel_rgn_get_rect (&pixel_rgn, data,
  489.                    0, ypos, xres, (yend - ypos));
  490.       d = data;
  491.     }
  492.  
  493.       saverow (fp, d);
  494.       d += xres * np;
  495.  
  496.       if (!(ypos & 0x0f))
  497.     gimp_progress_update ((double)ypos / 240.0 );
  498.     }
  499.  
  500.   /* close the file */
  501.   fclose (fp);
  502.  
  503.   g_free (rowbuf);
  504.   g_free (data);
  505.  
  506.   gimp_drawable_detach (drawable);
  507.  
  508.   return TRUE;
  509. }
  510.  
  511. /*********** Save dialog ************/
  512. /*
  513. static gint
  514. save_dialog (void)
  515. {
  516.   GtkWidget *dlg;
  517.  
  518.   dlg = gimp_dialog_new (_("Save as HRZ"), "hrz",
  519.              gimp_standard_help_func, "filters/hrz.html",
  520.              GTK_WIN_POS_MOUSE,
  521.              FALSE, TRUE, FALSE,
  522.  
  523.              _("OK"), save_ok_callback,
  524.              NULL, NULL, NULL, TRUE, FALSE,
  525.              _("Cancel"), gtk_widget_destroy,
  526.              NULL, 1, NULL, FALSE, TRUE,
  527.  
  528.              NULL);
  529.  
  530.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  531.               GTK_SIGNAL_FUNC (gtk_main_quit),
  532.               NULL);
  533.  
  534.   gtk_main ();
  535.   gdk_flush ();
  536.  
  537.   return psint.run;
  538. }
  539.  
  540. static void
  541. save_ok_callback (GtkWidget *widget,
  542.           gpointer   data)
  543. {
  544.   psint.run = TRUE;
  545.  
  546.   gtk_widget_destroy (GTK_WIDGET (data));
  547. }
  548. */
  549.