gimp/app/gimppreviewcache.c gimp/app/gimppreviewcache.h

Wed Jun 23 23:52:54 BST 1999 Andy Thomas <alt@gimp.org>

	* gimp/app/gimppreviewcache.c
	* gimp/app/gimppreviewcache.h
	* gimp/app/drawable_cmds.c
	* gimp/app/gdisplay.c
	* gimp/app/gimpdrawableP.h
	* gimp/app/gimage_cmds.c
	* gimp/app/Makefile.am
	* gimp/app/layers_dialog.c
	* gimp/app/channel.c
	* gimp/app/lc_dialog.c
	* gimp/app/lc_dialog.h
	* gimp/app/lc_dialogP.h
	* gimp/app/layer.c
	* gimp/app/gimpdrawable.c
	* gimp/app/internal_procs.c
	* gimp/libgimp/gimp.h
	* gimp/libgimp/gimpimage.c
	* gimp/libgimp/gimpdrawable.c
	* gimp/libgimp/gimpmenu.c
	* gimp/tools/pdbgen/pdb/drawable.pdb
	* gimp/tools/pdbgen/pdb/gimage.pdb

	Added thumbnail image preview functions.
	Previews are visible on the L&C&P dialogs as well as in the
	drawables/channels/ menus generated for plugins
	(see the bumpmap & Mapobject plugins).

	PDB interface exists to simply extract a thumbnail preview
	of a given size. This is much quicker & more efficient
	than getting the image data tile-by-tile if you only need a small
	image since a "preview cache" has been implemented. This cache also
	reduces the number of times the tiles cached is scanned since smaller
	previews are always generated from large ones if they exists and
	are valid.

	Some possible usages (I don't intend to implement these ideas. Just
	suggestions). More plugins using the thumbnail preview (ie any that
	use multiple images). Indication of "active image" somewhere.....
	Actually almost anywhere a drawable/image name appears.
This commit is contained in:
BST 1999 Andy Thomas 1999-06-23 23:01:14 +00:00 committed by Andy Thomas
parent 6bd258c588
commit 9b7d21dab5
36 changed files with 2003 additions and 132 deletions

View File

@ -1,3 +1,45 @@
Wed Jun 23 23:52:54 BST 1999 Andy Thomas <alt@gimp.org>
* gimp/app/gimppreviewcache.c
* gimp/app/gimppreviewcache.h
* gimp/app/drawable_cmds.c
* gimp/app/gdisplay.c
* gimp/app/gimpdrawableP.h
* gimp/app/gimage_cmds.c
* gimp/app/Makefile.am
* gimp/app/layers_dialog.c
* gimp/app/channel.c
* gimp/app/lc_dialog.c
* gimp/app/lc_dialog.h
* gimp/app/lc_dialogP.h
* gimp/app/layer.c
* gimp/app/gimpdrawable.c
* gimp/app/internal_procs.c
* gimp/libgimp/gimp.h
* gimp/libgimp/gimpimage.c
* gimp/libgimp/gimpdrawable.c
* gimp/libgimp/gimpmenu.c
* gimp/tools/pdbgen/pdb/drawable.pdb
* gimp/tools/pdbgen/pdb/gimage.pdb
Added thumbnail image preview functions.
Previews are visible on the L&C&P dialogs as well as in the
drawables/channels/ menus generated for plugins
(see the bumpmap & Mapobject plugins).
PDB interface exists to simply extract a thumbnail preview
of a given size. This is much quicker & more efficient
than getting the image data tile-by-tile if you only need a small
image since a "preview cache" has been implemented. This cache also
reduces the number of times the tiles cached is scanned since smaller
previews are always generated from large ones if they exists and
are valid.
Some possible usages (I don't intend to implement these ideas. Just
suggestions). More plugins using the thumbnail preview (ie any that
use multiple images). Indication of "active image" somewhere.....
Actually almost anywhere a drawable/image name appears.
1999-06-23 Michael Natterer <mitschel@cs.tu-berlin.de>
* app/brightness_contrast.c

View File

@ -18,6 +18,8 @@ libgimpim_a_SOURCES = \
gimpobject.h \
gimpobjectF.h \
gimpobjectP.h \
gimppreviewcache.h \
gimppreviewcache.c \
gimpset.c \
gimpset.h \
gimpsetF.h \

View File

@ -30,6 +30,7 @@
#include "parasitelist.h"
#include "temp_buf.h"
#include "undo.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
@ -425,12 +426,13 @@ channel_preview (Channel *channel, int width, int height)
MaskBuf * preview_buf;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
/* The easy way */
if (GIMP_DRAWABLE(channel)->preview_valid &&
GIMP_DRAWABLE(channel)->preview->width == width &&
GIMP_DRAWABLE(channel)->preview->height == height)
return GIMP_DRAWABLE(channel)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(channel)->preview_cache),
width,height)))
return ret_buf;
/* The hard way */
else
{
@ -455,13 +457,11 @@ channel_preview (Channel *channel, int width, int height)
subsample_region (&srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(channel)->preview_valid)
mask_buf_free (GIMP_DRAWABLE(channel)->preview);
GIMP_DRAWABLE(channel)->preview = preview_buf;
if(!GIMP_DRAWABLE(channel)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(channel)->preview_cache));
GIMP_DRAWABLE(channel)->preview_valid = 1;
return GIMP_DRAWABLE(channel)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(channel)->preview_cache),preview_buf);
return preview_buf;
}
}

View File

@ -30,6 +30,7 @@
#include "parasitelist.h"
#include "temp_buf.h"
#include "undo.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
@ -425,12 +426,13 @@ channel_preview (Channel *channel, int width, int height)
MaskBuf * preview_buf;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
/* The easy way */
if (GIMP_DRAWABLE(channel)->preview_valid &&
GIMP_DRAWABLE(channel)->preview->width == width &&
GIMP_DRAWABLE(channel)->preview->height == height)
return GIMP_DRAWABLE(channel)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(channel)->preview_cache),
width,height)))
return ret_buf;
/* The hard way */
else
{
@ -455,13 +457,11 @@ channel_preview (Channel *channel, int width, int height)
subsample_region (&srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(channel)->preview_valid)
mask_buf_free (GIMP_DRAWABLE(channel)->preview);
GIMP_DRAWABLE(channel)->preview = preview_buf;
if(!GIMP_DRAWABLE(channel)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(channel)->preview_cache));
GIMP_DRAWABLE(channel)->preview_valid = 1;
return GIMP_DRAWABLE(channel)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(channel)->preview_cache),preview_buf);
return preview_buf;
}
}

View File

@ -30,6 +30,7 @@
#include "parasitelist.h"
#include "temp_buf.h"
#include "undo.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
@ -425,12 +426,13 @@ channel_preview (Channel *channel, int width, int height)
MaskBuf * preview_buf;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
/* The easy way */
if (GIMP_DRAWABLE(channel)->preview_valid &&
GIMP_DRAWABLE(channel)->preview->width == width &&
GIMP_DRAWABLE(channel)->preview->height == height)
return GIMP_DRAWABLE(channel)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(channel)->preview_cache),
width,height)))
return ret_buf;
/* The hard way */
else
{
@ -455,13 +457,11 @@ channel_preview (Channel *channel, int width, int height)
subsample_region (&srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(channel)->preview_valid)
mask_buf_free (GIMP_DRAWABLE(channel)->preview);
GIMP_DRAWABLE(channel)->preview = preview_buf;
if(!GIMP_DRAWABLE(channel)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(channel)->preview_cache));
GIMP_DRAWABLE(channel)->preview_valid = 1;
return GIMP_DRAWABLE(channel)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(channel)->preview_cache),preview_buf);
return preview_buf;
}
}

View File

@ -650,7 +650,7 @@ gimp_drawable_init (GimpDrawable *drawable)
drawable->gimage = NULL;
drawable->type = -1;
drawable->has_alpha = FALSE;
drawable->preview = NULL;
drawable->preview_cache = NULL;
drawable->preview_valid = FALSE;
drawable->parasites = parasite_list_new();
drawable->tattoo = 0;
@ -679,8 +679,8 @@ gimp_drawable_destroy (GtkObject *object)
if (drawable->tiles)
tile_manager_destroy (drawable->tiles);
if (drawable->preview)
temp_buf_free (drawable->preview);
if (drawable->preview_cache)
gimp_preview_cache_invalidate(&drawable->preview_cache);
if (drawable->parasites)
gtk_object_unref(GTK_OBJECT(drawable->parasites));
@ -740,7 +740,7 @@ gimp_drawable_configure (GimpDrawable *drawable,
gimp_drawable_set_name(drawable, name);
/* preview variables */
drawable->preview = NULL;
drawable->preview_cache = NULL;
drawable->preview_valid = FALSE;
}

View File

@ -33,6 +33,8 @@
#include "parasitelist.h"
#include "undo.h"
#include "gimpsignal.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
#include "libgimp/parasite.h"
@ -1114,15 +1116,16 @@ layer_preview (layer, w, h)
int type;
int bytes;
int subsample;
TempBuf *ret_buf;
type = 0;
bytes = 0;
/* The easy way */
if (GIMP_DRAWABLE(layer)->preview_valid &&
GIMP_DRAWABLE(layer)->preview->width == w &&
GIMP_DRAWABLE(layer)->preview->height == h)
return GIMP_DRAWABLE(layer)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(layer)->preview_cache),
w,h)))
return ret_buf;
/* The hard way */
else
{
@ -1163,13 +1166,13 @@ layer_preview (layer, w, h)
layer_preview_scale (type, gimage->cmap, &srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(layer)->preview)
temp_buf_free (GIMP_DRAWABLE(layer)->preview);
if (!GIMP_DRAWABLE(layer)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(layer)->preview_cache));
GIMP_DRAWABLE(layer)->preview = preview_buf;
GIMP_DRAWABLE(layer)->preview_valid = TRUE;
return GIMP_DRAWABLE(layer)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(layer)->preview_cache),preview_buf);
return preview_buf;
}
}
@ -1183,6 +1186,7 @@ layer_mask_preview (layer, w, h)
LayerMask *mask;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
mask = layer->mask;
if (!mask)
@ -1190,9 +1194,9 @@ layer_mask_preview (layer, w, h)
/* The easy way */
if (GIMP_DRAWABLE(mask)->preview_valid &&
GIMP_DRAWABLE(mask)->preview->width == w &&
GIMP_DRAWABLE(mask)->preview->height == h)
return GIMP_DRAWABLE(mask)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(mask)->preview_cache),
w,h)))
return ret_buf;
/* The hard way */
else
{
@ -1215,13 +1219,13 @@ layer_mask_preview (layer, w, h)
layer_preview_scale (1 /* GRAY */, NULL, &srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(mask)->preview)
temp_buf_free (GIMP_DRAWABLE(mask)->preview);
if(!GIMP_DRAWABLE(mask)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(mask)->preview_cache));
GIMP_DRAWABLE(mask)->preview = preview_buf;
GIMP_DRAWABLE(mask)->preview_valid = TRUE;
gimp_preview_cache_add(&(GIMP_DRAWABLE(mask)->preview_cache),preview_buf);
return GIMP_DRAWABLE(mask)->preview;
return preview_buf;
}
}

