123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816 |
- /* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "config.h"
- #include <stdlib.h>
- #include <string.h>
- #include <gtk/gtk.h>
- #include "apptypes.h"
- #include "appenv.h"
- #include "gimprc.h"
- #include "gximage.h"
- #include "image_render.h"
- #include "pixel_region.h"
- #include "scale.h"
- #include "tile.h" /* ick. */
- #include "libgimp/gimpmath.h"
- typedef struct _RenderInfo RenderInfo;
- typedef void (*RenderFunc) (RenderInfo *info);
- struct _RenderInfo
- {
- GDisplay *gdisp;
- TileManager *src_tiles;
- guint *alpha;
- guchar *scale;
- guchar *src;
- guchar *dest;
- int x, y;
- int w, h;
- float scalex;
- float scaley;
- int src_x, src_y;
- int src_bpp;
- int dest_bpp;
- int dest_bpl;
- int dest_width;
- int byte_order;
- };
- /* accelerate transparency of image scaling */
- guchar *blend_dark_check = NULL;
- guchar *blend_light_check = NULL;
- guchar *tile_buf = NULL;
- guchar *check_buf = NULL;
- guchar *empty_buf = NULL;
- guchar *temp_buf = NULL;
- static guint check_mod;
- static guint check_shift;
- static guint tile_shift;
- static guchar check_combos[6][2] =
- {
- { 204, 255 },
- { 102, 153 },
- { 0, 51 },
- { 255, 255 },
- { 127, 127 },
- { 0, 0 }
- };
- void
- render_setup (int check_type,
- int check_size)
- {
- int i, j;
- /* based on the tile size, determine the tile shift amount
- * (assume here that tile_height and tile_width are equal)
- */
- tile_shift = 0;
- while ((1 << tile_shift) < TILE_WIDTH)
- tile_shift++;
- /* allocate a buffer for arranging information from a row of tiles */
- if (!tile_buf)
- tile_buf = g_new (guchar, GXIMAGE_WIDTH * MAX_CHANNELS);
- if (check_type < 0 || check_type > 5)
- g_error ("invalid check_type argument to render_setup: %d", check_type);
- if (check_size < 0 || check_size > 2)
- g_error ("invalid check_size argument to render_setup: %d", check_size);
- if (!blend_dark_check)
- blend_dark_check = g_new (guchar, 65536);
- if (!blend_light_check)
- blend_light_check = g_new (guchar, 65536);
- for (i = 0; i < 256; i++)
- for (j = 0; j < 256; j++)
- {
- blend_dark_check [(i << 8) + j] = (guchar)
- ((j * i + check_combos[check_type][0] * (255 - i)) / 255);
- blend_light_check [(i << 8) + j] = (guchar)
- ((j * i + check_combos[check_type][1] * (255 - i)) / 255);
- }
- switch (check_size)
- {
- case SMALL_CHECKS:
- check_mod = 0x3;
- check_shift = 2;
- break;
- case MEDIUM_CHECKS:
- check_mod = 0x7;
- check_shift = 3;
- break;
- case LARGE_CHECKS:
- check_mod = 0xf;
- check_shift = 4;
- break;
- }
- /* calculate check buffer for previews */
- if (preview_size)
- {
- if (check_buf)
- g_free (check_buf);
- if (empty_buf)
- g_free (empty_buf);
- if (temp_buf)
- g_free (temp_buf);
- check_buf = (unsigned char *) g_malloc ((preview_size + 4) * 3);
- for (i = 0; i < (preview_size + 4); i++)
- {
- if (i & 0x4)
- {
- check_buf[i * 3 + 0] = blend_dark_check[0];
- check_buf[i * 3 + 1] = blend_dark_check[0];
- check_buf[i * 3 + 2] = blend_dark_check[0];
- }
- else
- {
- check_buf[i * 3 + 0] = blend_light_check[0];
- check_buf[i * 3 + 1] = blend_light_check[0];
- check_buf[i * 3 + 2] = blend_light_check[0];
- }
- }
- empty_buf = (unsigned char *) g_malloc ((preview_size + 4) * 3);
- memset (empty_buf, 0, (preview_size + 4) * 3);
- temp_buf = (unsigned char *) g_malloc ((preview_size + 4) * 3);
- }
- else
- {
- check_buf = NULL;
- empty_buf = NULL;
- temp_buf = NULL;
- }
- }
- void
- render_free (void)
- {
- g_free (tile_buf);
- g_free (check_buf);
- }
- /* Render Image functions */
- static void render_image_rgb (RenderInfo *info);
- static void render_image_rgb_a (RenderInfo *info);
- static void render_image_gray (RenderInfo *info);
- static void render_image_gray_a (RenderInfo *info);
- static void render_image_indexed (RenderInfo *info);
- static void render_image_indexed_a (RenderInfo *info);
- static void render_image_init_info (RenderInfo *info,
- GDisplay *gdisp,
- int x,
- int y,
- int w,
- int h);
- static guint* render_image_init_alpha (int mult);
- static guchar* render_image_accelerate_scaling (int width,
- int start,
- float scalex);
- static guchar* render_image_tile_fault (RenderInfo *info);
- static RenderFunc render_funcs[6] =
- {
- render_image_rgb,
- render_image_rgb_a,
- render_image_gray,
- render_image_gray_a,
- render_image_indexed,
- render_image_indexed_a,
- };
- /*****************************************************************/
- /* This function is the core of the display--it offsets and */
- /* scales the image according to the current parameters in the */
- /* gdisp object. It handles color, grayscale, 8, 15, 16, 24, */
- /* & 32 bit output depths. */
- /*****************************************************************/
- void
- render_image (GDisplay *gdisp,
- int x,
- int y,
- int w,
- int h)
- {
- RenderInfo info;
- int image_type;
- render_image_init_info (&info, gdisp, x, y, w, h);
- image_type = gimage_projection_type (gdisp->gimage);
- if ((image_type < 0) || (image_type > 5))
- {
- g_message ("unknown gimage projection type: %d",
- gimage_projection_type (gdisp->gimage));
- return;
- }
- if ((info.dest_bpp < 1) || (info.dest_bpp > 4))
- {
- g_message ("unsupported destination bytes per pixel: %d", info.dest_bpp);
- return;
- }
- /* Currently, only RGBA and GRAYA projection types are used - the rest
- * are in case of future need. -- austin, 28th Nov 1998. */
- if (image_type != RGBA_GIMAGE && image_type != GRAYA_GIMAGE)
- g_warning ("using untested projection type %d", image_type);
- (* render_funcs[image_type]) (&info);
- }
- /*************************/
- /* 8 Bit functions */
- /*************************/
- static void
- render_image_indexed (RenderInfo *info)
- {
- guchar *src;
- guchar *dest;
- guchar *cmap;
- gulong val;
- gint byte_order;
- gint y, ye;
- gint x, xe;
- gint initial;
- cmap = gimage_cmap (info->gdisp->gimage);
- y = info->y;
- ye = info->y + info->h;
- xe = info->x + info->w;
- initial = TRUE;
- byte_order = info->byte_order;
- info->src = render_image_tile_fault (info);
- for (; y < ye; y++)
- {
- gint error = floor ((y + 1) / info->scaley) - floor (y / info->scaley);
- if (!initial && (error == 0))
- memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
- else
- {
- src = info->src;
- dest = info->dest;
- g_return_if_fail (src != NULL);
-
- for (x = info->x; x < xe; x++)
- {
- val = src[INDEXED_PIX] * 3;
- src += 1;
- dest[0] = cmap[val+0];
- dest[1] = cmap[val+1];
- dest[2] = cmap[val+2];
- dest += 3;
- }
- }
- info->dest += info->dest_bpl;
- initial = FALSE;
- if (error >= 1)
- {
- info->src_y += error;
- info->src = render_image_tile_fault (info);
- initial = TRUE;
- }
- }
- }
- static void
- render_image_indexed_a (RenderInfo *info)
- {
- guchar *src;
- guchar *dest;
- guint *alpha;
- guchar *cmap;
- gulong r, g, b;
- gulong val;
- guint a;
- gint dark_light;
- gint byte_order;
- gint y, ye;
- gint x, xe;
- gint initial;
- cmap = gimage_cmap (info->gdisp->gimage);
- alpha = info->alpha;
- y = info->y;
- ye = info->y + info->h;
- xe = info->x + info->w;
- initial = TRUE;
- byte_order = info->byte_order;
- info->src = render_image_tile_fault (info);
- for (; y < ye; y++)
- {
- gint error = floor ((y + 1) / info->scaley) - floor (y / info->scaley);
- if (!initial && (error == 0) && (y & check_mod))
- memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
- else
- {
- src = info->src;
- dest = info->dest;
- dark_light = (y >> check_shift) + (info->x >> check_shift);
- g_return_if_fail (src != NULL);
- for (x = info->x; x < xe; x++)
- {
- a = alpha[src[ALPHA_I_PIX]];
- val = src[INDEXED_PIX] * 3;
- src += 2;
- if (dark_light & 0x1)
- {
- r = blend_dark_check[(a | cmap[val+0])];
- g = blend_dark_check[(a | cmap[val+1])];
- b = blend_dark_check[(a | cmap[val+2])];
- }
- else
- {
- r = blend_light_check[(a | cmap[val+0])];
- g = blend_light_check[(a | cmap[val+1])];
- b = blend_light_check[(a | cmap[val+2])];
- }
- dest[0] = r;
- dest[1] = g;
- dest[2] = b;
- dest += 3;
- if (((x + 1) & check_mod) == 0)
- dark_light += 1;
- }
- }
- info->dest += info->dest_bpl;
- initial = FALSE;
- if (error >= 1)
- {
- info->src_y += error;
- info->src = render_image_tile_fault (info);
- initial = TRUE;
- }
- }
- }
- static void
- render_image_gray (RenderInfo *info)
- {
- guchar *src;
- guchar *dest;
- gulong val;
- gint byte_order;
- gint y, ye;
- gint x, xe;
- gint initial;
- y = info->y;
- ye = info->y + info->h;
- xe = info->x + info->w;
- initial = TRUE;
- byte_order = info->byte_order;
- info->src = render_image_tile_fault (info);
- for (; y < ye; y++)
- {
- gint error = floor ((y + 1) / info->scaley) - floor (y / info->scaley);
- if (!initial && (error == 0))
- memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
- else
- {
- src = info->src;
- dest = info->dest;
-
- g_return_if_fail (src != NULL);
- for (x = info->x; x < xe; x++)
- {
- val = src[GRAY_PIX];
- src += 1;
- dest[0] = val;
- dest[1] = val;
- dest[2] = val;
- dest += 3;
- }
- }
- info->dest += info->dest_bpl;
- initial = FALSE;
- if (error >= 1)
- {
- info->src_y += error;
- info->src = render_image_tile_fault (info);
- initial = TRUE;
- }
- }
- }
- static void
- render_image_gray_a (RenderInfo *info)
- {
- guchar *src;
- guchar *dest;
- guint *alpha;
- gulong val;
- guint a;
- gint dark_light;
- gint byte_order;
- gint y, ye;
- gint x, xe;
- gint initial;
- alpha = info->alpha;
- y = info->y;
- ye = info->y + info->h;
- xe = info->x + info->w;
- initial = TRUE;
- byte_order = info->byte_order;
- info->src = render_image_tile_fault (info);
- for (; y < ye; y++)
- {
- gint error = floor ((y + 1) / info->scaley) - floor (y / info->scaley);
- if (!initial && (error == 0) && (y & check_mod))
- memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
- else
- {
- src = info->src;
- dest = info->dest;
- dark_light = (y >> check_shift) + (info->x >> check_shift);
- g_return_if_fail (src != NULL);
- for (x = info->x; x < xe; x++)
- {
- a = alpha[src[ALPHA_G_PIX]];
- if (dark_light & 0x1)
- val = blend_dark_check[(a | src[GRAY_PIX])];
- else
- val = blend_light_check[(a | src[GRAY_PIX])];
- src += 2;
- dest[0] = val;
- dest[1] = val;
- dest[2] = val;
- dest += 3;
- if (((x + 1) & check_mod) == 0)
- dark_light += 1;
- }
- }
- info->dest += info->dest_bpl;
- initial = FALSE;
- if (error >= 1)
- {
- info->src_y += error;
- info->src = render_image_tile_fault (info);
- initial = TRUE;
- }
- }
- }
- static void
- render_image_rgb (RenderInfo *info)
- {
- guchar *src;
- guchar *dest;
- gint byte_order;
- gint y, ye;
- gint x, xe;
- gint initial;
- y = info->y;
- ye = info->y + info->h;
- xe = info->x + info->w;
- initial = TRUE;
- byte_order = info->byte_order;
- info->src = render_image_tile_fault (info);
- for (; y < ye; y++)
- {
- gint error = floor ((y + 1) / info->scaley) - floor (y / info->scaley);
- if (!initial && (error == 0))
- memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
- else
- {
- src = info->src;
- dest = info->dest;
- g_return_if_fail (src != NULL);
-
- /* replace this with memcpy, or better yet, avoid it altogether? */
- for (x = info->x; x < xe; x++)
- {
- dest[0] = src[0];
- dest[1] = src[1];
- dest[2] = src[2];
- src += 3;
- dest += 3;
- }
- }
- info->dest += info->dest_bpl;
- initial = FALSE;
- if (error >= 1)
- {
- info->src_y += error;
- info->src = render_image_tile_fault (info);
- initial = TRUE;
- }
- }
- }
- static void
- render_image_rgb_a (RenderInfo *info)
- {
- guchar *src;
- guchar *dest;
- guint *alpha;
- gulong r, g, b;
- guint a;
- gint dark_light;
- gint byte_order;
- gint y, ye;
- gint x, xe;
- gint initial;
- alpha = info->alpha;
- y = info->y;
- ye = info->y + info->h;
- xe = info->x + info->w;
- initial = TRUE;
- byte_order = info->byte_order;
- info->src = render_image_tile_fault (info);
- for (; y < ye; y++)
- {
- gint error = floor ((y + 1) / info->scaley) - floor (y / info->scaley);
- if (!initial && (error == 0) && (y & check_mod))
- memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
- else
- {
- src = info->src;
- dest = info->dest;
- dark_light = (y >> check_shift) + (info->x >> check_shift);
- g_return_if_fail (src != NULL);
- for (x = info->x; x < xe; x++)
- {
- a = alpha[src[ALPHA_PIX]];
- if (dark_light & 0x1)
- {
- r = blend_dark_check[(a | src[RED_PIX])];
- g = blend_dark_check[(a | src[GREEN_PIX])];
- b = blend_dark_check[(a | src[BLUE_PIX])];
- }
- else
- {
- r = blend_light_check[(a | src[RED_PIX])];
- g = blend_light_check[(a | src[GREEN_PIX])];
- b = blend_light_check[(a | src[BLUE_PIX])];
- }
- src += 4;
- dest[0] = r;
- dest[1] = g;
- dest[2] = b;
- dest += 3;
- if (((x + 1) & check_mod) == 0)
- dark_light += 1;
- }
- }
- info->dest += info->dest_bpl;
- initial = FALSE;
- if (error >= 1)
- {
- info->src_y += error;
- info->src = render_image_tile_fault (info);
- initial = TRUE;
- }
- }
- }
- static void
- render_image_init_info (RenderInfo *info,
- GDisplay *gdisp,
- int x,
- int y,
- int w,
- int h)
- {
- info->gdisp = gdisp;
- info->src_tiles = gimage_projection (gdisp->gimage);
- info->x = x + gdisp->offset_x;
- info->y = y + gdisp->offset_y;
- info->w = w;
- info->h = h;
- info->scalex = SCALEFACTOR_X (gdisp);
- info->scaley = SCALEFACTOR_Y (gdisp);
- info->src_x = UNSCALEX (gdisp, info->x);
- info->src_y = UNSCALEY (gdisp, info->y);
- info->src_bpp = gimage_projection_bytes (gdisp->gimage);
- info->dest = gximage_get_data ();
- info->dest_bpp = gximage_get_bpp ();
- info->dest_bpl = gximage_get_bpl ();
- info->dest_width = info->w * info->dest_bpp;
- info->byte_order = gximage_get_byte_order ();
- info->scale = render_image_accelerate_scaling (w, info->x, info->scalex);
- info->alpha = NULL;
- switch (gimage_projection_type (gdisp->gimage))
- {
- case RGBA_GIMAGE:
- case GRAYA_GIMAGE:
- case INDEXEDA_GIMAGE:
- info->alpha = render_image_init_alpha (gimage_projection_opacity (gdisp->gimage));
- break;
- default:
- /* nothing special needs doing */
- break;
- }
- }
- static guint*
- render_image_init_alpha (int mult)
- {
- static guint *alpha_mult = NULL;
- static int alpha_val = -1;
- int i;
- if (alpha_val != mult)
- {
- if (!alpha_mult)
- alpha_mult = g_new (guint, 256);
- alpha_val = mult;
- for (i = 0; i < 256; i++)
- alpha_mult[i] = ((mult * i) / 255) << 8;
- }
- return alpha_mult;
- }
- static guchar*
- render_image_accelerate_scaling (int width,
- int start,
- float scalex)
- {
- static guchar *scale = NULL;
- gint i;
- if (!scale)
- scale = g_new (guchar, GXIMAGE_WIDTH + 1);
- for (i = 0; i <= width; i++)
- {
- scale[i] = floor ((start + 1) / scalex) - floor (start / scalex);
- start++;
- }
- return scale;
- }
- static guchar*
- render_image_tile_fault (RenderInfo *info)
- {
- Tile *tile;
- guchar *data;
- guchar *dest;
- guchar *scale;
- int width;
- int tilex;
- int tiley;
- int srctilex, srctiley;
- int step;
- int bpp = info->src_bpp;
- int x, b;
- tilex = info->src_x / TILE_WIDTH;
- tiley = info->src_y / TILE_HEIGHT;
- tile = tile_manager_get_tile (info->src_tiles,
- srctilex=info->src_x, srctiley=info->src_y,
- TRUE, FALSE);
- if (!tile)
- return NULL;
- data = tile_data_pointer (tile,
- info->src_x % TILE_WIDTH,
- info->src_y % TILE_HEIGHT);
- scale = info->scale;
- dest = tile_buf;
- x = info->src_x;
- width = info->w;
- while (width--)
- {
- for (b = 0; b < bpp; b++)
- *dest++ = data[b];
- step = *scale++;
- if (step != 0)
- {
- x += step;
- data += step * bpp;
- if ((x >> tile_shift) != tilex)
- {
- tile_release (tile, FALSE);
- tilex += 1;
- tile = tile_manager_get_tile (info->src_tiles, srctilex=x,
- srctiley=info->src_y, TRUE, FALSE);
- if (!tile)
- return tile_buf;
- data = tile_data_pointer (tile,
- x % TILE_WIDTH,
- info->src_y % TILE_HEIGHT);
- }
- }
- }
- tile_release (tile, FALSE);
- return tile_buf;
- }
|