mirror of https://github.com/GNOME/gimp.git
541 lines
11 KiB
C
541 lines
11 KiB
C
|
/* 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
|
||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*/
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#include "appenv.h"
|
||
|
#include "channel.h"
|
||
|
#include "drawable.h"
|
||
|
#include "errors.h"
|
||
|
#include "floating_sel.h"
|
||
|
#include "gimage.h"
|
||
|
#include "gimage_mask.h"
|
||
|
#include "gdisplay.h"
|
||
|
#include "layer.h"
|
||
|
#include "linked.h"
|
||
|
#include "palette.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Static variables
|
||
|
*/
|
||
|
int global_drawable_ID = 1;
|
||
|
|
||
|
/**************************/
|
||
|
/* Function definitions */
|
||
|
|
||
|
void
|
||
|
drawable_apply_image (drawable_id, x1, y1, x2, y2, tiles, sparse)
|
||
|
int drawable_id;
|
||
|
int x1, y1;
|
||
|
int x2, y2;
|
||
|
TileManager *tiles;
|
||
|
int sparse;
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
channel_apply_image (channel, x1, y1, x2, y2, tiles, sparse);
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
layer_apply_image (layer, x1, y1, x2, y2, tiles, sparse);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
drawable_merge_shadow (drawable_id, undo)
|
||
|
int drawable_id;
|
||
|
int undo;
|
||
|
{
|
||
|
GImage *gimage;
|
||
|
PixelRegion shadowPR;
|
||
|
int x1, y1, x2, y2;
|
||
|
|
||
|
if (! (gimage = drawable_gimage (drawable_id)))
|
||
|
return;
|
||
|
|
||
|
/* A useful optimization here is to limit the update to the
|
||
|
* extents of the selection mask, as it cannot extend beyond
|
||
|
* them.
|
||
|
*/
|
||
|
drawable_mask_bounds (drawable_id, &x1, &y1, &x2, &y2);
|
||
|
pixel_region_init (&shadowPR, gimage->shadow, x1, y1,
|
||
|
(x2 - x1), (y2 - y1), FALSE);
|
||
|
gimage_apply_image (gimage, drawable_id, &shadowPR, undo, OPAQUE,
|
||
|
REPLACE_MODE, NULL, x1, y1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
drawable_fill (drawable_id, fill_type)
|
||
|
int drawable_id;
|
||
|
int fill_type;
|
||
|
{
|
||
|
GImage *gimage;
|
||
|
PixelRegion destPR;
|
||
|
unsigned char c[MAX_CHANNELS];
|
||
|
unsigned char i, r, g, b, a;
|
||
|
|
||
|
if (! (gimage = drawable_gimage (drawable_id)))
|
||
|
return;
|
||
|
|
||
|
a = 255;
|
||
|
|
||
|
/* a gimage_fill affects the active layer */
|
||
|
switch (fill_type)
|
||
|
{
|
||
|
case BACKGROUND_FILL:
|
||
|
palette_get_background (&r, &g, &b);
|
||
|
a = 255;
|
||
|
break;
|
||
|
case WHITE_FILL:
|
||
|
a = r = g = b = 255;
|
||
|
break;
|
||
|
case TRANSPARENT_FILL:
|
||
|
r = g = b = a = 0;
|
||
|
break;
|
||
|
case NO_FILL:
|
||
|
return;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (drawable_type (drawable_id))
|
||
|
{
|
||
|
case RGB_GIMAGE: case RGBA_GIMAGE:
|
||
|
c[RED_PIX] = r;
|
||
|
c[GREEN_PIX] = g;
|
||
|
c[BLUE_PIX] = b;
|
||
|
if (drawable_type (drawable_id) == RGBA_GIMAGE)
|
||
|
c[ALPHA_PIX] = a;
|
||
|
break;
|
||
|
case GRAY_GIMAGE: case GRAYA_GIMAGE:
|
||
|
c[GRAY_PIX] = r;
|
||
|
if (drawable_type (drawable_id) == GRAYA_GIMAGE)
|
||
|
c[ALPHA_G_PIX] = a;
|
||
|
break;
|
||
|
case INDEXED_GIMAGE: case INDEXEDA_GIMAGE:
|
||
|
c[RED_PIX] = r;
|
||
|
c[GREEN_PIX] = g;
|
||
|
c[BLUE_PIX] = b;
|
||
|
gimage_transform_color (gimage, drawable_id, c, &i, RGB);
|
||
|
c[INDEXED_PIX] = i;
|
||
|
if (drawable_type (drawable_id) == INDEXEDA_GIMAGE)
|
||
|
c[ALPHA_I_PIX] = a;
|
||
|
break;
|
||
|
default:
|
||
|
warning ("Can't fill unknown image type.");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pixel_region_init (&destPR,
|
||
|
drawable_data (drawable_id),
|
||
|
0, 0,
|
||
|
drawable_width (drawable_id),
|
||
|
drawable_height (drawable_id),
|
||
|
TRUE);
|
||
|
color_region (&destPR, c);
|
||
|
|
||
|
/* Update the filled area */
|
||
|
drawable_update (drawable_id, 0, 0,
|
||
|
drawable_width (drawable_id),
|
||
|
drawable_height (drawable_id));
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
drawable_update (drawable_id, x, y, w, h)
|
||
|
int drawable_id;
|
||
|
int x, y;
|
||
|
int w, h;
|
||
|
{
|
||
|
GImage *gimage;
|
||
|
int offset_x, offset_y;
|
||
|
|
||
|
if (! (gimage = drawable_gimage (drawable_id)))
|
||
|
return;
|
||
|
|
||
|
drawable_offsets (drawable_id, &offset_x, &offset_y);
|
||
|
x += offset_x;
|
||
|
y += offset_y;
|
||
|
gdisplays_update_area (gimage->ID, x, y, w, h);
|
||
|
|
||
|
/* invalidate the preview */
|
||
|
drawable_invalidate_preview (drawable_id);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_mask_bounds (drawable_id, x1, y1, x2, y2)
|
||
|
int drawable_id;
|
||
|
int *x1, *y1;
|
||
|
int *x2, *y2;
|
||
|
{
|
||
|
GImage *gimage;
|
||
|
int off_x, off_y;
|
||
|
|
||
|
if (! (gimage = drawable_gimage (drawable_id)))
|
||
|
return FALSE;
|
||
|
|
||
|
if (gimage_mask_bounds (gimage, x1, y1, x2, y2))
|
||
|
{
|
||
|
drawable_offsets (drawable_id, &off_x, &off_y);
|
||
|
*x1 = BOUNDS (*x1 - off_x, 0, drawable_width (drawable_id));
|
||
|
*y1 = BOUNDS (*y1 - off_y, 0, drawable_height (drawable_id));
|
||
|
*x2 = BOUNDS (*x2 - off_x, 0, drawable_width (drawable_id));
|
||
|
*y2 = BOUNDS (*y2 - off_y, 0, drawable_height (drawable_id));
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*x2 = drawable_width (drawable_id);
|
||
|
*y2 = drawable_height (drawable_id);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
drawable_invalidate_preview (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
GImage *gimage;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
channel->preview_valid = FALSE;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
{
|
||
|
if (layer_is_floating_sel (layer))
|
||
|
floating_sel_invalidate (layer);
|
||
|
else
|
||
|
layer->preview_valid = FALSE;
|
||
|
}
|
||
|
|
||
|
gimage = drawable_gimage (drawable_id);
|
||
|
if (gimage)
|
||
|
{
|
||
|
gimage->comp_preview_valid[0] = FALSE;
|
||
|
gimage->comp_preview_valid[1] = FALSE;
|
||
|
gimage->comp_preview_valid[2] = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_dirty (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel->dirty = (channel->dirty < 0) ? 2 : channel->dirty + 1;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->dirty = (layer->dirty < 0) ? 2 : layer->dirty + 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_clean (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel->dirty = (channel->dirty <= 0) ? 0 : channel->dirty - 1;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->dirty = (layer->dirty <= 0) ? 0 : layer->dirty - 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
GImage *
|
||
|
drawable_gimage (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return gimage_get_ID (channel->gimage_ID);
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return gimage_get_ID (layer->gimage_ID);
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_type (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return GRAY_GIMAGE;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->type;
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_has_alpha (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return FALSE;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer_has_alpha (layer);
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_type_with_alpha (int drawable_id)
|
||
|
{
|
||
|
int type = drawable_type (drawable_id);
|
||
|
int has_alpha = drawable_has_alpha (drawable_id);
|
||
|
|
||
|
if (has_alpha)
|
||
|
return type;
|
||
|
else
|
||
|
switch (type)
|
||
|
{
|
||
|
case RGB_GIMAGE:
|
||
|
return RGBA_GIMAGE; break;
|
||
|
case GRAY_GIMAGE:
|
||
|
return GRAYA_GIMAGE; break;
|
||
|
case INDEXED_GIMAGE:
|
||
|
return INDEXEDA_GIMAGE; break;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_color (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
if (drawable_type (drawable_id) == RGBA_GIMAGE ||
|
||
|
drawable_type (drawable_id) == RGB_GIMAGE)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_gray (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
if (drawable_type (drawable_id) == GRAYA_GIMAGE ||
|
||
|
drawable_type (drawable_id) == GRAY_GIMAGE)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_indexed (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
if (drawable_type (drawable_id) == INDEXEDA_GIMAGE ||
|
||
|
drawable_type (drawable_id) == INDEXED_GIMAGE)
|
||
|
return 1;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
TileManager *
|
||
|
drawable_data (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel->tiles;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->tiles;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
TileManager *
|
||
|
drawable_shadow (int drawable_id)
|
||
|
{
|
||
|
GImage *gimage;
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if (! (gimage = drawable_gimage (drawable_id)))
|
||
|
return NULL;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
{
|
||
|
return gimage_shadow (gimage, channel->width, channel->height, 1);
|
||
|
}
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
{
|
||
|
return gimage_shadow (gimage, layer->width, layer->height, layer->bytes);
|
||
|
}
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_bytes (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel->bytes;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->bytes;
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_width (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel->width;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->width;
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
drawable_height (int drawable_id)
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel->height;
|
||
|
else if ((layer = layer_get_ID (drawable_id)))
|
||
|
return layer->height;
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
drawable_offsets (drawable_id, off_x, off_y)
|
||
|
int drawable_id;
|
||
|
int *off_x;
|
||
|
int *off_y;
|
||
|
{
|
||
|
Channel *channel;
|
||
|
Layer *layer;
|
||
|
|
||
|
/* return the active layer offsets */
|
||
|
if ((layer = layer_get_ID (drawable_id)))
|
||
|
{
|
||
|
*off_x = layer->offset_x;
|
||
|
*off_y = layer->offset_y;
|
||
|
return;
|
||
|
}
|
||
|
/* The case of a layer mask */
|
||
|
else if ((channel = channel_get_ID (drawable_id)))
|
||
|
{
|
||
|
if (channel->layer_ID != -1)
|
||
|
if ((layer = layer_get_ID (channel->layer_ID)))
|
||
|
{
|
||
|
*off_x = layer->offset_x;
|
||
|
*off_y = layer->offset_y;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*off_x = 0;
|
||
|
*off_y = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
unsigned char *
|
||
|
drawable_cmap (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
GImage *gimage;
|
||
|
|
||
|
if ((gimage = drawable_gimage (drawable_id)))
|
||
|
return gimage->cmap;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
Layer *
|
||
|
drawable_layer (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
Layer *layer;
|
||
|
|
||
|
if ((layer = layer_get_ID (drawable_id)))
|
||
|
if (!layer->mask || (layer->mask && !layer->edit_mask))
|
||
|
return layer;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
Channel *
|
||
|
drawable_layer_mask (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
Channel *channel;
|
||
|
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
if (channel->layer_ID != -1)
|
||
|
return channel;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
Channel *
|
||
|
drawable_channel (drawable_id)
|
||
|
int drawable_id;
|
||
|
{
|
||
|
Channel *channel;
|
||
|
if ((channel = channel_get_ID (drawable_id)))
|
||
|
return channel;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|