271
app/core/gimppreviewcache.c Normal file
View File

@ -0,0 +1,271 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1999 Andy Thomas alt@gimp.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "gimpdrawableP.h"
#include "gimage.h"
#include "temp_buf.h"
#include "gimppreviewcache.h"
static gint
preview_cache_compare(gconstpointer a,
gconstpointer b)
{
PreviewCache *pc1 = (PreviewCache *)a;
PreviewCache *pc2 = (PreviewCache *)b;
if(pc1->width > pc2->width && pc1->height > pc2->height)
return -1;
return 1;
}
static void
preview_cache_find_exact(gpointer data, gpointer udata)
{
PreviewCache *pc = (PreviewCache *)data;
PreviewNearest *pNearest = (PreviewNearest *)udata;
/* printf("this value w,h [%d,%d]\n",pc->width,pc->height); */
/* if(pNearest->pc) */
/* printf("current nearest value w,h [%d,%d]\n",pNearest->pc->width,pNearest->pc->height); */
if(pNearest->pc)
return;
if(pc->width == pNearest->width &&
pc->height == pNearest->height)
{
/* Ok we could make the preview out of this one...
* If we already have it are these bigger dimensions?
*/
pNearest->pc = pc;
return;
}
}
static void
preview_cache_find_biggest(gpointer data, gpointer udata)
{
PreviewCache *pc = (PreviewCache *)data;
PreviewNearest *pNearest = (PreviewNearest *)udata;
/* printf("this value w,h [%d,%d]\n",pc->width,pc->height); */
/* if(pNearest->pc) */
/* printf("current nearest value w,h [%d,%d]\n",pNearest->pc->width,pNearest->pc->height); */
if(pc->width >= pNearest->width &&
pc->height >= pNearest->height)
{
/* Ok we could make the preview out of this one...
* If we already have it are these bigger dimensions?
*/
if(pNearest->pc)
{
if(pNearest->pc->width > pc->width &&
pNearest->pc->height > pc->height)
return;
}
pNearest->pc = pc;
}
}
static void
preview_cache_remove_smallest(GSList **plist)
{
GSList *cur = *plist;
PreviewCache *smallest = NULL;
/* printf("Removing smallest\n"); */
if(!cur)
return;
do
{
if(!smallest)
{
smallest = cur->data;
/* printf("init smallest %d,%d\n",smallest->width,smallest->height); */
}
else
{
PreviewCache *pcthis = cur->data;
/* printf("Checking %d,%d\n",pcthis->width,pcthis->height); */
if((smallest->height*smallest->width) >=
(pcthis->height*pcthis->width))
{
smallest = pcthis;
/* printf("smallest now %d,%d\n",smallest->width,smallest->height); */
}
}
} while((cur = g_slist_next(cur)));
*plist = g_slist_remove(*plist,smallest);
/* printf("removed %d,%d\n",smallest->width,smallest->height); */
/* printf("removed smallest\n"); */
}
static void
preview_cache_invalidate(gpointer data, gpointer udata)
{
PreviewCache *pc = (PreviewCache *)data;
temp_buf_free (pc->preview);
g_free(pc);
}
static void
preview_cache_print(gpointer data, gpointer udata)
{
/* PreviewCache *pc = (PreviewCache *)data; */
if(!data)
{
/* printf("\tNo Cache\n"); */
return;
}
/* printf("\tvalue w,h [%d,%d] => %p\n",pc->width,pc->height,pc->preview); */
}
void
gimp_preview_cache_invalidate(GSList **plist)
{
/* printf("gimp_preview_cache_invalidate\n"); */
g_slist_foreach(*plist,preview_cache_print,NULL);
g_slist_foreach(*plist,preview_cache_invalidate,NULL);
*plist = NULL;
}
void
gimp_preview_cache_add(GSList **plist,
TempBuf *buf)
{
PreviewCache *pc;
/* printf("gimp_preview_cache_add %d %d\n",buf->width,buf->height); */
g_slist_foreach(*plist,preview_cache_print,NULL);
if(g_slist_length(*plist) > MAX_CACHE_PREVIEWS)
{
/* Remove the smallest */
preview_cache_remove_smallest(plist);
}
pc = g_new0(PreviewCache,1);
pc->preview = buf;
pc->width = buf->width;
pc->height = buf->height;
*plist = g_slist_insert_sorted(*plist,pc,preview_cache_compare);
}
TempBuf *
gimp_preview_cache_get(GSList **plist,
gint width,
gint height)
{
PreviewNearest pn;
PreviewCache *pc;
/* printf("gimp_preview_cache_get %d %d\n",width,height); */
g_slist_foreach(*plist,preview_cache_print,NULL);
pn.pc = NULL;
pn.width = width;
pn.height = height;
g_slist_foreach(*plist,preview_cache_find_exact,&pn);
if(pn.pc && pn.pc->preview)
{
/* printf("extact value w,h [%d,%d] => %p\n",pn.pc->width,pn.pc->height,pn.pc->preview); */
return pn.pc->preview;
}
g_slist_foreach(*plist,preview_cache_find_biggest,&pn);
if(pn.pc)
{
gint pwidth;
gint pheight;
gdouble x_ratio;
gdouble y_ratio;
guchar *src_data;
guchar *dest_data;
gint loop1,loop2;
/* printf("nearest value w,h [%d,%d] => %p\n",pn.pc->width,pn.pc->height,pn.pc->preview); */
/* if(pn.pc->width == width && */
/* pn.pc->height == height) */
/* return pn.pc->preview; */
if(!pn.pc->preview)
{
g_error("gimp_preview_cache_get:: Invalid cache item");
return NULL;
}
/* Make up new preview from the large one... */
pwidth = pn.pc->preview->width;
pheight = pn.pc->preview->height;
/* Now get the real one and add to cache */
/* printf("Must create from large preview\n"); */
pc = g_new0(PreviewCache,1);
pc->preview = temp_buf_new(width,height,pn.pc->preview->bytes,0,0,NULL);
/* preview from nearest bigger one */
x_ratio = (gdouble)pwidth/(gdouble)width;
y_ratio = (gdouble)pheight/(gdouble)height;
src_data = temp_buf_data(pn.pc->preview);
dest_data = temp_buf_data(pc->preview);
/* printf("x_ratio , y_ratio [%f,%f]\n",x_ratio,y_ratio); */
for(loop1 = 0 ; loop1 < height ; loop1++)
for(loop2 = 0 ; loop2 < width ; loop2++)
{
int i;
guchar *src_pixel = src_data +
((gint)(loop2*x_ratio))*pn.pc->preview->bytes +
((gint)(loop1*y_ratio))*pwidth*pn.pc->preview->bytes;
guchar *dest_pixel = dest_data +
(loop2+loop1*width)*pn.pc->preview->bytes;
for(i = 0 ; i < pn.pc->preview->bytes; i++)
*dest_pixel++ = *src_pixel++;
}
pc->width = width;
pc->height = height;
*plist = g_slist_insert_sorted(*plist,pc,preview_cache_compare);
/* printf("New preview created [%d,%d] => %p\n",pc->width,pc->height,pc->preview); */
return pc->preview;
}
/* printf("gimp_preview_cache_get returning NULL\n"); */
return NULL;
}

View File

@ -0,0 +1,42 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1999 Andy Thomas alt@gimp.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMPPREVIEWCACHE_H__
#define __GIMPPREVIEWCACHE_H__
#include "temp_buf.h"
typedef struct _PreviewCache {
TempBuf* preview;
gint width;
gint height;
} PreviewCache;
typedef struct _PreviewNearest {
PreviewCache *pc;
gint width;
gint height;
} PreviewNearest;
#define MAX_CACHE_PREVIEWS 5
TempBuf * gimp_preview_cache_get(GSList **,gint,gint);
void gimp_preview_cache_add(GSList **,TempBuf *);
void gimp_preview_cache_invalidate(GSList **);
#endif /* __GIMPPREVIEWCACHE_H__ */

View File

@ -151,6 +151,8 @@ gdisplay_new (GimpImage *gimage,
gimage->instance_count++;
gimage->ref_count++;
lc_dialog_preview_update(gimage);
return gdisp;
}

View File

@ -151,6 +151,8 @@ gdisplay_new (GimpImage *gimage,
gimage->instance_count++;
gimage->ref_count++;
lc_dialog_preview_update(gimage);
return gdisp;
}

View File

