1997-11-25 06:05:25 +08:00
/* The GIMP -- an image manipulation program
* Copyright ( C ) 1995 Spencer Kimball and Peter Mattis
*
* 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
1998-04-13 13:44:11 +08:00
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
1997-11-25 06:05:25 +08:00
*/
/*
* This filter tiles an image to arbitrary width and height
*/
2000-01-26 01:46:56 +08:00
# include "config.h"
1997-11-25 06:05:25 +08:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2000-01-09 04:00:10 +08:00
# include <gtk/gtk.h>
# include <libgimp/gimp.h>
# include <libgimp/gimpui.h>
1997-11-25 06:05:25 +08:00
2000-01-26 01:46:56 +08:00
# include "libgimp/stdplugins-intl.h"
1997-11-25 06:05:25 +08:00
2000-01-26 01:46:56 +08:00
typedef struct
{
1997-11-25 06:05:25 +08:00
gint new_width ;
gint new_height ;
gint constrain ;
gint new_image ;
} TileVals ;
2000-01-26 01:46:56 +08:00
typedef struct
{
2000-02-03 01:59:44 +08:00
GtkWidget * sizeentry ;
GtkWidget * chainbutton ;
2000-01-26 01:46:56 +08:00
gint run ;
1997-11-25 06:05:25 +08:00
} TileInterface ;
/* Declare a local function.
*/
static void query ( void ) ;
2000-01-26 01:46:56 +08:00
static void run ( gchar * name ,
gint nparams ,
1997-11-25 06:05:25 +08:00
GParam * param ,
2000-01-26 01:46:56 +08:00
gint * nreturn_vals ,
1997-11-25 06:05:25 +08:00
GParam * * return_vals ) ;
2000-01-26 01:46:56 +08:00
1997-11-25 06:05:25 +08:00
static gint32 tile ( gint32 image_id ,
gint32 drawable_id ,
gint32 * layer_id ) ;
2000-02-03 01:59:44 +08:00
static gint tile_dialog ( gint32 image_ID ,
gint32 drawable_ID ) ;
1997-11-25 06:05:25 +08:00
2000-01-26 01:46:56 +08:00
static void tile_ok_callback ( GtkWidget * widget ,
gpointer data ) ;
1997-11-25 06:05:25 +08:00
GPlugInInfo PLUG_IN_INFO =
{
2000-01-26 01:46:56 +08:00
NULL , /* init_proc */
NULL , /* quit_proc */
query , /* query_proc */
run , /* run_proc */
1997-11-25 06:05:25 +08:00
} ;
static TileVals tvals =
{
2000-01-26 01:46:56 +08:00
1 , /* new_width */
1 , /* new_height */
TRUE , /* constrain */
TRUE /* new_image */
1997-11-25 06:05:25 +08:00
} ;
static TileInterface tint =
{
2000-02-03 01:59:44 +08:00
NULL , /* sizeentry */
FALSE /* run */
1997-11-25 06:05:25 +08:00
} ;
MAIN ( )
static void
2000-01-26 01:46:56 +08:00
query ( void )
1997-11-25 06:05:25 +08:00
{
static GParamDef args [ ] =
{
{ PARAM_INT32 , " run_mode " , " Interactive, non-interactive " } ,
{ PARAM_IMAGE , " image " , " Input image (unused) " } ,
{ PARAM_DRAWABLE , " drawable " , " Input drawable " } ,
{ PARAM_INT32 , " new_width " , " New (tiled) image width " } ,
{ PARAM_INT32 , " new_height " , " New (tiled) image height " } ,
{ PARAM_INT32 , " new_image " , " Create a new image? " } ,
} ;
static GParamDef return_vals [ ] =
{
1998-10-07 10:55:17 +08:00
{ PARAM_IMAGE , " new_image " , " Output image (N/A if new_image == FALSE) " } ,
{ PARAM_LAYER , " new_layer " , " Output layer (N/A if new_image == FALSE) " } ,
1997-11-25 06:05:25 +08:00
} ;
2000-01-26 01:46:56 +08:00
static gint nargs = sizeof ( args ) / sizeof ( args [ 0 ] ) ;
static gint nreturn_vals = sizeof ( return_vals ) / sizeof ( return_vals [ 0 ] ) ;
1997-11-25 06:05:25 +08:00
2000-01-09 14:02:20 +08:00
INIT_I18N ( ) ;
1997-11-25 06:05:25 +08:00
gimp_install_procedure ( " plug_in_tile " ,
2000-01-31 10:32:30 +08:00
" Create a new image which is a tiled version of the input drawable " ,
" This function creates a new image with a single layer sized to the specified 'new_width' and 'new_height' parameters. The specified drawable is tiled into this layer. The new layer will have the same type as the specified drawable and the new image will have a corresponding base type " ,
1997-11-25 06:05:25 +08:00
" Spencer Kimball & Peter Mattis " ,
" Spencer Kimball & Peter Mattis " ,
" 1996-1997 " ,
2000-01-09 14:02:20 +08:00
N_ ( " <Image>/Filters/Map/Tile... " ) ,
1997-11-25 06:05:25 +08:00
" RGB*, GRAY*, INDEXED* " ,
PROC_PLUG_IN ,
nargs , nreturn_vals ,
args , return_vals ) ;
}
static void
2000-01-26 01:46:56 +08:00
run ( gchar * name ,
gint nparams ,
1997-11-25 06:05:25 +08:00
GParam * param ,
2000-01-26 01:46:56 +08:00
gint * nreturn_vals ,
1997-11-25 06:05:25 +08:00
GParam * * return_vals )
{
static GParam values [ 3 ] ;
2000-01-26 01:46:56 +08:00
GRunModeType run_mode ;
GStatusType status = STATUS_SUCCESS ;
gint32 new_layer ;
gint width , height ;
1997-11-25 06:05:25 +08:00
run_mode = param [ 0 ] . data . d_int32 ;
* nreturn_vals = 3 ;
* return_vals = values ;
values [ 0 ] . type = PARAM_STATUS ;
values [ 0 ] . data . d_status = status ;
values [ 1 ] . type = PARAM_IMAGE ;
1998-10-07 10:55:17 +08:00
values [ 2 ] . type = PARAM_LAYER ;
1997-11-25 06:05:25 +08:00
2000-02-03 01:59:44 +08:00
width = gimp_drawable_width ( param [ 2 ] . data . d_drawable ) ;
1997-11-25 06:05:25 +08:00
height = gimp_drawable_height ( param [ 2 ] . data . d_drawable ) ;
switch ( run_mode )
{
case RUN_INTERACTIVE :
2000-01-09 14:02:20 +08:00
INIT_I18N_UI ( ) ;
1997-11-25 06:05:25 +08:00
/* Possibly retrieve data */
gimp_get_data ( " plug_in_tile " , & tvals ) ;
/* First acquire information with a dialog */
2000-02-03 01:59:44 +08:00
if ( ! tile_dialog ( param [ 1 ] . data . d_image ,
param [ 2 ] . data . d_drawable ) )
1997-11-25 06:05:25 +08:00
return ;
break ;
case RUN_NONINTERACTIVE :
2000-01-09 14:02:20 +08:00
INIT_I18N ( ) ;
1997-11-25 06:05:25 +08:00
/* Make sure all the arguments are there! */
if ( nparams ! = 6 )
{
2000-02-03 01:59:44 +08:00
status = STATUS_CALLING_ERROR ;
}
else
{
tvals . new_width = param [ 3 ] . data . d_int32 ;
1997-11-25 06:05:25 +08:00
tvals . new_height = param [ 4 ] . data . d_int32 ;
2000-02-03 01:59:44 +08:00
tvals . new_image = param [ 5 ] . data . d_int32 ? TRUE : FALSE ;
if ( tvals . new_width < 0 | | tvals . new_height < 0 )
status = STATUS_CALLING_ERROR ;
1997-11-25 06:05:25 +08:00
}
break ;
case RUN_WITH_LAST_VALS :
2000-01-09 14:02:20 +08:00
INIT_I18N ( ) ;
1997-11-25 06:05:25 +08:00
/* Possibly retrieve data */
gimp_get_data ( " plug_in_tile " , & tvals ) ;
break ;
default :
break ;
}
/* Make sure that the drawable is gray or RGB color */
if ( status = = STATUS_SUCCESS )
{
2000-02-03 01:59:44 +08:00
gimp_progress_init ( _ ( " Tiling... " ) ) ;
1997-11-25 06:05:25 +08:00
gimp_tile_cache_ntiles ( 2 * ( width + 1 ) / gimp_tile_width ( ) ) ;
2000-02-03 01:59:44 +08:00
values [ 1 ] . data . d_image = tile ( param [ 1 ] . data . d_image ,
param [ 2 ] . data . d_drawable ,
& new_layer ) ;
1997-11-25 06:05:25 +08:00
values [ 2 ] . data . d_layer = new_layer ;
/* Store data */
if ( run_mode = = RUN_INTERACTIVE )
gimp_set_data ( " plug_in_tile " , & tvals , sizeof ( TileVals ) ) ;
if ( run_mode ! = RUN_NONINTERACTIVE )
{
if ( tvals . new_image )
gimp_display_new ( values [ 1 ] . data . d_image ) ;
else
gimp_displays_flush ( ) ;
}
}
values [ 0 ] . data . d_status = status ;
}
static gint32
2000-01-26 01:46:56 +08:00
tile ( gint32 image_id ,
gint32 drawable_id ,
gint32 * layer_id )
1997-11-25 06:05:25 +08:00
{
GPixelRgn src_rgn , dest_rgn ;
GDrawable * drawable , * new_layer ;
GImageType image_type ;
gint32 new_image_id ;
gint old_width , old_height ;
gint width , height ;
gint i , j , k ;
gint progress , max_progress ;
gint nreturn_vals ;
gpointer pr ;
/* initialize */
image_type = RGB ;
new_image_id = 0 ;
2000-02-03 01:59:44 +08:00
old_width = gimp_drawable_width ( drawable_id ) ;
1997-11-25 06:05:25 +08:00
old_height = gimp_drawable_height ( drawable_id ) ;
if ( tvals . new_image )
{
/* create a new image */
switch ( gimp_drawable_type ( drawable_id ) )
{
case RGB_IMAGE : case RGBA_IMAGE :
image_type = RGB ;
break ;
case GRAY_IMAGE : case GRAYA_IMAGE :
image_type = GRAY ;
break ;
case INDEXED_IMAGE : case INDEXEDA_IMAGE :
image_type = INDEXED ;
break ;
}
2000-01-26 01:46:56 +08:00
new_image_id = gimp_image_new ( tvals . new_width , tvals . new_height ,
image_type ) ;
2000-01-09 14:02:20 +08:00
* layer_id = gimp_layer_new ( new_image_id , _ ( " Background " ) ,
1997-11-25 06:05:25 +08:00
tvals . new_width , tvals . new_height ,
gimp_drawable_type ( drawable_id ) ,
100 , NORMAL_MODE ) ;
gimp_image_add_layer ( new_image_id , * layer_id , 0 ) ;
new_layer = gimp_drawable_get ( * layer_id ) ;
/* Get the specified drawable */
drawable = gimp_drawable_get ( drawable_id ) ;
}
else
{
2000-01-26 01:46:56 +08:00
gimp_undo_push_group_start ( image_id ) ;
1997-11-25 06:05:25 +08:00
gimp_run_procedure ( " gimp_image_resize " , & nreturn_vals ,
PARAM_IMAGE , image_id ,
PARAM_INT32 , tvals . new_width ,
PARAM_INT32 , tvals . new_height ,
PARAM_INT32 , 0 ,
PARAM_INT32 , 0 ,
PARAM_END ) ;
1999-10-17 08:07:55 +08:00
if ( gimp_drawable_is_layer ( drawable_id ) )
1997-11-25 06:05:25 +08:00
gimp_run_procedure ( " gimp_layer_resize " , & nreturn_vals ,
PARAM_LAYER , drawable_id ,
PARAM_INT32 , tvals . new_width ,
PARAM_INT32 , tvals . new_height ,
PARAM_INT32 , 0 ,
PARAM_INT32 , 0 ,
PARAM_END ) ;
/* Get the specified drawable */
drawable = gimp_drawable_get ( drawable_id ) ;
new_layer = drawable ;
}
/* progress */
progress = 0 ;
max_progress = tvals . new_width * tvals . new_height ;
/* tile... */
for ( i = 0 ; i < tvals . new_height ; i + = old_height )
{
height = old_height ;
if ( height + i > tvals . new_height )
height = tvals . new_height - i ;
for ( j = 0 ; j < tvals . new_width ; j + = old_width )
{
width = old_width ;
if ( width + j > tvals . new_width )
width = tvals . new_width - j ;
gimp_pixel_rgn_init ( & src_rgn , drawable , 0 , 0 , width , height , FALSE , FALSE ) ;
gimp_pixel_rgn_init ( & dest_rgn , new_layer , j , i , width , height , TRUE , FALSE ) ;
for ( pr = gimp_pixel_rgns_register ( 2 , & src_rgn , & dest_rgn ) ; pr ! = NULL ;
pr = gimp_pixel_rgns_process ( pr ) )
{
for ( k = 0 ; k < src_rgn . h ; k + + )
memcpy ( dest_rgn . data + k * dest_rgn . rowstride ,
src_rgn . data + k * src_rgn . rowstride ,
src_rgn . w * src_rgn . bpp ) ;
progress + = src_rgn . w * src_rgn . h ;
gimp_progress_update ( ( double ) progress / ( double ) max_progress ) ;
}
}
}
/* copy the colormap, if necessary */
if ( image_type = = INDEXED & & tvals . new_image )
{
2000-02-03 01:59:44 +08:00
gint ncols ;
1997-11-25 06:05:25 +08:00
guchar * cmap ;
cmap = gimp_image_get_cmap ( image_id , & ncols ) ;
gimp_image_set_cmap ( new_image_id , cmap , ncols ) ;
g_free ( cmap ) ;
}
if ( tvals . new_image )
{
gimp_drawable_flush ( new_layer ) ;
gimp_drawable_detach ( new_layer ) ;
}
else
gimp_run_procedure ( " gimp_undo_push_group_end " , & nreturn_vals ,
PARAM_IMAGE , image_id ,
PARAM_END ) ;
gimp_drawable_flush ( drawable ) ;
gimp_drawable_detach ( drawable ) ;
return new_image_id ;
}
static gint
2000-02-03 01:59:44 +08:00
tile_dialog ( gint32 image_ID ,
gint32 drawable_ID )
1997-11-25 06:05:25 +08:00
{
GtkWidget * dlg ;
GtkWidget * frame ;
2000-02-03 01:59:44 +08:00
GtkWidget * sizeentry ;
2000-01-26 01:46:56 +08:00
GtkWidget * toggle ;
2000-02-03 01:59:44 +08:00
gint width ;
gint height ;
gdouble xres ;
gdouble yres ;
2000-02-08 04:35:13 +08:00
GimpUnit unit ;
2000-02-03 01:59:44 +08:00
gchar * * argv ;
gint argc ;
1997-11-25 06:05:25 +08:00
2000-01-09 04:00:10 +08:00
argc = 1 ;
argv = g_new ( gchar * , 1 ) ;
1997-11-25 06:05:25 +08:00
argv [ 0 ] = g_strdup ( " tile " ) ;
gtk_init ( & argc , & argv ) ;
gtk_rc_parse ( gimp_gtkrc ( ) ) ;
2000-02-03 01:59:44 +08:00
width = gimp_drawable_width ( drawable_ID ) ;
height = gimp_drawable_height ( drawable_ID ) ;
unit = gimp_image_get_unit ( image_ID ) ;
gimp_image_get_resolution ( image_ID , & xres , & yres ) ;
2000-01-26 01:46:56 +08:00
tvals . new_width = width ;
1997-11-25 06:05:25 +08:00
tvals . new_height = height ;
2000-02-03 01:59:44 +08:00
dlg = gimp_dialog_new ( _ ( " Tile " ) , " tile " ,
2000-01-09 04:00:10 +08:00
gimp_plugin_help_func , " filters/tile.html " ,
GTK_WIN_POS_MOUSE ,
FALSE , TRUE , FALSE ,
2000-01-09 14:02:20 +08:00
_ ( " OK " ) , tile_ok_callback ,
2000-01-09 04:00:10 +08:00
NULL , NULL , NULL , TRUE , FALSE ,
2000-01-09 14:02:20 +08:00
_ ( " Cancel " ) , gtk_widget_destroy ,
2000-01-09 04:00:10 +08:00
NULL , 1 , NULL , FALSE , TRUE ,
NULL ) ;
1997-11-25 06:05:25 +08:00
gtk_signal_connect ( GTK_OBJECT ( dlg ) , " destroy " ,
2000-01-09 04:00:10 +08:00
GTK_SIGNAL_FUNC ( gtk_main_quit ) ,
1997-11-25 06:05:25 +08:00
NULL ) ;
/* parameter settings */
2000-01-26 01:46:56 +08:00
frame = gtk_frame_new ( _ ( " Tile to New Size " ) ) ;
1997-11-25 06:05:25 +08:00
gtk_frame_set_shadow_type ( GTK_FRAME ( frame ) , GTK_SHADOW_ETCHED_IN ) ;
2000-01-09 04:00:10 +08:00
gtk_container_set_border_width ( GTK_CONTAINER ( frame ) , 6 ) ;
1997-11-25 06:05:25 +08:00
gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG ( dlg ) - > vbox ) , frame , TRUE , TRUE , 0 ) ;
2000-02-03 01:59:44 +08:00
gtk_widget_show ( frame ) ;
sizeentry = gimp_coordinates_new ( unit , " %a " , TRUE , TRUE , 75 ,
GIMP_SIZE_ENTRY_UPDATE_SIZE ,
2000-02-23 23:52:33 +08:00
tvals . constrain , TRUE ,
2000-02-03 01:59:44 +08:00
_ ( " Width: " ) , width , xres ,
1 , GIMP_MAX_IMAGE_SIZE ,
0 , width ,
1997-11-25 06:05:25 +08:00
2000-02-03 01:59:44 +08:00
_ ( " Height: " ) , height , yres ,
1 , GIMP_MAX_IMAGE_SIZE ,
0 , height ) ;
gtk_container_set_border_width ( GTK_CONTAINER ( sizeentry ) , 4 ) ;
gtk_container_add ( GTK_CONTAINER ( frame ) , sizeentry ) ;
gtk_table_set_row_spacing ( GTK_TABLE ( sizeentry ) , 1 , 4 ) ;
gtk_widget_show ( sizeentry ) ;
tint . sizeentry = sizeentry ;
2000-02-23 23:52:33 +08:00
tint . chainbutton = GTK_WIDGET ( GIMP_COORDINATES_CHAINBUTTON ( sizeentry ) ) ;
2000-02-03 01:59:44 +08:00
toggle = gtk_check_button_new_with_label ( _ ( " Create New Image " ) ) ;
gtk_table_attach ( GTK_TABLE ( sizeentry ) , toggle , 0 , 4 , 2 , 3 ,
2000-01-09 04:00:10 +08:00
GTK_EXPAND | GTK_FILL , GTK_FILL , 0 , 0 ) ;
1997-11-25 06:05:25 +08:00
gtk_signal_connect ( GTK_OBJECT ( toggle ) , " toggled " ,
2000-01-26 01:46:56 +08:00
GTK_SIGNAL_FUNC ( gimp_toggle_button_update ) ,
1997-11-25 06:05:25 +08:00
& tvals . new_image ) ;
1999-01-16 01:35:04 +08:00
gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON ( toggle ) , tvals . new_image ) ;
1997-11-25 06:05:25 +08:00
gtk_widget_show ( toggle ) ;
gtk_widget_show ( dlg ) ;
gtk_main ( ) ;
gdk_flush ( ) ;
return tint . run ;
}
static void
tile_ok_callback ( GtkWidget * widget ,
gpointer data )
{
2000-02-03 01:59:44 +08:00
tvals . new_width =
gimp_size_entry_get_refval ( GIMP_SIZE_ENTRY ( tint . sizeentry ) , 0 ) ;
tvals . new_height =
gimp_size_entry_get_refval ( GIMP_SIZE_ENTRY ( tint . sizeentry ) , 1 ) ;
2000-01-26 01:46:56 +08:00
2000-02-03 01:59:44 +08:00
tvals . constrain =
gimp_chain_button_get_active ( GIMP_CHAIN_BUTTON ( tint . chainbutton ) ) ;
1997-11-25 06:05:25 +08:00
2000-02-03 01:59:44 +08:00
tint . run = TRUE ;
2000-01-26 01:46:56 +08:00
2000-02-03 01:59:44 +08:00
gtk_widget_destroy ( GTK_WIDGET ( data ) ) ;
1997-11-25 06:05:25 +08:00
}