home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / temp_buf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  13.9 KB  |  593 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>
  22.  
  23. #include <errno.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #ifdef HAVE_UNISTD_H
  27. #include <unistd.h>
  28. #endif
  29. #include <string.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32.  
  33. #ifdef G_OS_WIN32
  34. #include <process.h>        /* For _getpid() */
  35. #endif
  36.  
  37. #include "apptypes.h"
  38.  
  39. #include "appenv.h"
  40. #include "drawable.h"
  41. #include "gdisplay.h"
  42. #include "gimprc.h"
  43. #include "paint_funcs.h"
  44. #include "temp_buf.h"
  45.  
  46. #include "libgimp/gimpcolorspace.h"
  47.  
  48.  
  49. static guchar * temp_buf_allocate (guint);
  50. static void     temp_buf_to_color (TempBuf *, TempBuf *);
  51. static void     temp_buf_to_gray  (TempBuf *, TempBuf *);
  52.  
  53.  
  54. /*  Memory management  */
  55.  
  56. static guchar *
  57. temp_buf_allocate (guint size)
  58. {
  59.   guchar *data;
  60.  
  61.   data = g_new (guchar, size);
  62.  
  63.   return data;
  64. }
  65.  
  66.  
  67. /*  The conversion routines  */
  68.  
  69. static void
  70. temp_buf_to_color (TempBuf *src_buf, 
  71.            TempBuf *dest_buf)
  72. {
  73.   guchar *src;
  74.   guchar *dest;
  75.   long num_bytes;
  76.  
  77.   src = temp_buf_data (src_buf);
  78.   dest = temp_buf_data (dest_buf);
  79.  
  80.   num_bytes = src_buf->width * src_buf->height;
  81.  
  82.   while (num_bytes--)
  83.     {
  84.       guchar tmpch;
  85.       *dest++ = *src++;  /* alpha channel */
  86.       *dest++ = tmpch = *src++;
  87.       *dest++ = tmpch;
  88.       *dest++ = tmpch;
  89.     }
  90. }
  91.  
  92.  
  93. static void
  94. temp_buf_to_gray (TempBuf *src_buf, 
  95.           TempBuf *dest_buf)
  96. {
  97.   guchar *src;
  98.   guchar *dest;
  99.   long  num_bytes;
  100.   float pix;
  101.  
  102.   src = temp_buf_data (src_buf);
  103.   dest = temp_buf_data (dest_buf);
  104.  
  105.   num_bytes = src_buf->width * src_buf->height;
  106.  
  107.   while (num_bytes--)
  108.     {
  109.       *dest++ = *src++;  /* alpha channel */
  110.  
  111.       pix = INTENSITY (*src++, *src++, *src++);
  112.  
  113.       *dest++ = (guchar) pix;
  114.     }
  115. }
  116.  
  117.  
  118. TempBuf *
  119. temp_buf_new (gint    width, 
  120.           gint    height, 
  121.           gint    bytes, 
  122.           gint    x, 
  123.           gint    y, 
  124.           guchar *col)
  125. {
  126.   long i;
  127.   int  j;
  128.   guchar  *data;
  129.   TempBuf *temp;
  130.  
  131.   temp = g_new (TempBuf, 1);
  132.  
  133.   temp->width  = width;
  134.   temp->height = height;
  135.   temp->bytes  = bytes;
  136.   temp->x      = x;
  137.   temp->y      = y;
  138.   temp->swapped = FALSE;
  139.   temp->filename = NULL;
  140.  
  141.   temp->data = data = temp_buf_allocate (width * height * bytes);
  142.  
  143.   /*  initialize the data  */
  144.   if (col)
  145.     {
  146.       /* First check if we can save a lot of work */
  147.       if (bytes == 1)
  148.         {
  149.           memset (data, *col, width * height);
  150.         }
  151.       else if ((bytes == 3) && (col[1] == *col) && (*col == col[2]))
  152.         {
  153.           memset (data, *col, width * height * 3);
  154.         }
  155.       else if ((bytes == 4) && (col[1] == *col) && (*col == col[2]) && (col[2] == col[3]))
  156.         {
  157.           memset (data, *col, (width * height) << 2);
  158.         }
  159.       else
  160.         {
  161.           /* No, we cannot */
  162.           guchar * dptr;
  163.           /* Fill the first row */
  164.           dptr = data;
  165.           for (i = width - 1; i >= 0; --i)
  166.             {
  167.               guchar * init;
  168.               j = bytes;
  169.               init = col;
  170.               while (j--)
  171.                 *dptr++ = *init++;
  172.             }
  173.           /* Now copy from it (we set bytes to bytesperrow now) */
  174.           bytes *= width;
  175.           while (--height)
  176.             {
  177.               memcpy (dptr, data, bytes);
  178.               dptr += bytes;
  179.             }
  180.         }
  181.     }
  182.  
  183.   return temp;
  184. }
  185.  
  186.  
  187. TempBuf *
  188. temp_buf_copy (TempBuf *src, 
  189.            TempBuf *dest)
  190. {
  191.   TempBuf * new;
  192.   long length;
  193.  
  194.   if (!src)
  195.     {
  196.       g_message ("trying to copy a temp buf which is NULL.");
  197.       return dest;
  198.     }
  199.  
  200.   if (!dest)
  201.     new = temp_buf_new (src->width, src->height, src->bytes, 0, 0, NULL);
  202.   else
  203.     {
  204.       new = dest;
  205.       if (dest->width != src->width || dest->height != src->height)
  206.     g_message ("In temp_buf_copy, the widths or heights don't match.");
  207.       /*  The temp buf is smart, and can translate between color and gray  */
  208.       /*  (only necessary if not we allocated it */
  209.       if (src->bytes != new->bytes)
  210.         {
  211.           if (src->bytes == 4)  /* RGB color */
  212.         temp_buf_to_gray (src, new);
  213.           else if (src->bytes == 2) /* grayscale */
  214.         temp_buf_to_color (src, new);
  215.           else
  216.         g_message ("Cannot convert from indexed color.");
  217.       return new;
  218.         }
  219.     }
  220.  
  221.   /* make the copy */
  222.   length = src->width * src->height * src->bytes;
  223.   memcpy (temp_buf_data (new), temp_buf_data (src), length);
  224.  
  225.   return new;
  226. }
  227.  
  228.  
  229. TempBuf *
  230. temp_buf_resize (TempBuf *buf, 
  231.          gint     bytes, 
  232.          gint     x, 
  233.          gint     y, 
  234.          gint     w, 
  235.          gint     h)
  236. {
  237.   gint size;
  238.  
  239.   /*  calculate the requested size  */
  240.   size = w * h * bytes;
  241.  
  242.   /*  First, configure the canvas buffer  */
  243.   if (!buf)
  244.     buf = temp_buf_new (w, h, bytes, x, y, NULL);
  245.   else
  246.     {
  247.       if (size != (buf->width * buf->height * buf->bytes))
  248.       {
  249.     /*  Make sure the temp buf is unswapped  */
  250.     temp_buf_unswap (buf);
  251.  
  252.     /*  Reallocate the data for it  */
  253.     buf->data = g_realloc (buf->data, size);
  254.       }
  255.  
  256.       /*  Make sure the temp buf fields are valid  */
  257.       buf->x = x;
  258.       buf->y = y;
  259.       buf->width = w;
  260.       buf->height = h;
  261.       buf->bytes = bytes;
  262.     }
  263.  
  264.   return buf;
  265. }
  266.  
  267.  
  268. TempBuf *
  269. temp_buf_copy_area (TempBuf *src, 
  270.             TempBuf *dest, 
  271.             gint     x, 
  272.             gint     y, 
  273.             gint     w, 
  274.             gint     h, 
  275.             gint     border)
  276. {
  277.   TempBuf * new;
  278.   PixelRegion srcR, destR;
  279.   guchar empty[MAX_CHANNELS] = { 0, 0, 0, 0 };
  280.   gint x1, y1, x2, y2;
  281.  
  282.   if (!src)
  283.     {
  284.       g_message ("trying to copy a temp buf which is NULL.");
  285.       return dest;
  286.     }
  287.  
  288.   /*  some bounds checking  */
  289.   x1 = CLAMP (x, 0, src->width);
  290.   y1 = CLAMP (y, 0, src->height);
  291.   x2 = CLAMP (x + w, 0, src->width);
  292.   y2 = CLAMP (y + h, 0, src->height);
  293.  
  294.   if (!(x2 - x1) || !(y2 - y1))
  295.     return dest;
  296.  
  297.   x = x1 - border;
  298.   y = y1 - border;
  299.   w = (x2 - x1) + border * 2;
  300.   h = (y2 - y1) + border * 2;
  301.  
  302.   if (!dest)
  303.     new = temp_buf_new (w, h, src->bytes, x, y, empty);
  304.   else
  305.     {
  306.       new = dest;
  307.       if (dest->bytes != src->bytes)
  308.     g_message ("In temp_buf_copy_area, the widths or heights or bytes don't match.");
  309.     }
  310.  
  311.   /*  Set the offsets for the dest  */
  312.   new->x = src->x + x;
  313.   new->y = src->y + y;
  314.  
  315.   /*  Copy the region  */
  316.   srcR.bytes = src->bytes;
  317.   srcR.w = (x2 - x1);
  318.   srcR.h = (y2 - y1);
  319.   srcR.rowstride = src->bytes * src->width;
  320.   srcR.data = temp_buf_data (src) + y1 * srcR.rowstride + x1 * srcR.bytes;
  321.  
  322.   destR.rowstride = new->bytes * new->width;
  323.   destR.data = temp_buf_data (new) + (y1 - y) * destR.rowstride + (x1 - x) * srcR.bytes;
  324.  
  325.   copy_region (&srcR, &destR);
  326.  
  327.   return new;
  328. }
  329.  
  330.  
  331. void
  332. temp_buf_free (TempBuf *temp_buf)
  333. {
  334.   if (temp_buf->data)
  335.     g_free (temp_buf->data);
  336.  
  337.   if (temp_buf->swapped)
  338.     temp_buf_swap_free (temp_buf);
  339.  
  340.   g_free (temp_buf);
  341. }
  342.  
  343.  
  344. guchar *
  345. temp_buf_data (TempBuf *temp_buf)
  346. {
  347.   if (temp_buf->swapped)
  348.     temp_buf_unswap (temp_buf);
  349.  
  350.   return temp_buf->data;
  351. }
  352.  
  353.  
  354. /******************************************************************
  355.  *  Mask buffer functions                                         *
  356.  ******************************************************************/
  357.  
  358.  
  359. MaskBuf *
  360. mask_buf_new (gint width, 
  361.           gint height)
  362. {
  363.   static guchar empty = 0;
  364.  
  365.   return (temp_buf_new (width, height, 1, 0, 0, &empty));
  366. }
  367.  
  368.  
  369. void
  370. mask_buf_free (MaskBuf *mask)
  371. {
  372.   temp_buf_free ((TempBuf *) mask);
  373. }
  374.  
  375.  
  376. guchar *
  377. mask_buf_data (MaskBuf *mask_buf)
  378. {
  379.   if (mask_buf->swapped)
  380.     temp_buf_unswap (mask_buf);
  381.  
  382.   return mask_buf->data;
  383. }
  384.  
  385.  
  386. /******************************************************************
  387.  *  temp buffer disk caching functions                            *
  388.  ******************************************************************/
  389.  
  390. /*  NOTES:
  391.  *  Disk caching is setup as follows:
  392.  *    On a call to temp_buf_swap, the TempBuf parameter is stored
  393.  *    in a temporary variable called cached_in_memory.
  394.  *    On the next call to temp_buf_swap, if cached_in_memory is non-null,
  395.  *    cached_in_memory is moved to disk, and the latest TempBuf parameter
  396.  *    is stored in cached_in_memory.  This method keeps the latest TempBuf
  397.  *    structure in memory instead of moving it directly to disk as requested.
  398.  *    On a call to temp_buf_unswap, if cached_in_memory is non-null, it is
  399.  *    compared against the requested TempBuf.  If they are the same, nothing
  400.  *    must be moved in from disk since it still resides in memory.  However,
  401.  *    if the two pointers are different, the requested TempBuf is retrieved
  402.  *    from disk.  In the former case, cached_in_memory is set to NULL;
  403.  *    in the latter case, cached_in_memory is left unchanged.
  404.  *    If temp_buf_swap_free is called, cached_in_memory must be checked
  405.  *    against the temp buf being freed.  If they are the same, then 
  406.  *    cached_in_memory must be set to NULL;
  407.  *
  408.  *  In the case where memory usage is set to "stingy":
  409.  *    temp bufs are not cached in memory at all, they go right to disk.
  410.  */
  411.  
  412.  
  413. /*  a static counter for generating unique filenames  */
  414. static gint swap_index = 0;
  415.  
  416. /*  a static pointer which keeps track of the last request for a swapped buffer  */
  417. static TempBuf * cached_in_memory = NULL;
  418.  
  419.  
  420. static gchar *
  421. generate_unique_filename (void)
  422. {
  423.   pid_t pid;
  424.   pid = getpid ();
  425.   return g_strdup_printf ("%s" G_DIR_SEPARATOR_S "gimp%d.%d",
  426.               temp_path, (int) pid, swap_index++);
  427. }
  428.  
  429.  
  430. void
  431. temp_buf_swap (TempBuf *buf)
  432. {
  433.   TempBuf * swap;
  434.   gchar * filename;
  435.   struct stat stat_buf;
  436.   gint err;
  437.   FILE * fp;
  438.  
  439.   if (!buf || buf->swapped)
  440.     return;
  441.  
  442.   /*  Set the swapped flag  */
  443.   buf->swapped = TRUE;
  444.  
  445.   if (stingy_memory_use)
  446.     swap = buf;
  447.   else
  448.     {
  449.       swap = cached_in_memory;
  450.       cached_in_memory = buf;
  451.     }
  452.  
  453.   /*  For the case where there is no temp buf ready to be moved to disk, return  */
  454.   if (!swap)
  455.     return;
  456.  
  457.   /*  Get a unique filename for caching the data to a UNIX file  */
  458.   filename = generate_unique_filename ();
  459.  
  460.   /*  Check if generated filename is valid  */
  461.   err = stat (filename, &stat_buf);
  462.   if (!err)
  463.     {
  464.       if (stat_buf.st_mode & S_IFDIR)
  465.     {
  466.       g_message ("Error in temp buf caching: \"%s\" is a directory (cannot overwrite)", filename);
  467.       g_free (filename);
  468.       return;
  469.     }
  470.     }
  471.  
  472.   /*  Open file for overwrite  */
  473.   if ((fp = fopen (filename, "wb")))
  474.     {
  475.       size_t blocks_written;
  476.       blocks_written = fwrite (swap->data, swap->width * swap->height * swap->bytes, 1, fp);
  477.       /* Check whether all bytes were written and fclose() was able to flush its buffers */
  478.       if ((0 != fclose (fp)) || (1 != blocks_written))
  479.         {
  480.           (void) unlink (filename);
  481.           perror ("Write error on temp buf");
  482.           g_message ("Cannot write \"%s\"", filename);
  483.           g_free (filename);
  484.           return;
  485.         }
  486.     }
  487.   else
  488.     {
  489.       (void) unlink (filename);
  490.       perror ("Error in temp buf caching");
  491.       g_message ("Cannot write \"%s\"", filename);
  492.       g_free (filename);
  493.       return;
  494.     }
  495.   /*  Finally, free the buffer's data  */
  496.   g_free (swap->data);
  497.   swap->data = NULL;
  498.  
  499.   swap->filename = filename;
  500. }
  501.  
  502.  
  503. void
  504. temp_buf_unswap (TempBuf *buf)
  505. {
  506.   struct stat stat_buf;
  507.   FILE * fp;
  508.   gboolean succ = FALSE;
  509.  
  510.   if (!buf || !buf->swapped)
  511.     return;
  512.  
  513.   /*  Set the swapped flag  */
  514.   buf->swapped = FALSE;
  515.  
  516.   /*  If the requested temp buf is still in memory, simply return  */
  517.   if (cached_in_memory == buf)
  518.     {
  519.       cached_in_memory = NULL;
  520.       return;
  521.     }
  522.  
  523.   /*  Allocate memory for the buffer's data  */
  524.   buf->data   = temp_buf_allocate (buf->width * buf->height * buf->bytes);
  525.  
  526.   /*  Find out if the filename of the swapped data is an existing file... */
  527.   /*  (buf->filname HAS to be != 0 */
  528.   if (!stat (buf->filename, &stat_buf))
  529.     {
  530.       if ((fp = fopen (buf->filename, "rb")))
  531.     {
  532.       size_t blocks_read;
  533.       blocks_read = fread (buf->data, buf->width * buf->height * buf->bytes, 1, fp);
  534.       (void) fclose (fp);
  535.       if (blocks_read != 1)
  536.             perror ("Read error on temp buf");
  537.       else
  538.         succ = TRUE;
  539.     }
  540.       else
  541.     perror ("Error in temp buf caching");
  542.  
  543.       /*  Delete the swap file  */
  544.       unlink (buf->filename);
  545.     }
  546.   if (!succ)
  547.     g_message ("Error in temp buf caching: information swapped to disk was lost!");
  548.  
  549.   g_free (buf->filename);   /*  free filename  */
  550.   buf->filename = NULL;
  551. }
  552.  
  553.  
  554. void
  555. temp_buf_swap_free (TempBuf *buf)
  556. {
  557.   struct stat stat_buf;
  558.  
  559.   if (!buf->swapped)
  560.     return;
  561.  
  562.   /*  Set the swapped flag  */
  563.   buf->swapped = FALSE;
  564.  
  565.   /*  If the requested temp buf is cached in memory...  */
  566.   if (cached_in_memory == buf)
  567.     {
  568.       cached_in_memory = NULL;
  569.       return;
  570.     }
  571.  
  572.   /*  Find out if the filename of the swapped data is an existing file... */
  573.   if (!stat (buf->filename, &stat_buf))
  574.     {
  575.       /*  Delete the swap file  */
  576.       unlink (buf->filename);
  577.     }
  578.   else
  579.     g_message ("Error in temp buf disk swapping: information swapped to disk was lost!");
  580.  
  581.   if (buf->filename)
  582.     g_free (buf->filename);   /*  free filename  */
  583.   buf->filename = NULL;
  584. }
  585.  
  586.  
  587. void
  588. swapping_free (void)
  589. {
  590.   if (cached_in_memory)
  591.     temp_buf_free (cached_in_memory);
  592. }
  593.