@ -20,6 +20,9 @@
#include "procedural_db.h"
#include <glib.h>
#include <string.h>
#include "drawable.h"
#include "gimpdrawable.h"
#include "gimpimage.h"
@ -45,6 +48,7 @@ static ProcRecord drawable_channel_proc;
static ProcRecord drawable_get_pixel_proc;
static ProcRecord drawable_set_pixel_proc;
static ProcRecord drawable_set_image_proc;
static ProcRecord drawable_thumbnail_proc;
void
register_drawable_procs (void)
@ -70,6 +74,7 @@ register_drawable_procs (void)
procedural_db_register (&drawable_get_pixel_proc);
procedural_db_register (&drawable_set_pixel_proc);
procedural_db_register (&drawable_set_image_proc);
procedural_db_register (&drawable_thumbnail_proc);
}
static Argument *
@ -1270,3 +1275,143 @@ static ProcRecord drawable_set_image_proc =
NULL,
{ { drawable_set_image_invoker } }
};
static Argument *
drawable_thumbnail_invoker (Argument *args)
{
gboolean success = TRUE;
Argument *return_args;
GimpDrawable *drawable;
gint32 req_width;
gint32 req_height;
gint32 width = 0;
gint32 height = 0;
gint32 bpp = 0;
gint32 num_pixels = 0;
gint8 *thumbnail_data = NULL;
drawable = gimp_drawable_get_ID (args[0].value.pdb_int);
if (drawable == NULL)
success = FALSE;
req_width = args[1].value.pdb_int;
if (req_width <= 0)
success = FALSE;
req_height = args[2].value.pdb_int;
if (req_height <= 0)
success = FALSE;
if (success)
{
TempBuf * buf;
gint dwidth,dheight;
if(req_width <= 128 && req_height <= 128)
{
/* Adjust the width/height ratio */
dwidth = drawable_width(GIMP_DRAWABLE(drawable));
dheight = drawable_height(GIMP_DRAWABLE(drawable));
if(dwidth > dheight)
{
req_height = (req_width*dheight)/dwidth;
}
else
{
req_width = (req_height*dwidth)/dheight;
}
if(GIMP_IS_LAYER(drawable))
buf = layer_preview(GIMP_LAYER(drawable),req_width,req_height);
else
buf = channel_preview(GIMP_CHANNEL(drawable),req_width,req_height);
num_pixels = buf->height * buf->width * buf->bytes;
thumbnail_data = (gint8 *)g_new (gint8, num_pixels);
g_memmove (thumbnail_data, temp_buf_data (buf), num_pixels);
width = buf->width;
height = buf->height;
bpp = buf->bytes;
}
}
return_args = procedural_db_return_args (&drawable_thumbnail_proc, success);
if (success)
{
return_args[1].value.pdb_int = width;
return_args[2].value.pdb_int = height;
return_args[3].value.pdb_int = bpp;
return_args[4].value.pdb_int = num_pixels;
return_args[5].value.pdb_pointer = thumbnail_data;
}
return return_args;
}
static ProcArg drawable_thumbnail_inargs[] =
{
{
PDB_DRAWABLE,
"drawable",
"The drawable"
},
{
PDB_INT32,
"width",
"The thumbnail width"
},
{
PDB_INT32,
"height",
"The thumbnail height"
}
};
static ProcArg drawable_thumbnail_outargs[] =
{
{
PDB_INT32,
"width",
"The previews width"
},
{
PDB_INT32,
"height",
"The previews height"
},
{
PDB_INT32,
"bpp",
"The previews bpp"
},
{
PDB_INT32,
"thumbnail_data_count",
"The number of pixels in thumbnail data"
},
{
PDB_INT8ARRAY,
"thumbnail_data",
"The thumbnail data"
}
};
static ProcRecord drawable_thumbnail_proc =
{
"gimp_drawable_thumbnail",
"Get a thumbnail of a drawable.",
"This function gets data from which a thumbnail of a drawable preview can be created. Maximum x or y dimension is 128 pixels. The pixles are returned in the RGB[A] format. The bpp return value gives the number of bytes in the image. The alpha channel also returned if the drawable has one.",
"Andy Thomas",
"Andy Thomas",
"1999",
PDB_INTERNAL,
3,
drawable_thumbnail_inargs,
5,
drawable_thumbnail_outargs,
{ { drawable_thumbnail_invoker } }
};

View File

@ -151,6 +151,8 @@ gdisplay_new (GimpImage *gimage,
gimage->instance_count++;
gimage->ref_count++;
lc_dialog_preview_update(gimage);
return gdisp;
}

View File

@ -20,6 +20,7 @@
#include "procedural_db.h"
#include <glib.h>
#include <string.h>
#include "channel.h"
@ -65,6 +66,7 @@ static ProcRecord image_disable_undo_proc;
static ProcRecord image_clean_all_proc;
static ProcRecord image_floating_selection_proc;
static ProcRecord image_floating_sel_attached_to_proc;
static ProcRecord image_thumbnail_proc;
static ProcRecord image_width_proc;
static ProcRecord image_height_proc;
static ProcRecord image_get_active_layer_proc;
@ -122,6 +124,7 @@ register_gimage_procs (void)
procedural_db_register (&image_clean_all_proc);
procedural_db_register (&image_floating_selection_proc);
procedural_db_register (&image_floating_sel_attached_to_proc);
procedural_db_register (&image_thumbnail_proc);
procedural_db_register (&image_width_proc);
procedural_db_register (&image_height_proc);
procedural_db_register (&image_get_active_layer_proc);
@ -2178,6 +2181,142 @@ static ProcRecord image_floating_sel_attached_to_proc =
{ { image_floating_sel_attached_to_invoker } }
};
static Argument *
image_thumbnail_invoker (Argument *args)
{
gboolean success = TRUE;
Argument *return_args;
GimpImage *gimage;
gint32 req_width;
gint32 req_height;
gint32 width = 0;
gint32 height = 0;
gint32 bpp = 0;
gint32 num_pixels = 0;
gint8 *thumbnail_data = NULL;
gimage = pdb_id_to_image (args[0].value.pdb_int);
if (gimage == NULL)
success = FALSE;
req_width = args[1].value.pdb_int;
if (req_width <= 0)
success = FALSE;
req_height = args[2].value.pdb_int;
if (req_height <= 0)
success = FALSE;
if (success)
{
TempBuf * buf;
gint dwidth,dheight;
if(req_width <= 128 && req_height <= 128)
{
/* Adjust the width/height ratio */
dwidth = gimage->width;
dheight = gimage->height;
if(dwidth > dheight)
{
req_height = (req_width*dheight)/dwidth;
}
else
{
req_width = (req_height*dwidth)/dheight;
}
buf = gimp_image_construct_composite_preview(gimage,req_width,req_height);
num_pixels = buf->height * buf->width * buf->bytes;
thumbnail_data = (gint8 *)g_new (gint8, num_pixels);
g_memmove (thumbnail_data, temp_buf_data (buf), num_pixels);
width = buf->width;
height = buf->height;
bpp = buf->bytes;
}
}
return_args = procedural_db_return_args (&image_thumbnail_proc, success);
if (success)
{
return_args[1].value.pdb_int = width;
return_args[2].value.pdb_int = height;
return_args[3].value.pdb_int = bpp;
return_args[4].value.pdb_int = num_pixels;
return_args[5].value.pdb_pointer = thumbnail_data;
}
return return_args;
}
static ProcArg image_thumbnail_inargs[] =
{
{
PDB_IMAGE,
"image",
"The image"
},
{
PDB_INT32,
"width",
"The thumbnail width"
},
{
PDB_INT32,
"height",
"The thumbnail height"
}
};
static ProcArg image_thumbnail_outargs[] =
{
{
PDB_INT32,
"width",
"The previews width"
},
{
PDB_INT32,
"height",
"The previews height"
},
{
PDB_INT32,
"bpp",
"The previews bpp"
},
{
PDB_INT32,
"thumbnail_data_count",
"The number of pixels in thumbnail data"
},
{
PDB_INT8ARRAY,
"thumbnail_data",
"The thumbnail data"
}
};
static ProcRecord image_thumbnail_proc =
{
"gimp_image_thumbnail",
"Get a thumbnail of an image.",
"This function gets data from which a thumbnail of an image preview can be created. Maximum x or y dimension is 128 pixels. The pixles are returned in the RGB[A] format. The bpp return value gives the number of bytes in the image. The alpha channel also returned if the image has one.",
"Andy Thomas",
"Andy Thomas",
"1999",
PDB_INTERNAL,
3,
image_thumbnail_inargs,
5,
image_thumbnail_outargs,
{ { image_thumbnail_invoker } }
};
static Argument *
image_width_invoker (Argument *args)
{

View File

@ -30,6 +30,7 @@
#include "parasitelist.h"
#include "temp_buf.h"
#include "undo.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
@ -425,12 +426,13 @@ channel_preview (Channel *channel, int width, int height)
MaskBuf * preview_buf;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
/* The easy way */
if (GIMP_DRAWABLE(channel)->preview_valid &&
GIMP_DRAWABLE(channel)->preview->width == width &&
GIMP_DRAWABLE(channel)->preview->height == height)
return GIMP_DRAWABLE(channel)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(channel)->preview_cache),
width,height)))
return ret_buf;
/* The hard way */
else
{
@ -455,13 +457,11 @@ channel_preview (Channel *channel, int width, int height)
subsample_region (&srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(channel)->preview_valid)
mask_buf_free (GIMP_DRAWABLE(channel)->preview);
GIMP_DRAWABLE(channel)->preview = preview_buf;
if(!GIMP_DRAWABLE(channel)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(channel)->preview_cache));
GIMP_DRAWABLE(channel)->preview_valid = 1;
return GIMP_DRAWABLE(channel)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(channel)->preview_cache),preview_buf);
return preview_buf;
}
}

View File

@ -650,7 +650,7 @@ gimp_drawable_init (GimpDrawable *drawable)
drawable->gimage = NULL;
drawable->type = -1;
drawable->has_alpha = FALSE;
drawable->preview = NULL;
drawable->preview_cache = NULL;
drawable->preview_valid = FALSE;
drawable->parasites = parasite_list_new();
drawable->tattoo = 0;
@ -679,8 +679,8 @@ gimp_drawable_destroy (GtkObject *object)
if (drawable->tiles)
tile_manager_destroy (drawable->tiles);
if (drawable->preview)
temp_buf_free (drawable->preview);
if (drawable->preview_cache)
gimp_preview_cache_invalidate(&drawable->preview_cache);
if (drawable->parasites)
gtk_object_unref(GTK_OBJECT(drawable->parasites));
@ -740,7 +740,7 @@ gimp_drawable_configure (GimpDrawable *drawable,
gimp_drawable_set_name(drawable, name);
/* preview variables */
drawable->preview = NULL;
drawable->preview_cache = NULL;
drawable->preview_valid = FALSE;
}

View File

@ -21,6 +21,7 @@
#include "gimpobjectP.h"
#include "gimpdrawable.h"
#include "parasitelistF.h"
#include "gimppreviewcache.h"
struct _GimpDrawable
{
@ -43,7 +44,7 @@ struct _GimpDrawable
ParasiteList *parasites; /* Plug-in parasite data */
/* Preview variables */
TempBuf *preview; /* preview of the channel */
GSList *preview_cache; /* preview caches of the channel */
int preview_valid; /* is the preview valid? */
};

View File

@ -33,6 +33,8 @@
#include "parasitelist.h"
#include "undo.h"
#include "gimpsignal.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
#include "libgimp/parasite.h"
@ -1114,15 +1116,16 @@ layer_preview (layer, w, h)
int type;
int bytes;
int subsample;
TempBuf *ret_buf;
type = 0;
bytes = 0;
/* The easy way */
if (GIMP_DRAWABLE(layer)->preview_valid &&
GIMP_DRAWABLE(layer)->preview->width == w &&
GIMP_DRAWABLE(layer)->preview->height == h)
return GIMP_DRAWABLE(layer)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(layer)->preview_cache),
w,h)))
return ret_buf;
/* The hard way */
else
{
@ -1163,13 +1166,13 @@ layer_preview (layer, w, h)
layer_preview_scale (type, gimage->cmap, &srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(layer)->preview)
temp_buf_free (GIMP_DRAWABLE(layer)->preview);
if (!GIMP_DRAWABLE(layer)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(layer)->preview_cache));
GIMP_DRAWABLE(layer)->preview = preview_buf;
GIMP_DRAWABLE(layer)->preview_valid = TRUE;
return GIMP_DRAWABLE(layer)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(layer)->preview_cache),preview_buf);
return preview_buf;
}
}
@ -1183,6 +1186,7 @@ layer_mask_preview (layer, w, h)
LayerMask *mask;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
mask = layer->mask;
if (!mask)
@ -1190,9 +1194,9 @@ layer_mask_preview (layer, w, h)
/* The easy way */
if (GIMP_DRAWABLE(mask)->preview_valid &&
GIMP_DRAWABLE(mask)->preview->width == w &&
GIMP_DRAWABLE(mask)->preview->height == h)
return GIMP_DRAWABLE(mask)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(mask)->preview_cache),
w,h)))
return ret_buf;
/* The hard way */
else
{
@ -1215,13 +1219,13 @@ layer_mask_preview (layer, w, h)
layer_preview_scale (1 /* GRAY */, NULL, &srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(mask)->preview)
temp_buf_free (GIMP_DRAWABLE(mask)->preview);
if(!GIMP_DRAWABLE(mask)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(mask)->preview_cache));
GIMP_DRAWABLE(mask)->preview = preview_buf;
GIMP_DRAWABLE(mask)->preview_valid = TRUE;
gimp_preview_cache_add(&(GIMP_DRAWABLE(mask)->preview_cache),preview_buf);
return GIMP_DRAWABLE(mask)->preview;
return preview_buf;
}
}

271
app/gimppreviewcache.c Normal file
View File

@ -0,0 +1,271 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1999 Andy Thomas alt@gimp.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "gimpdrawableP.h"
#include "gimage.h"
#include "temp_buf.h"
#include "gimppreviewcache.h"
static gint
preview_cache_compare(gconstpointer a,
gconstpointer b)
{
PreviewCache *pc1 = (PreviewCache *)a;
PreviewCache *pc2 = (PreviewCache *)b;
if(pc1->width > pc2->width && pc1->height > pc2->height)
return -1;
return 1;
}
static void
preview_cache_find_exact(gpointer data, gpointer udata)
{
PreviewCache *pc = (PreviewCache *)data;
PreviewNearest *pNearest = (PreviewNearest *)udata;
/* printf("this value w,h [%d,%d]\n",pc->width,pc->height); */
/* if(pNearest->pc) */
/* printf("current nearest value w,h [%d,%d]\n",pNearest->pc->width,pNearest->pc->height); */
if(pNearest->pc)
return;
if(pc->width == pNearest->width &&
pc->height == pNearest->height)
{
/* Ok we could make the preview out of this one...
* If we already have it are these bigger dimensions?
*/
pNearest->pc = pc;
return;
}
}
static void
preview_cache_find_biggest(gpointer data, gpointer udata)
{
PreviewCache *pc = (PreviewCache *)data;
PreviewNearest *pNearest = (PreviewNearest *)udata;
/* printf("this value w,h [%d,%d]\n",pc->width,pc->height); */
/* if(pNearest->pc) */
/* printf("current nearest value w,h [%d,%d]\n",pNearest->pc->width,pNearest->pc->height); */
if(pc->width >= pNearest->width &&
pc->height >= pNearest->height)
{
/* Ok we could make the preview out of this one...
* If we already have it are these bigger dimensions?
*/
if(pNearest->pc)
{
if(pNearest->pc->width > pc->width &&
pNearest->pc->height > pc->height)
return;
}
pNearest->pc = pc;
}
}
static void
preview_cache_remove_smallest(GSList **plist)
{
GSList *cur = *plist;
PreviewCache *smallest = NULL;
/* printf("Removing smallest\n"); */
if(!cur)
return;
do
{
if(!smallest)
{
smallest = cur->data;
/* printf("init smallest %d,%d\n",smallest->width,smallest->height); */
}
else
{
PreviewCache *pcthis = cur->data;
/* printf("Checking %d,%d\n",pcthis->width,pcthis->height); */
if((smallest->height*smallest->width) >=
(pcthis->height*pcthis->width))
{
smallest = pcthis;
/* printf("smallest now %d,%d\n",smallest->width,smallest->height); */
}
}
} while((cur = g_slist_next(cur)));
*plist = g_slist_remove(*plist,smallest);
/* printf("removed %d,%d\n",smallest->width,smallest->height); */
/* printf("removed smallest\n"); */
}
static void
preview_cache_invalidate(gpointer data, gpointer udata)
{
PreviewCache *pc = (PreviewCache *)data;
temp_buf_free (pc->preview);
g_free(pc);
}
static void
preview_cache_print(gpointer data, gpointer udata)
{
/* PreviewCache *pc = (PreviewCache *)data; */
if(!data)
{
/* printf("\tNo Cache\n"); */
return;
}
/* printf("\tvalue w,h [%d,%d] => %p\n",pc->width,pc->height,pc->preview); */
}
void
gimp_preview_cache_invalidate(GSList **plist)
{
/* printf("gimp_preview_cache_invalidate\n"); */
g_slist_foreach(*plist,preview_cache_print,NULL);
g_slist_foreach(*plist,preview_cache_invalidate,NULL);
*plist = NULL;
}
void
gimp_preview_cache_add(GSList **plist,
TempBuf *buf)
{
PreviewCache *pc;
/* printf("gimp_preview_cache_add %d %d\n",buf->width,buf->height); */
g_slist_foreach(*plist,preview_cache_print,NULL);
if(g_slist_length(*plist) > MAX_CACHE_PREVIEWS)
{
/* Remove the smallest */
preview_cache_remove_smallest(plist);
}
pc = g_new0(PreviewCache,1);
pc->preview = buf;
pc->width = buf->width;
pc->height = buf->height;
*plist = g_slist_insert_sorted(*plist,pc,preview_cache_compare);
}
TempBuf *
gimp_preview_cache_get(GSList **plist,
gint width,
gint height)
{
PreviewNearest pn;
PreviewCache *pc;
/* printf("gimp_preview_cache_get %d %d\n",width,height); */
g_slist_foreach(*plist,preview_cache_print,NULL);
pn.pc = NULL;
pn.width = width;
pn.height = height;
g_slist_foreach(*plist,preview_cache_find_exact,&pn);
if(pn.pc && pn.pc->preview)
{
/* printf("extact value w,h [%d,%d] => %p\n",pn.pc->width,pn.pc->height,pn.pc->preview); */
return pn.pc->preview;
}
g_slist_foreach(*plist,preview_cache_find_biggest,&pn);
if(pn.pc)
{
gint pwidth;
gint pheight;
gdouble x_ratio;
gdouble y_ratio;
guchar *src_data;
guchar *dest_data;
gint loop1,loop2;
/* printf("nearest value w,h [%d,%d] => %p\n",pn.pc->width,pn.pc->height,pn.pc->preview); */
/* if(pn.pc->width == width && */
/* pn.pc->height == height) */
/* return pn.pc->preview; */
if(!pn.pc->preview)
{
g_error("gimp_preview_cache_get:: Invalid cache item");
return NULL;
}
/* Make up new preview from the large one... */
pwidth = pn.pc->preview->width;
pheight = pn.pc->preview->height;
/* Now get the real one and add to cache */
/* printf("Must create from large preview\n"); */
pc = g_new0(PreviewCache,1);
pc->preview = temp_buf_new(width,height,pn.pc->preview->bytes,0,0,NULL);
/* preview from nearest bigger one */
x_ratio = (gdouble)pwidth/(gdouble)width;
y_ratio = (gdouble)pheight/(gdouble)height;
src_data = temp_buf_data(pn.pc->preview);
dest_data = temp_buf_data(pc->preview);
/* printf("x_ratio , y_ratio [%f,%f]\n",x_ratio,y_ratio); */
for(loop1 = 0 ; loop1 < height ; loop1++)
for(loop2 = 0 ; loop2 < width ; loop2++)
{
int i;
guchar *src_pixel = src_data +
((gint)(loop2*x_ratio))*pn.pc->preview->bytes +
((gint)(loop1*y_ratio))*pwidth*pn.pc->preview->bytes;
guchar *dest_pixel = dest_data +
(loop2+loop1*width)*pn.pc->preview->bytes;
for(i = 0 ; i < pn.pc->preview->bytes; i++)
*dest_pixel++ = *src_pixel++;
}
pc->width = width;
pc->height = height;
*plist = g_slist_insert_sorted(*plist,pc,preview_cache_compare);
/* printf("New preview created [%d,%d] => %p\n",pc->width,pc->height,pc->preview); */
return pc->preview;
}
/* printf("gimp_preview_cache_get returning NULL\n"); */
return NULL;
}

42
app/gimppreviewcache.h Normal file
View File

@ -0,0 +1,42 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1999 Andy Thomas alt@gimp.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GIMPPREVIEWCACHE_H__
#define __GIMPPREVIEWCACHE_H__
#include "temp_buf.h"
typedef struct _PreviewCache {
TempBuf* preview;
gint width;
gint height;
} PreviewCache;
typedef struct _PreviewNearest {
PreviewCache *pc;
gint width;
gint height;
} PreviewNearest;
#define MAX_CACHE_PREVIEWS 5
TempBuf * gimp_preview_cache_get(GSList **,gint,gint);
void gimp_preview_cache_add(GSList **,TempBuf *);
void gimp_preview_cache_invalidate(GSList **);
#endif /* __GIMPPREVIEWCACHE_H__ */

View File

@ -78,6 +78,8 @@
#define SELECTED 1
#define INSENSITIVE 2
typedef struct _LayersDialog LayersDialog;
struct _LayersDialog
@ -257,7 +259,6 @@ static OpsButton layers_ops_buttons[] =
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
/************************************/
/* Public layers dialog functions */
/************************************/
@ -424,6 +425,22 @@ layers_dialog_free ()
layersD = NULL;
}
void
layers_dialog_invalidate_previews(GimpImage *gimage)
{
GSList *list = gimage->layers;
Layer * layer;
/* Invalidate all previews ... */
/* This is called during loading the image */
while (list)
{
layer = (Layer *) list->data;
GIMP_DRAWABLE(layer)->preview_valid = FALSE;
list = g_slist_next (list);
}
}
void
layers_dialog_update (GimpImage* gimage)
{
@ -582,6 +599,7 @@ layers_dialog_flush ()
gtk_container_foreach (GTK_CONTAINER (layersD->layer_list),
layer_widget_layer_flush, NULL);
}
void
@ -1222,7 +1240,6 @@ opacity_scale_update (GtkAdjustment *adjustment,
}
}
static void
preserve_trans_update (GtkWidget *w,
gpointer data)

View File

@ -59,7 +59,7 @@ void register_tools_procs (void);
void register_undo_procs (void);
void register_unit_procs (void);
/* 295 procedures registered total */
/* 297 procedures registered total */
void
internal_procs_init (void)
@ -73,82 +73,82 @@ internal_procs_init (void)
app_init_update_status (NULL, _("Channel"), 0.047);
register_channel_procs ();
app_init_update_status (NULL, _("Channel Ops"), 0.095);
app_init_update_status (NULL, _("Channel Ops"), 0.094);
register_channel_ops_procs ();
app_init_update_status (NULL, _("Color"), 0.102);
app_init_update_status (NULL, _("Color"), 0.101);
register_color_procs ();
app_init_update_status (NULL, _("Convert"), 0.142);
app_init_update_status (NULL, _("Convert"), 0.141);
register_convert_procs ();
app_init_update_status (NULL, _("Drawable procedures"), 0.156);
app_init_update_status (NULL, _("Drawable procedures"), 0.155);
register_drawable_procs ();
app_init_update_status (NULL, _("Edit procedures"), 0.227);
app_init_update_status (NULL, _("Edit procedures"), 0.229);
register_edit_procs ();
app_init_update_status (NULL, _("File Operations"), 0.247);
app_init_update_status (NULL, _("File Operations"), 0.249);
register_fileops_procs ();
app_init_update_status (NULL, _("Floating selections"), 0.268);
app_init_update_status (NULL, _("Floating selections"), 0.269);
register_floating_sel_procs ();
app_init_update_status (NULL, _("GDisplay procedures"), 0.288);
app_init_update_status (NULL, _("GDisplay procedures"), 0.29);
register_gdisplay_procs ();
app_init_update_status (NULL, _("Image"), 0.298);
app_init_update_status (NULL, _("Image"), 0.3);
register_gimage_procs ();
app_init_update_status (NULL, _("Image mask"), 0.478);
app_init_update_status (NULL, _("Image mask"), 0.481);
register_gimage_mask_procs ();
app_init_update_status (NULL, _("Gimprc procedures"), 0.536);
app_init_update_status (NULL, _("Gimprc procedures"), 0.539);
register_gimprc_procs ();
app_init_update_status (NULL, _("Gradients"), 0.542);
app_init_update_status (NULL, _("Gradients"), 0.545);
register_gradient_procs ();
app_init_update_status (NULL, _("Gradient UI"), 0.559);
app_init_update_status (NULL, _("Gradient UI"), 0.562);
register_gradient_select_procs ();
app_init_update_status (NULL, _("Guide procedures"), 0.573);
app_init_update_status (NULL, _("Guide procedures"), 0.576);
register_guides_procs ();
app_init_update_status (NULL, _("Interface"), 0.593);
app_init_update_status (NULL, _("Interface"), 0.596);
register_interface_procs ();
app_init_update_status (NULL, _("Layer"), 0.603);
app_init_update_status (NULL, _("Layer"), 0.606);
register_layer_procs ();
app_init_update_status (NULL, _("Miscellaneous"), 0.705);
app_init_update_status (NULL, _("Miscellaneous"), 0.707);
register_misc_procs ();
app_init_update_status (NULL, _("Palette"), 0.712);
app_init_update_status (NULL, _("Palette"), 0.714);
register_palette_procs ();
app_init_update_status (NULL, _("Parasite procedures"), 0.736);
app_init_update_status (NULL, _("Parasite procedures"), 0.737);
register_parasite_procs ();
app_init_update_status (NULL, _("Paths"), 0.78);
app_init_update_status (NULL, _("Paths"), 0.781);
register_paths_procs ();
app_init_update_status (NULL, _("Pattern UI"), 0.81);
app_init_update_status (NULL, _("Pattern UI"), 0.811);
register_pattern_select_procs ();
app_init_update_status (NULL, _("Patterns"), 0.82);
app_init_update_status (NULL, _("Patterns"), 0.822);
register_patterns_procs ();
app_init_update_status (NULL, _("Plug-in"), 0.834);
app_init_update_status (NULL, _("Plug-in"), 0.835);
register_plug_in_procs ();
app_init_update_status (NULL, _("Procedural database"), 0.847);
app_init_update_status (NULL, _("Procedural database"), 0.848);
register_procedural_db_procs ();
app_init_update_status (NULL, _("Text procedures"), 0.875);
register_text_tool_procs ();
app_init_update_status (NULL, _("Tool procedures"), 0.888);
app_init_update_status (NULL, _("Tool procedures"), 0.889);
register_tools_procs ();
app_init_update_status (NULL, _("Undo"), 0.956);

View File

@ -33,6 +33,8 @@
#include "parasitelist.h"
#include "undo.h"
#include "gimpsignal.h"
#include "gimppreviewcache.h"
#include "libgimp/gimpintl.h"
#include "libgimp/parasite.h"
@ -1114,15 +1116,16 @@ layer_preview (layer, w, h)
int type;
int bytes;
int subsample;
TempBuf *ret_buf;
type = 0;
bytes = 0;
/* The easy way */
if (GIMP_DRAWABLE(layer)->preview_valid &&
GIMP_DRAWABLE(layer)->preview->width == w &&
GIMP_DRAWABLE(layer)->preview->height == h)
return GIMP_DRAWABLE(layer)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(layer)->preview_cache),
w,h)))
return ret_buf;
/* The hard way */
else
{
@ -1163,13 +1166,13 @@ layer_preview (layer, w, h)
layer_preview_scale (type, gimage->cmap, &srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(layer)->preview)
temp_buf_free (GIMP_DRAWABLE(layer)->preview);
if (!GIMP_DRAWABLE(layer)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(layer)->preview_cache));
GIMP_DRAWABLE(layer)->preview = preview_buf;
GIMP_DRAWABLE(layer)->preview_valid = TRUE;
return GIMP_DRAWABLE(layer)->preview;
gimp_preview_cache_add(&(GIMP_DRAWABLE(layer)->preview_cache),preview_buf);
return preview_buf;
}
}
@ -1183,6 +1186,7 @@ layer_mask_preview (layer, w, h)
LayerMask *mask;
PixelRegion srcPR, destPR;
int subsample;
TempBuf *ret_buf;
mask = layer->mask;
if (!mask)
@ -1190,9 +1194,9 @@ layer_mask_preview (layer, w, h)
/* The easy way */
if (GIMP_DRAWABLE(mask)->preview_valid &&
GIMP_DRAWABLE(mask)->preview->width == w &&
GIMP_DRAWABLE(mask)->preview->height == h)
return GIMP_DRAWABLE(mask)->preview;
(ret_buf = gimp_preview_cache_get(&(GIMP_DRAWABLE(mask)->preview_cache),
w,h)))
return ret_buf;
/* The hard way */
else
{
@ -1215,13 +1219,13 @@ layer_mask_preview (layer, w, h)
layer_preview_scale (1 /* GRAY */, NULL, &srcPR, &destPR, subsample);
if (GIMP_DRAWABLE(mask)->preview)
temp_buf_free (GIMP_DRAWABLE(mask)->preview);
if(!GIMP_DRAWABLE(mask)->preview_valid)
gimp_preview_cache_invalidate(&(GIMP_DRAWABLE(mask)->preview_cache));
GIMP_DRAWABLE(mask)->preview = preview_buf;
GIMP_DRAWABLE(mask)->preview_valid = TRUE;
gimp_preview_cache_add(&(GIMP_DRAWABLE(mask)->preview_cache),preview_buf);
return GIMP_DRAWABLE(mask)->preview;
return preview_buf;
}
}

View File

@ -78,6 +78,8 @@
#define SELECTED 1
#define INSENSITIVE 2
typedef struct _LayersDialog LayersDialog;
struct _LayersDialog
@ -257,7 +259,6 @@ static OpsButton layers_ops_buttons[] =
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
/************************************/
/* Public layers dialog functions */
/************************************/
@ -424,6 +425,22 @@ layers_dialog_free ()
layersD = NULL;
}
void
layers_dialog_invalidate_previews(GimpImage *gimage)
{
GSList *list = gimage->layers;
Layer * layer;
/* Invalidate all previews ... */
/* This is called during loading the image */
while (list)
{
layer = (Layer *) list->data;
GIMP_DRAWABLE(layer)->preview_valid = FALSE;
list = g_slist_next (list);
}
}
void
layers_dialog_update (GimpImage* gimage)
{
@ -582,6 +599,7 @@ layers_dialog_flush ()
gtk_container_foreach (GTK_CONTAINER (layersD->layer_list),
layer_widget_layer_flush, NULL);
}
void
@ -1222,7 +1240,6 @@ opacity_scale_update (GtkAdjustment *adjustment,
}
}
static void
preserve_trans_update (GtkWidget *w,
gpointer data)

View File

@ -18,7 +18,8 @@
#ifndef __LAYERS_DIALOG_P_H__
#define __LAYERS_DIALOG_P_H__
void render_fs_preview (GtkWidget *, GdkPixmap *);
void render_preview (TempBuf *, GtkWidget *, int, int, int);
void render_fs_preview (GtkWidget *, GdkPixmap *);
void render_preview (TempBuf *, GtkWidget *, int, int, int);
void layers_dialog_invalidate_previews (GimpImage *gimage);
#endif /* __LAYERS_DIALOG_P_H__ */

View File

@ -28,10 +28,19 @@
#include "image_render.h"
#include "lc_dialog.h"
#include "lc_dialogP.h"
#include "layers_dialogP.h"
#include "session.h"
#include "libgimp/gimpintl.h"
#define GRAD_CHECK_SIZE_SM 4
#define GRAD_CHECK_DARK (1.0 / 3.0)
#define GRAD_CHECK_LIGHT (2.0 / 3.0)
#define MENU_THUMBNAIL_WIDTH 24
#define MENU_THUMBNAIL_HEIGHT 24
/* local function prototypes */
static void lc_dialog_update (GimpImage *);
static void lc_dialog_image_menu_callback (GtkWidget *, gpointer);
@ -42,6 +51,12 @@ static void lc_dialog_remove_cb (GimpSet *, GimpImage *, gpointer);
static void lc_dialog_destroy_cb (GimpImage *, gpointer);
static void lc_dialog_change_image (GimpContext *, GimpImage *,
gpointer);
static void lc_dialog_image_menu_preview_update_cb (GtkWidget *,gpointer);
static void lc_dialog_fill_preview_with_thumb(GtkWidget *,
GimpImage *,
gint ,
gint );
/* FIXME: move these to a better place */
static GtkWidget * lc_dialog_create_image_menu (GimpImage **, int *,
@ -262,6 +277,56 @@ lc_dialog_flush ()
paths_dialog_flush ();
}
static gint
image_menu_preview_update_do(GimpImage *gimage)
{
if(lc_dialog)
{
gtk_container_foreach (GTK_CONTAINER (lc_dialog->image_menu),
lc_dialog_image_menu_preview_update_cb, (gpointer)gimage);
}
return FALSE;
}
static void
menu_preview_dirty (GtkObject *obj,
gpointer client_data)
{
/* Update preview at a less busy time */
/* printf("menu_preview_dirty:: adding %p to obj %p\n",client_data,obj); */
gtk_idle_add((GtkFunction)image_menu_preview_update_do,(gpointer)obj);
}
void
lc_dialog_preview_update(GimpImage *gimage)
{
layers_dialog_invalidate_previews(gimage);
gtk_idle_add((GtkFunction)image_menu_preview_update_do,gimage);
}
static void
lc_dialog_image_menu_preview_update_cb (GtkWidget *widget,
gpointer client_data)
{
GtkWidget *menu_preview;
GimpImage *gimage;
GimpImage *gimage_to_update = GIMP_IMAGE((GimpImage *)client_data);
menu_preview = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(widget),"menu_preview");
gimage = GIMP_IMAGE((GimpImage *)gtk_object_get_data(GTK_OBJECT(widget),"menu_preview_gimage"));
/* printf("image_menu_preview_update::menu_preview = %p gimage %p gimage_to_update %d\n",menu_preview,gimage,gimage_to_update); */
if(menu_preview && gimage && gimage_to_update == gimage)
{
/* Must update the preview? */
lc_dialog_fill_preview_with_thumb(menu_preview,
gimage,
MENU_THUMBNAIL_WIDTH,
MENU_THUMBNAIL_HEIGHT);
gtk_widget_draw(GTK_WIDGET(menu_preview),NULL);
}
}
void
lc_dialog_update_image_list ()
{
@ -334,6 +399,131 @@ typedef struct
GImage *id;
} IMCBData;
static void
lc_dialog_fill_preview_with_thumb(GtkWidget *w,
GimpImage *gimage,
gint width,
gint height)
{
guchar *drawable_data;
TempBuf *buf;
gint bpp;
gint dwidth;
gint dheight;
bpp = 0; /* Only returned */
dwidth = gimage->width;
dheight = gimage->height;
/* Get right aspect ratio */
if(dwidth > dheight)
{
height = (width*dheight)/dwidth;
}
else
{
width = (height*dwidth)/dheight;
}
buf = gimp_image_construct_composite_preview(gimage,
width,
height);
drawable_data = temp_buf_data(buf);
bpp = buf->bytes;
gtk_preview_size(GTK_PREVIEW(w),width,height);
/* First greyscale and non-alpha */
if(bpp < 4)
{
guchar *buf;
guchar *src;
gint x,y;
/* Draw the image */
buf = g_new (gchar, width * 3);
src = drawable_data;
for (y = 0; y < height; y++)
{
if (bpp == 1)
for (x = 0; x < width; x++)
{
buf[x*3+0] = src[x];
buf[x*3+1] = src[x];
buf[x*3+2] = src[x];
}
else
for (x = 0; x < width; x++)
{
buf[x*3+0] = src[x*3+0];
buf[x*3+1] = src[x*3+1];
buf[x*3+2] = src[x*3+2];
}
gtk_preview_draw_row (GTK_PREVIEW (w), (guchar *)buf, 0, y, width);
src += width * bpp;
}
g_free(buf);
}
else /* Has alpha channel */
{
gint x,y;
guchar *src;
gdouble r, g, b, a;
gdouble c0, c1;
guchar *p0, *p1,*even,*odd;
/* Draw the thumbnail with checks */
src = drawable_data;
even = g_malloc(width*3);
odd = g_malloc(width*3);
for (y = 0; y < height; y++)
{
p0 = even;
p1 = odd;
for (x = 0; x < width; x++) {
r = ((gdouble)src[x*4+0])/255.0;
g = ((gdouble)src[x*4+1])/255.0;
b = ((gdouble)src[x*4+2])/255.0;
a = ((gdouble)src[x*4+3])/255.0;
if ((x / GRAD_CHECK_SIZE_SM) & 1) {
c0 = GRAD_CHECK_LIGHT;
c1 = GRAD_CHECK_DARK;
} else {
c0 = GRAD_CHECK_DARK;
c1 = GRAD_CHECK_LIGHT;
} /* else */
*p0++ = (c0 + (r - c0) * a) * 255.0;
*p0++ = (c0 + (g - c0) * a) * 255.0;
*p0++ = (c0 + (b - c0) * a) * 255.0;
*p1++ = (c1 + (r - c1) * a) * 255.0;
*p1++ = (c1 + (g - c1) * a) * 255.0;
*p1++ = (c1 + (b - c1) * a) * 255.0;
} /* for */
if ((y / GRAD_CHECK_SIZE_SM) & 1)
{
gtk_preview_draw_row (GTK_PREVIEW (w), (guchar *)odd, 0, y, width);
}
else
{
gtk_preview_draw_row (GTK_PREVIEW (w), (guchar *)even, 0, y, width);
}
src += width * bpp;
}
g_free(even);
g_free(odd);
}
}
static void
lc_dialog_create_image_menu_cb (gpointer im,
gpointer d)
@ -343,6 +533,10 @@ lc_dialog_create_image_menu_cb (gpointer im,
char *image_name;
char *menu_item_label;
GtkWidget *menu_item;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *wcolor_box;
GtkWidget *wlabel;
/* make sure the default index gets set to _something_, if possible */
if (*data->default_index == -1)
@ -360,12 +554,50 @@ lc_dialog_create_image_menu_cb (gpointer im,
image_name = g_basename (gimage_filename (gimage));
menu_item_label =
g_strdup_printf ("%s-%d", image_name, pdb_image_to_id (gimage));
menu_item = gtk_menu_item_new_with_label (menu_item_label);
menu_item = gtk_menu_item_new();
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
(GtkSignalFunc) data->callback, gimage);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add (GTK_CONTAINER (menu_item), hbox);
gtk_widget_show(hbox);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
wcolor_box = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
lc_dialog_fill_preview_with_thumb(wcolor_box,
gimage,
MENU_THUMBNAIL_WIDTH,
MENU_THUMBNAIL_HEIGHT);
gtk_widget_set_usize( GTK_WIDGET (wcolor_box) ,
MENU_THUMBNAIL_WIDTH ,
MENU_THUMBNAIL_HEIGHT);
gtk_container_add(GTK_CONTAINER(vbox), wcolor_box);
gtk_widget_show(wcolor_box);
wlabel = gtk_label_new(menu_item_label);
gtk_misc_set_alignment(GTK_MISC(wlabel), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), wlabel, TRUE, TRUE, 4);
gtk_widget_show(wlabel);
gtk_container_add (GTK_CONTAINER (data->menu), menu_item);
if(gtk_object_get_data(GTK_OBJECT (gimage),"menu_preview_dirty") == NULL)
{
/* Only add this signal once */
gtk_object_set_data(GTK_OBJECT (gimage),"menu_preview_dirty",(gpointer)1);
gtk_signal_connect_after (GTK_OBJECT (gimage), "dirty",
GTK_SIGNAL_FUNC(menu_preview_dirty),NULL);
}
gtk_object_set_data(GTK_OBJECT(menu_item),"menu_preview",wcolor_box);
gtk_object_set_data(GTK_OBJECT(menu_item),"menu_preview_gimage",gimage);
gtk_widget_show (menu_item);
g_free (menu_item_label);
data->num_items ++;
}

View File

@ -28,5 +28,7 @@ void lc_dialog_rebuild (int); /* implies free & create */
void lc_dialog_flush (void);
void lc_dialog_update_image_list (void);
void lc_dialog_preview_update (GimpImage *gimage);
#endif /* __LC_DIALOG_H__ */

View File

@ -527,6 +527,10 @@ gint32 gimp_image_get_layer_by_tattoo (gint32 image_ID,
gint32 gimp_image_get_channel_by_tattoo (gint32 image_ID,
gint32 tattoo);
guchar * gimp_image_get_thumbnail_data (gint32 image_ID,
gint *width,
gint *height,
gint *bytes);
/****************************************
* Guides *
@ -719,7 +723,10 @@ void gimp_layer_attach_new_parasite(gint32 drawable,
int size, const void *data);
void gimp_drawable_detach_parasite (gint32 drawable,
const char *name);
guchar * gimp_drawable_get_thumbnail_data (gint32 drawable_ID,
gint *width,
gint *height,
gint *bytes);
/****************************************
* GTiles *

View File

@ -16,6 +16,8 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "gimp.h"
@ -654,3 +656,36 @@ gimp_drawable_detach_parasite (gint32 drawable_ID,
gimp_destroy_params (return_vals, nreturn_vals);
}
guchar *
gimp_drawable_get_thumbnail_data (gint32 drawable_ID,
gint *width,
gint *height,
gint *bytes)
{
GParam *return_vals;
int nreturn_vals;
gchar *drawable_data = NULL;
return_vals = gimp_run_procedure ("gimp_drawable_thumbnail",
&nreturn_vals,
PARAM_DRAWABLE, drawable_ID,
PARAM_INT32, *width,
PARAM_INT32, *height,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
*width = return_vals[1].data.d_int32;
*height = return_vals[2].data.d_int32;
*bytes = return_vals[3].data.d_int32;
drawable_data = g_new (gchar,return_vals[4].data.d_int32);
g_memmove (drawable_data, return_vals[5].data.d_int32array,return_vals[4].data.d_int32);
}
gimp_destroy_params (return_vals, nreturn_vals);
return drawable_data;
}

View File

@ -16,6 +16,8 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "gimp.h"
@ -654,3 +656,36 @@ gimp_drawable_detach_parasite (gint32 drawable_ID,
gimp_destroy_params (return_vals, nreturn_vals);
}
guchar *
gimp_drawable_get_thumbnail_data (gint32 drawable_ID,
gint *width,
gint *height,
gint *bytes)
{
GParam *return_vals;
int nreturn_vals;
gchar *drawable_data = NULL;
return_vals = gimp_run_procedure ("gimp_drawable_thumbnail",
&nreturn_vals,
PARAM_DRAWABLE, drawable_ID,
PARAM_INT32, *width,
PARAM_INT32, *height,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
*width = return_vals[1].data.d_int32;
*height = return_vals[2].data.d_int32;
*bytes = return_vals[3].data.d_int32;
drawable_data = g_new (gchar,return_vals[4].data.d_int32);
g_memmove (drawable_data, return_vals[5].data.d_int32array,return_vals[4].data.d_int32);
}
gimp_destroy_params (return_vals, nreturn_vals);
return drawable_data;
}

View File

@ -1132,3 +1132,35 @@ gimp_image_get_channel_by_tattoo (gint32 image_ID, gint32 tattoo)
return channel;
}
guchar *
gimp_image_get_thumbnail_data (gint32 image_ID,
gint *width,
gint *height,
gint *bytes)
{
GParam *return_vals;
int nreturn_vals;
gchar *image_data = NULL;
return_vals = gimp_run_procedure ("gimp_image_thumbnail",
&nreturn_vals,
PARAM_DRAWABLE, image_ID,
PARAM_INT32, *width,
PARAM_INT32, *height,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
*width = return_vals[1].data.d_int32;
*height = return_vals[2].data.d_int32;
*bytes = return_vals[3].data.d_int32;
image_data = g_new (gchar,return_vals[4].data.d_int32);
g_memmove (image_data, return_vals[5].data.d_int32array,return_vals[4].data.d_int32);
}
gimp_destroy_params (return_vals, nreturn_vals);
return image_data;
}

View File

@ -1132,3 +1132,35 @@ gimp_image_get_channel_by_tattoo (gint32 image_ID, gint32 tattoo)
return channel;
}
guchar *
gimp_image_get_thumbnail_data (gint32 image_ID,
gint *width,
gint *height,
gint *bytes)
{
GParam *return_vals;
int nreturn_vals;
gchar *image_data = NULL;
return_vals = gimp_run_procedure ("gimp_image_thumbnail",
&nreturn_vals,
PARAM_DRAWABLE, image_ID,
PARAM_INT32, *width,
PARAM_INT32, *height,
PARAM_END);
if (return_vals[0].data.d_status == STATUS_SUCCESS)
{
*width = return_vals[1].data.d_int32;
*height = return_vals[2].data.d_int32;
*bytes = return_vals[3].data.d_int32;
image_data = g_new (gchar,return_vals[4].data.d_int32);
g_memmove (image_data, return_vals[5].data.d_int32array,return_vals[4].data.d_int32);
}
gimp_destroy_params (return_vals, nreturn_vals);
return image_data;
}

View File

@ -22,6 +22,13 @@
#include "gimp.h"
#include "gimpui.h"
#define GRAD_CHECK_SIZE_SM 4
#define GRAD_CHECK_DARK (1.0 / 3.0)
#define GRAD_CHECK_LIGHT (2.0 / 3.0)
#define MENU_THUMBNAIL_WIDTH 24
#define MENU_THUMBNAIL_HEIGHT 24
/* Copy data from temp_PDB call */
struct _GBrushData {
@ -84,7 +91,10 @@ static gboolean input_callback (GIOChannel *channel,
gpointer data);
static void gimp_setup_callbacks (void);
static gchar* gen_temp_plugin_name (void);
static void fill_preview_with_thumb(GtkWidget *,
gint32,
gint,
gint);
/* From gimp.c */
void gimp_run_temp (void);
@ -95,7 +105,6 @@ static GBrushData *active_brush_pdb = NULL;
static GPatternData *active_pattern_pdb = NULL;
static GGradientData *active_gradient_pdb = NULL;
GtkWidget*
gimp_image_menu_new (GimpConstraintFunc constraint,
GimpMenuCallback callback,
@ -156,6 +165,8 @@ gimp_image_menu_new (GimpConstraintFunc constraint,
return menu;
}
GtkWidget*
gimp_layer_menu_new (GimpConstraintFunc constraint,
GimpMenuCallback callback,
@ -193,15 +204,49 @@ gimp_layer_menu_new (GimpConstraintFunc constraint,
for (j = 0; j < nlayers; j++)
if (!constraint || (* constraint) (images[i], layers[j], data))
{
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *wcolor_box;
GtkWidget *wlabel;
name = gimp_layer_get_name (layers[j]);
label = g_new (char, strlen (image_label) + strlen (name) + 2);
sprintf (label, "%s/%s", image_label, name);
g_free (name);
menuitem = gtk_menu_item_new_with_label (label);
menuitem = gtk_menu_item_new();
gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
(GtkSignalFunc) gimp_menu_callback,
&layers[j]);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(menuitem), hbox);
gtk_widget_show(hbox);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
wcolor_box = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
fill_preview_with_thumb(wcolor_box,
layers[j],
MENU_THUMBNAIL_WIDTH,
MENU_THUMBNAIL_HEIGHT);
gtk_widget_set_usize( GTK_WIDGET (wcolor_box) ,
MENU_THUMBNAIL_WIDTH ,
MENU_THUMBNAIL_HEIGHT);
gtk_container_add(GTK_CONTAINER(vbox), wcolor_box);
gtk_widget_show(wcolor_box);
wlabel = gtk_label_new(label);
gtk_misc_set_alignment(GTK_MISC(wlabel), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), wlabel, TRUE, TRUE, 4);
gtk_widget_show(wlabel);
gtk_menu_append (GTK_MENU (menu), menuitem);
gtk_widget_show (menuitem);
@ -273,15 +318,49 @@ gimp_channel_menu_new (GimpConstraintFunc constraint,
for (j = 0; j < nchannels; j++)
if (!constraint || (* constraint) (images[i], channels[j], data))
{
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *wcolor_box;
GtkWidget *wlabel;
name = gimp_channel_get_name (channels[j]);
label = g_new (char, strlen (image_label) + strlen (name) + 2);
sprintf (label, "%s/%s", image_label, name);
g_free (name);
menuitem = gtk_menu_item_new_with_label (label);
menuitem = gtk_menu_item_new();
gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
(GtkSignalFunc) gimp_menu_callback,
&channels[j]);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(menuitem), hbox);
gtk_widget_show(hbox);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
wcolor_box = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
fill_preview_with_thumb(wcolor_box,
channels[j],
MENU_THUMBNAIL_WIDTH,
MENU_THUMBNAIL_HEIGHT);
gtk_widget_set_usize( GTK_WIDGET (wcolor_box) ,
MENU_THUMBNAIL_WIDTH ,
MENU_THUMBNAIL_HEIGHT);
gtk_container_add(GTK_CONTAINER(vbox), wcolor_box);
gtk_widget_show(wcolor_box);
wlabel = gtk_label_new(label);
gtk_misc_set_alignment(GTK_MISC(wlabel), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), wlabel, TRUE, TRUE, 4);
gtk_widget_show(wlabel);
gtk_menu_append (GTK_MENU (menu), menuitem);
gtk_widget_show (menuitem);
@ -355,15 +434,49 @@ gimp_drawable_menu_new (GimpConstraintFunc constraint,
for (j = 0; j < nlayers; j++)
if (!constraint || (* constraint) (images[i], layers[j], data))
{
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *wcolor_box;
GtkWidget *wlabel;
name = gimp_layer_get_name (layers[j]);
label = g_new (char, strlen (image_label) + strlen (name) + 2);
sprintf (label, "%s/%s", image_label, name);
g_free (name);
menuitem = gtk_menu_item_new_with_label (label);
menuitem = gtk_menu_item_new();
gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
(GtkSignalFunc) gimp_menu_callback,
&layers[j]);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(menuitem), hbox);
gtk_widget_show(hbox);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
wcolor_box = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
fill_preview_with_thumb(wcolor_box,
layers[j],
MENU_THUMBNAIL_WIDTH,
MENU_THUMBNAIL_HEIGHT);
gtk_widget_set_usize( GTK_WIDGET (wcolor_box) ,
MENU_THUMBNAIL_WIDTH ,
MENU_THUMBNAIL_HEIGHT);
gtk_container_add(GTK_CONTAINER(vbox), wcolor_box);
gtk_widget_show(wcolor_box);
wlabel = gtk_label_new(label);
gtk_misc_set_alignment(GTK_MISC(wlabel), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), wlabel, TRUE, TRUE, 4);
gtk_widget_show(wlabel);
gtk_menu_append (GTK_MENU (menu), menuitem);
gtk_widget_show (menuitem);
@ -384,15 +497,49 @@ gimp_drawable_menu_new (GimpConstraintFunc constraint,
for (j = 0; j < nchannels; j++)
if (!constraint || (* constraint) (images[i], channels[j], data))
{
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *wcolor_box;
GtkWidget *wlabel;
name = gimp_channel_get_name (channels[j]);
label = g_new (char, strlen (image_label) + strlen (name) + 2);
sprintf (label, "%s/%s", image_label, name);
g_free (name);
menuitem = gtk_menu_item_new_with_label (label);
menuitem = gtk_menu_item_new();
gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
(GtkSignalFunc) gimp_menu_callback,
&channels[j]);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(menuitem), hbox);
gtk_widget_show(hbox);
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
wcolor_box = gtk_preview_new(GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
fill_preview_with_thumb(wcolor_box,
channels[j],
MENU_THUMBNAIL_WIDTH,
MENU_THUMBNAIL_HEIGHT);
gtk_widget_set_usize( GTK_WIDGET (wcolor_box) ,
MENU_THUMBNAIL_WIDTH ,
MENU_THUMBNAIL_HEIGHT);
gtk_container_add(GTK_CONTAINER(vbox), wcolor_box);
gtk_widget_show(wcolor_box);
wlabel = gtk_label_new(label);
gtk_misc_set_alignment(GTK_MISC(wlabel), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), wlabel, TRUE, TRUE, 4);
gtk_widget_show(wlabel);
gtk_menu_append (GTK_MENU (menu), menuitem);
gtk_widget_show (menuitem);
@ -441,6 +588,107 @@ gimp_menu_callback (GtkWidget *w,
(* callback) (*id, callback_data);
}
static void
fill_preview_with_thumb(GtkWidget *w,gint32 drawableId,gint width,gint height)
{
guchar *drawable_data;
gint bpp;
bpp = 0; /* Only returned */
drawable_data = gimp_drawable_get_thumbnail_data(drawableId,&width,&height,&bpp);
gtk_preview_size(GTK_PREVIEW(w),width,height);
/* First greyscale and non-alpha */
if(bpp < 4)
{
guchar *buf;
guchar *src;
gint x,y;
/* Draw the image */
buf = g_new (gchar, width * 3);
src = drawable_data;
for (y = 0; y < height; y++)
{
if (bpp == 1)
for (x = 0; x < width; x++)
{
buf[x*3+0] = src[x];
buf[x*3+1] = src[x];
buf[x*3+2] = src[x];
}
else
for (x = 0; x < width; x++)
{
buf[x*3+0] = src[x*3+0];
buf[x*3+1] = src[x*3+1];
buf[x*3+2] = src[x*3+2];
}
gtk_preview_draw_row (GTK_PREVIEW (w), (guchar *)buf, 0, y, width);
src += width * bpp;
}
g_free(buf);
}
else /* Has alpha channel */
{
gint x,y;
guchar *src;
gdouble r, g, b, a;
gdouble c0, c1;
guchar *p0, *p1,*even,*odd;
/* Draw the thumbnail with checks */
src = drawable_data;
even = g_malloc(width*3);
odd = g_malloc(width*3);
for (y = 0; y < height; y++)
{
p0 = even;
p1 = odd;
for (x = 0; x < width; x++) {
r = ((gdouble)src[x*4+0])/255.0;
g = ((gdouble)src[x*4+1])/255.0;
b = ((gdouble)src[x*4+2])/255.0;
a = ((gdouble)src[x*4+3])/255.0;
if ((x / GRAD_CHECK_SIZE_SM) & 1) {
c0 = GRAD_CHECK_LIGHT;
c1 = GRAD_CHECK_DARK;
} else {
c0 = GRAD_CHECK_DARK;
c1 = GRAD_CHECK_LIGHT;
} /* else */
*p0++ = (c0 + (r - c0) * a) * 255.0;
*p0++ = (c0 + (g - c0) * a) * 255.0;
*p0++ = (c0 + (b - c0) * a) * 255.0;
*p1++ = (c1 + (r - c1) * a) * 255.0;
*p1++ = (c1 + (g - c1) * a) * 255.0;
*p1++ = (c1 + (b - c1) * a) * 255.0;
} /* for */
if ((y / GRAD_CHECK_SIZE_SM) & 1)
{
gtk_preview_draw_row (GTK_PREVIEW (w), (guchar *)odd, 0, y, width);
}
else
{
gtk_preview_draw_row (GTK_PREVIEW (w), (guchar *)even, 0, y, width);
}
src += width * bpp;
}
g_free(even);
g_free(odd);
}
}
/* These functions allow the callback PDB work with gtk
* ALT.
@ -734,7 +982,6 @@ gen_temp_plugin_name (void)
return result;
}
/* Can only be used in conjuction with gdk since we need to tie into the input
* selection mech.
*/

View File

@ -426,6 +426,91 @@ HELP
%invoke = ( code => 'gimp_drawable_set_gimage (drawable, gimage);' );
}
sub dim_args () {
my @args;
foreach (qw(width height bpp)) {
push @args, { name => $_, type => 'int32', desc => "The previews $_", init => 1 };
}
@args;
}
sub drawable_thumbnail {
$blurb = 'Get a thumbnail of a drawable.';
$help = <<'HELP';
This function gets data from which a thumbnail of a drawable preview can be
created. Maximum x or y dimension is 128 pixels. The pixles are returned
in the RGB[A] format. The bpp return value gives the number of bytes in
the image. The alpha channel also returned if the drawable has one.
HELP
$author = $copyright = 'Andy Thomas';
$date = '1999';
@inargs = (
{ name => 'drawable',
type => 'drawable',
desc => 'The drawable' },
{ name => 'width', type => '0 < int32',
desc => 'The thumbnail width',
alias => 'req_width' },
{ name => 'height', type => '0 < int32',
desc => 'The thumbnail height',
alias => 'req_height' }
);
@outargs = (
&dim_args,
{ name => 'thumbnail_data', type => 'int8array',
desc => 'The thumbnail data', init => 1,
array => { name => 'thumbnail_data_count',
desc => 'The number of pixels in thumbnail data',
alias => 'num_pixels', init => 1 } }
);
%invoke = (
headers => [ qw(<glib.h> <string.h>) ],
code => <<'CODE'
{
TempBuf * buf;
gint dwidth,dheight;
if(req_width <= 128 && req_height <= 128)
{
/* Adjust the width/height ratio */
dwidth = drawable_width(GIMP_DRAWABLE(drawable));
dheight = drawable_height(GIMP_DRAWABLE(drawable));
if(dwidth > dheight)
{
req_height = (req_width*dheight)/dwidth;
}
else
{
req_width = (req_height*dwidth)/dheight;
}
if(GIMP_IS_LAYER(drawable))
buf = layer_preview(GIMP_LAYER(drawable),req_width,req_height);
else
buf = channel_preview(GIMP_CHANNEL(drawable),req_width,req_height);
num_pixels = buf->height * buf->width * buf->bytes;
thumbnail_data = (gint8 *)g_new (gint8, num_pixels);
g_memmove (thumbnail_data, temp_buf_data (buf), num_pixels);
width = buf->width;
height = buf->height;
bpp = buf->bytes;
}
}
CODE
);
}
@headers = qw("drawable.h");
@procs = qw(drawable_merge_shadow drawable_fill drawable_update
@ -434,7 +519,7 @@ HELP
drawable_gray drawable_indexed drawable_bytes drawable_width
drawable_height drawable_offsets drawable_layer
drawable_layer_mask drawable_channel drawable_get_pixel
drawable_set_pixel drawable_set_image);
drawable_set_pixel drawable_set_image drawable_thumbnail);
%exports = (app => [@procs], lib => [@procs]);
$desc = 'Drawable procedures';

View File

@ -1184,6 +1184,84 @@ CODE
SUB
}
sub preview_dim_args () {
my @args;
foreach (qw(width height bpp)) {
push @args, { name => $_, type => 'int32', desc => "The previews $_", init => 1 };
}
@args;
}
sub image_thumbnail {
$blurb = 'Get a thumbnail of an image.';
$help = <<'HELP';
This function gets data from which a thumbnail of an image preview can be
created. Maximum x or y dimension is 128 pixels. The pixles are returned
in the RGB[A] format. The bpp return value gives the number of bytes in
the image. The alpha channel also returned if the image has one.
HELP
$author = $copyright = 'Andy Thomas';
$date = '1999';
@inargs = (
&std_image_arg,
{ name => 'width', type => '0 < int32',
desc => 'The thumbnail width',
alias => 'req_width' },
{ name => 'height', type => '0 < int32',
desc => 'The thumbnail height',
alias => 'req_height' }
);
@outargs = (
&preview_dim_args,
{ name => 'thumbnail_data', type => 'int8array',
desc => 'The thumbnail data', init => 1,
array => { name => 'thumbnail_data_count',
desc => 'The number of pixels in thumbnail data',
alias => 'num_pixels', init => 1 } }
);
%invoke = (
headers => [ qw(<glib.h> <string.h>) ],
code => <<'CODE'
{
TempBuf * buf;
gint dwidth,dheight;
if(req_width <= 128 && req_height <= 128)
{
/* Adjust the width/height ratio */
dwidth = gimage->width;
dheight = gimage->height;
if(dwidth > dheight)
{
req_height = (req_width*dheight)/dwidth;
}
else
{
req_width = (req_height*dwidth)/dheight;
}
buf = gimp_image_construct_composite_preview(gimage,req_width,req_height);
num_pixels = buf->height * buf->width * buf->bytes;
thumbnail_data = (gint8 *)g_new (gint8, num_pixels);
g_memmove (thumbnail_data, temp_buf_data (buf), num_pixels);
width = buf->width;
height = buf->height;
bpp = buf->bytes;
}
}
CODE
);
}
@headers = qw(<string.h> "gimage.h");
$extra{app}->{code} = <<'CODE';
@ -1210,7 +1288,7 @@ unshift @procs, qw(list_images image_new image_resize image_scale image_delete
image_active_drawable image_base_type image_get_cmap
image_set_cmap image_enable_undo image_disable_undo
image_clean_all image_floating_selection
image_floating_sel_attached_to);
image_floating_sel_attached_to image_thumbnail);
%exports = (app => [@procs]);
$desc = 'Image';

View File

@ -1184,6 +1184,84 @@ CODE
SUB
}
sub preview_dim_args () {
my @args;
foreach (qw(width height bpp)) {
push @args, { name => $_, type => 'int32', desc => "The previews $_", init => 1 };
}
@args;
}
sub image_thumbnail {
$blurb = 'Get a thumbnail of an image.';
$help = <<'HELP';
This function gets data from which a thumbnail of an image preview can be
created. Maximum x or y dimension is 128 pixels. The pixles are returned
in the RGB[A] format. The bpp return value gives the number of bytes in
the image. The alpha channel also returned if the image has one.
HELP
$author = $copyright = 'Andy Thomas';
$date = '1999';
@inargs = (
&std_image_arg,
{ name => 'width', type => '0 < int32',
desc => 'The thumbnail width',
alias => 'req_width' },
{ name => 'height', type => '0 < int32',
desc => 'The thumbnail height',
alias => 'req_height' }
);
@outargs = (
&preview_dim_args,
{ name => 'thumbnail_data', type => 'int8array',
desc => 'The thumbnail data', init => 1,
array => { name => 'thumbnail_data_count',
desc => 'The number of pixels in thumbnail data',
alias => 'num_pixels', init => 1 } }
);
%invoke = (
headers => [ qw(<glib.h> <string.h>) ],
code => <<'CODE'
{
TempBuf * buf;
gint dwidth,dheight;
if(req_width <= 128 && req_height <= 128)
{
/* Adjust the width/height ratio */
dwidth = gimage->width;
dheight = gimage->height;
if(dwidth > dheight)
{
req_height = (req_width*dheight)/dwidth;
}
else
{
req_width = (req_height*dwidth)/dheight;
}
buf = gimp_image_construct_composite_preview(gimage,req_width,req_height);
num_pixels = buf->height * buf->width * buf->bytes;
thumbnail_data = (gint8 *)g_new (gint8, num_pixels);
g_memmove (thumbnail_data, temp_buf_data (buf), num_pixels);
width = buf->width;
height = buf->height;
bpp = buf->bytes;
}
}
CODE
);
}
@headers = qw(<string.h> "gimage.h");
$extra{app}->{code} = <<'CODE';
@ -1210,7 +1288,7 @@ unshift @procs, qw(list_images image_new image_resize image_scale image_delete
image_active_drawable image_base_type image_get_cmap
image_set_cmap image_enable_undo image_disable_undo
image_clean_all image_floating_selection
image_floating_sel_attached_to);
image_floating_sel_attached_to image_thumbnail);
%exports = (app => [@procs]);
$desc = 'Image';