2001-07-04 02:38:56 +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
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2001-07-23 06:18:01 +08:00
|
|
|
#include <string.h> /* strcmp, memcmp */
|
2001-07-04 02:38:56 +08:00
|
|
|
|
2001-08-17 22:27:31 +08:00
|
|
|
#include <glib-object.h>
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
|
|
|
|
|
|
#include "core/core-types.h"
|
|
|
|
|
|
|
|
#include "base/tile.h"
|
|
|
|
#include "base/tile-manager.h"
|
|
|
|
#include "base/tile-manager-private.h"
|
|
|
|
|
2002-11-19 04:50:31 +08:00
|
|
|
#include "config/gimpcoreconfig.h"
|
|
|
|
|
2001-07-06 00:21:36 +08:00
|
|
|
#include "core/gimp.h"
|
2001-07-04 02:38:56 +08:00
|
|
|
#include "core/gimpcontainer.h"
|
|
|
|
#include "core/gimpdrawable.h"
|
|
|
|
#include "core/gimpimage.h"
|
2003-07-05 03:55:58 +08:00
|
|
|
#include "core/gimpimage-grid.h"
|
include the new "paint-funcs/paint-funcs-types.h".
2001-11-28 Michael Natterer <mitch@gimp.org>
* app/base/base-types.h: include the new
"paint-funcs/paint-funcs-types.h".
* app/paint-funcs/Makefile.am
* app/paint-funcs/paint-funcs-types.h: new file. Includes
"base/base-types.h".
* app/paint-funcs/paint-funcs.[ch]: removed the enums here,
include "paint-funcs-types.h".
* app/widgets/widgets-types.h: include "display/display-types.h"
* app/display/display-types.h: include "widgets/widgets-types.h".
* app/tools/tools-types.h: include "display/display-types.h"
* app/gui/gui-types.h: include "tools/tools-types.h".
The order of namespaces/dependencies should be (but is not):
(base, paint-funcs) -> (core, file, xcf, pdb) ->
(widgets, display) -> tools -> gui
* app/path.c: include "tools/tools-types.h".
* app/core/Makefile.am
* app/core/gimpimage-guides.[ch]
* app/core/gimpimage-merge.[ch]
* app/core/gimpimage-resize.[ch]
* app/core/gimpimage-scale.[ch]: new files.
* app/core/gimpimage.[ch]: removed the stuff which is in the new
files. Reordered all functions in both the .h and .c files,
commented the groups of functions.
* app/core/gimpcontainer.c: create the handler_id using a counter,
not the address of a pointer, because the address *may* be the
same twice, added debugging output.
* app/core/gimpviewable.[ch]: added primitive support for getting
a preview GdkPixbuf.
* app/nav_window.c
* app/undo.c
* app/undo_history.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage-mask.[ch]
* app/display/gimpdisplay.c
* app/display/gimpdisplayshell-callbacks.c
* app/display/gimpdisplayshell-dnd.c
* app/display/gimpdisplayshell-render.c
* app/display/gimpdisplayshell-scale.c
* app/display/gimpdisplayshell-scroll.c
* app/gui/image-commands.c
* app/gui/info-window.c
* app/gui/layers-commands.c
* app/gui/palette-import-dialog.c
* app/tools/gimpbycolorselecttool.c
* app/tools/gimpeditselectiontool.c
* app/tools/gimpmeasuretool.c
* app/tools/gimpmovetool.c
* app/widgets/gimpcontainerview-utils.c
* app/xcf/xcf-load.c: changed accordingly, some cleanup.
* tools/pdbgen/pdb/guides.pdb
* tools/pdbgen/pdb/image.pdb: changed accordingly, reordered functions.
* app/plug_in.c: set the labels of the "Repeat" and "Re-Show" menu
items to the name of the last plug-in (Fixes #50986).
* app/display/gimpdisplayshell.[ch]: set the labels of "Undo" and
"Redo" to the resp. undo names. Much simplified the WM icon stuff
by removing most code and using gimp_viewable_get_new_preview_pixbuf().
* app/widgets/gimpbrushfactoryview.c: forgot to assign the GQuark
returned by gimp_container_add_handler().
* app/pdb/guides_cmds.c
* app/pdb/image_cmds.c
* libgimp/gimpimage_pdb.[ch]: regenerated.
2001-11-29 01:51:06 +08:00
|
|
|
#include "core/gimpimage-guides.h"
|
2001-07-04 02:38:56 +08:00
|
|
|
#include "core/gimplayer.h"
|
2002-02-22 06:19:45 +08:00
|
|
|
#include "core/gimplayer-floating-sel.h"
|
2001-07-04 02:38:56 +08:00
|
|
|
#include "core/gimplayermask.h"
|
2001-07-10 03:48:30 +08:00
|
|
|
#include "core/gimpparasitelist.h"
|
2003-09-03 07:07:40 +08:00
|
|
|
#include "core/gimpselection.h"
|
2001-07-11 20:39:49 +08:00
|
|
|
#include "core/gimpunit.h"
|
2001-07-04 02:38:56 +08:00
|
|
|
|
2003-06-24 21:59:36 +08:00
|
|
|
#include "text/gimptextlayer.h"
|
|
|
|
#include "text/gimptext-parasite.h"
|
|
|
|
|
2003-09-09 23:46:59 +08:00
|
|
|
#include "vectors/gimpanchor.h"
|
|
|
|
#include "vectors/gimpstroke.h"
|
|
|
|
#include "vectors/gimpbezierstroke.h"
|
2003-05-15 03:21:42 +08:00
|
|
|
#include "vectors/gimpvectors.h"
|
2003-05-23 03:02:38 +08:00
|
|
|
#include "vectors/gimpvectors-compat.h"
|
2003-05-15 03:21:42 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
#include "xcf-private.h"
|
|
|
|
#include "xcf-load.h"
|
|
|
|
#include "xcf-read.h"
|
|
|
|
#include "xcf-seek.h"
|
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
|
2003-09-03 07:07:40 +08:00
|
|
|
static gboolean xcf_load_image_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
|
|
|
static gboolean xcf_load_layer_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage,
|
|
|
|
GimpLayer *layer,
|
|
|
|
gboolean *apply_mask,
|
|
|
|
gboolean *edit_mask,
|
|
|
|
gboolean *show_mask);
|
|
|
|
static gboolean xcf_load_channel_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage,
|
|
|
|
GimpChannel **channel);
|
|
|
|
static gboolean xcf_load_prop (XcfInfo *info,
|
|
|
|
PropType *prop_type,
|
|
|
|
guint32 *prop_size);
|
|
|
|
static GimpLayer * xcf_load_layer (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
|
|
|
static GimpChannel * xcf_load_channel (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
|
|
|
static GimpLayerMask * xcf_load_layer_mask (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
|
|
|
static gboolean xcf_load_hierarchy (XcfInfo *info,
|
|
|
|
TileManager *tiles);
|
|
|
|
static gboolean xcf_load_level (XcfInfo *info,
|
|
|
|
TileManager *tiles);
|
|
|
|
static gboolean xcf_load_tile (XcfInfo *info,
|
|
|
|
Tile *tile);
|
|
|
|
static gboolean xcf_load_tile_rle (XcfInfo *info,
|
|
|
|
Tile *tile,
|
|
|
|
gint data_length);
|
|
|
|
static GimpParasite * xcf_load_parasite (XcfInfo *info);
|
|
|
|
static gboolean xcf_load_old_paths (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
|
|
|
static gboolean xcf_load_old_path (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
2003-09-09 23:46:59 +08:00
|
|
|
static gboolean xcf_load_vectors (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
|
|
|
static gboolean xcf_load_vector (XcfInfo *info,
|
|
|
|
GimpImage *gimage);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
#ifdef SWAP_FROM_FILE
|
2003-09-03 07:07:40 +08:00
|
|
|
static gboolean xcf_swap_func (gint fd,
|
|
|
|
Tile *tile,
|
|
|
|
gint cmd,
|
|
|
|
gpointer user_data);
|
2001-07-04 02:38:56 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
GimpImage *
|
2001-07-05 03:31:35 +08:00
|
|
|
xcf_load_image (Gimp *gimp,
|
|
|
|
XcfInfo *info)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
2003-07-05 03:55:58 +08:00
|
|
|
GimpImage *gimage;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpChannel *channel;
|
|
|
|
GimpParasite *parasite;
|
|
|
|
guint32 saved_pos;
|
|
|
|
guint32 offset;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint image_type;
|
|
|
|
gint num_successful_elements = 0;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* read in the image width, height and type */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &image_type, 1);
|
|
|
|
|
2001-07-06 00:21:36 +08:00
|
|
|
gimage = gimp_create_image (gimp,
|
|
|
|
width, height,
|
|
|
|
image_type,
|
|
|
|
FALSE);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* read the image properties */
|
|
|
|
if (!xcf_load_image_props (info, gimage))
|
|
|
|
goto hard_error;
|
|
|
|
|
2003-07-05 03:55:58 +08:00
|
|
|
/* check for a GimpGrid parasite */
|
|
|
|
parasite = gimp_image_parasite_find (GIMP_IMAGE (gimage),
|
|
|
|
gimp_grid_parasite_name ());
|
|
|
|
if (parasite)
|
|
|
|
{
|
|
|
|
GimpGrid *grid = gimp_grid_from_parasite (parasite);
|
|
|
|
|
|
|
|
if (grid)
|
|
|
|
{
|
|
|
|
gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites,
|
|
|
|
gimp_parasite_name (parasite));
|
|
|
|
|
|
|
|
gimp_image_set_grid (GIMP_IMAGE (gimage), grid, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
/* read in the offset of the next layer */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &offset, 1);
|
|
|
|
|
|
|
|
/* if the offset is 0 then we are at the end
|
|
|
|
* of the layer list.
|
|
|
|
*/
|
|
|
|
if (offset == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* save the current position as it is where the
|
|
|
|
* next layer offset is stored.
|
|
|
|
*/
|
|
|
|
saved_pos = info->cp;
|
|
|
|
|
|
|
|
/* seek to the layer offset */
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, offset, NULL))
|
|
|
|
goto error;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* read in the layer */
|
|
|
|
layer = xcf_load_layer (info, gimage);
|
|
|
|
if (!layer)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
num_successful_elements++;
|
|
|
|
|
|
|
|
/* add the layer to the image if its not the floating selection */
|
|
|
|
if (layer != info->floating_sel)
|
|
|
|
gimp_image_add_layer (gimage, layer,
|
|
|
|
gimp_container_num_children (gimage->layers));
|
|
|
|
|
|
|
|
/* restore the saved position so we'll be ready to
|
|
|
|
* read the next offset.
|
|
|
|
*/
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, saved_pos, NULL))
|
|
|
|
goto error;
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
/* read in the offset of the next channel */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &offset, 1);
|
|
|
|
|
|
|
|
/* if the offset is 0 then we are at the end
|
|
|
|
* of the channel list.
|
|
|
|
*/
|
|
|
|
if (offset == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* save the current position as it is where the
|
|
|
|
* next channel offset is stored.
|
|
|
|
*/
|
|
|
|
saved_pos = info->cp;
|
|
|
|
|
|
|
|
/* seek to the channel offset */
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, offset, NULL))
|
|
|
|
goto error;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* read in the layer */
|
|
|
|
channel = xcf_load_channel (info, gimage);
|
|
|
|
if (!channel)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
num_successful_elements++;
|
|
|
|
|
|
|
|
/* add the channel to the image if its not the selection */
|
|
|
|
if (channel != gimage->selection_mask)
|
|
|
|
gimp_image_add_channel (gimage, channel, -1);
|
|
|
|
|
|
|
|
/* restore the saved position so we'll be ready to
|
|
|
|
* read the next offset.
|
|
|
|
*/
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, saved_pos, NULL))
|
|
|
|
goto error;
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->active_layer)
|
|
|
|
gimp_image_set_active_layer (gimage, info->active_layer);
|
|
|
|
|
|
|
|
if (info->active_channel)
|
|
|
|
gimp_image_set_active_channel (gimage, info->active_channel);
|
|
|
|
|
2002-04-19 20:05:47 +08:00
|
|
|
gimp_image_set_filename (gimage, info->filename);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
return gimage;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (num_successful_elements == 0)
|
|
|
|
goto hard_error;
|
|
|
|
|
|
|
|
g_message ("XCF: This file is corrupt! I have loaded as much\n"
|
|
|
|
"of it as I can, but it is incomplete.");
|
|
|
|
|
|
|
|
return gimage;
|
|
|
|
|
2003-09-01 07:46:05 +08:00
|
|
|
hard_error:
|
2001-07-04 02:38:56 +08:00
|
|
|
g_message ("XCF: This file is corrupt! I could not even\n"
|
|
|
|
"salvage any partial image data from it.");
|
|
|
|
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (gimage);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_image_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
PropType prop_type;
|
|
|
|
guint32 prop_size;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
if (!xcf_load_prop (info, &prop_type, &prop_size))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (prop_type)
|
|
|
|
{
|
|
|
|
case PROP_END:
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case PROP_COLORMAP:
|
2003-09-01 07:46:05 +08:00
|
|
|
if (info->file_version == 0)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_message (_("XCF warning: version 0 of XCF file format\n"
|
|
|
|
"did not save indexed colormaps correctly.\n"
|
|
|
|
"Substituting grayscale map."));
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
2003-04-10 22:37:06 +08:00
|
|
|
xcf_read_int32 (info->fp, (guint32 *) &gimage->num_cols, 1);
|
|
|
|
gimage->cmap = g_new (guchar, gimage->num_cols * 3);
|
2002-12-20 14:26:34 +08:00
|
|
|
if (!xcf_seek_pos (info, info->cp + gimage->num_cols, NULL))
|
|
|
|
return FALSE;
|
|
|
|
|
2003-09-01 07:46:05 +08:00
|
|
|
for (i = 0; i<gimage->num_cols; i++)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
gimage->cmap[i*3+0] = i;
|
|
|
|
gimage->cmap[i*3+1] = i;
|
|
|
|
gimage->cmap[i*3+2] = i;
|
|
|
|
}
|
|
|
|
}
|
2003-09-01 07:46:05 +08:00
|
|
|
else
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
2003-04-10 22:37:06 +08:00
|
|
|
xcf_read_int32 (info->fp, (guint32 *) &gimage->num_cols, 1);
|
|
|
|
gimage->cmap = g_new (guchar, gimage->num_cols * 3);
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int8 (info->fp,
|
2003-04-10 22:37:06 +08:00
|
|
|
(guint8 *) gimage->cmap, gimage->num_cols * 3);
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_COMPRESSION:
|
|
|
|
{
|
|
|
|
guint8 compression;
|
|
|
|
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int8 (info->fp, (guint8 *) &compression, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
if ((compression != COMPRESS_NONE) &&
|
|
|
|
(compression != COMPRESS_RLE) &&
|
|
|
|
(compression != COMPRESS_ZLIB) &&
|
|
|
|
(compression != COMPRESS_FRACTAL))
|
|
|
|
{
|
|
|
|
g_message ("unknown compression type: %d", (int) compression);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->compression = compression;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_GUIDES:
|
|
|
|
{
|
2003-03-28 21:52:01 +08:00
|
|
|
gint32 position;
|
|
|
|
gint8 orientation;
|
|
|
|
gint i, nguides;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
nguides = prop_size / (4 + 1);
|
|
|
|
for (i = 0; i < nguides; i++)
|
|
|
|
{
|
2003-04-30 20:51:11 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &position, 1);
|
|
|
|
info->cp += xcf_read_int8 (info->fp, (guint8 *) &orientation, 1);
|
|
|
|
|
|
|
|
/* skip -1 guides from old XCFs */
|
|
|
|
if (position < 0)
|
|
|
|
continue;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
switch (orientation)
|
|
|
|
{
|
2003-02-08 01:12:21 +08:00
|
|
|
case XCF_ORIENTATION_HORIZONTAL:
|
2003-03-28 21:52:01 +08:00
|
|
|
gimp_image_add_hguide (gimage, position, FALSE);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
|
2003-02-08 01:12:21 +08:00
|
|
|
case XCF_ORIENTATION_VERTICAL:
|
2003-03-28 21:52:01 +08:00
|
|
|
gimp_image_add_vguide (gimage, position, FALSE);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_message ("guide orientation out of range in XCF file");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this is silly as the order of guides doesn't really matter,
|
|
|
|
* but it restores the list to it's original order, which
|
|
|
|
* cannot be wrong --Mitch
|
|
|
|
*/
|
|
|
|
gimage->guides = g_list_reverse (gimage->guides);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_RESOLUTION:
|
|
|
|
{
|
|
|
|
gfloat xres, yres;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
info->cp += xcf_read_float (info->fp, &xres, 1);
|
|
|
|
info->cp += xcf_read_float (info->fp, &yres, 1);
|
|
|
|
if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
|
|
|
|
yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
|
|
|
|
{
|
|
|
|
g_message ("Warning, resolution out of range in XCF file");
|
2001-07-11 20:39:49 +08:00
|
|
|
xres = gimage->gimp->config->default_xresolution;
|
|
|
|
yres = gimage->gimp->config->default_yresolution;
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
gimage->xresolution = xres;
|
|
|
|
gimage->yresolution = yres;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_TATTOO:
|
|
|
|
{
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &gimage->tattoo_state, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_PARASITES:
|
|
|
|
{
|
|
|
|
glong base = info->cp;
|
|
|
|
GimpParasite *p;
|
|
|
|
|
|
|
|
while (info->cp - base < prop_size)
|
|
|
|
{
|
2001-07-19 23:34:19 +08:00
|
|
|
p = xcf_load_parasite (info);
|
2001-07-04 02:38:56 +08:00
|
|
|
gimp_image_parasite_attach (gimage, p);
|
|
|
|
gimp_parasite_free (p);
|
|
|
|
}
|
|
|
|
if (info->cp - base != prop_size)
|
|
|
|
g_message ("Error detected while loading an image's parasites");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_UNIT:
|
|
|
|
{
|
|
|
|
guint32 unit;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, &unit, 1);
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
if ((unit <= GIMP_UNIT_PIXEL) ||
|
removed the gimp_busy boolean, check whether user_installation is needed
2001-07-10 Michael Natterer <mitch@gimp.org>
* app/app_procs.[ch]: removed the gimp_busy boolean, check whether
user_installation is needed here, not in user_install.c, parse
gtkrc an friends only if(!no_interface), create the Gimp object
before parsing gimp's rc files an pas it to the parse functions,
many other cleanups.
* app/appenums.h: added MessageHandlerType and StackTraceMode.
* app/appenv.h: removed MessageHandlerType, declare all global
variables from main.c (no more hidden global stuff please).
* app/errors.[ch]: added the fatal message func here (from main.c),
removed the StackTraceMode enum.
* app/gimprc.[ch]: renamed functions to gimprc_*(), pass a Gimp
pointer to some functions.
* app/gimpunit.c
* app/unitrc.h: ok, this is ugly: renamed all functions to
_gimp_unit_*() and made them public. The unit list is part
of the Gimp object now, so pass a Gimp* to all functions.
* app/libgimp_glue.[ch]: added EEKy wrappers for all gimp_unit_*()
functions which are used by widgets.
* app/main.c: cleaned up the global variables, removed the fatal
message handler, call app_init() directly, not via the
user_install stuff, misc. cleanups.
* app/user_install.[ch]: removed the check if user_installation is
needed (done by app_procs.c now).
* app/core/gimp.[ch]: added the user_unit list and the "busy"
boolean. Moved gimp_[set|unset]_busy() here. Added
gimp_initialize() which is called after unitrc and gimprc are
parsed.
* app/batch.c
* app/colormaps.c
* app/devices.c
* app/disp_callbacks.c
* app/gdisplay_ops.c
* app/gimphelp.c
* app/module_db.c
* app/nav_window.c
* app/plug_in.c
* app/core/gimpcontext.c
* app/core/gimpdatafiles.c
* app/core/gimpimage-convert.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage.c
* app/core/gimpparasite.c
* app/core/gimpparasitelist.h
* app/gui/file-open-dialog.c
* app/gui/gui.[ch]
* app/gui/info-dialog.c
* app/gui/info-window.c
* app/gui/preferences-dialog.c
* app/gui/session.c
* app/gui/tips-dialog.c
* app/gui/toolbox.c
* app/tools/gimpblendtool.c
* app/tools/gimpbucketfilltool.c
* app/tools/gimpcolorpickertool.c
* app/tools/gimpfuzzyselecttool.c
* app/tools/gimptransformtool.c
* app/tools/tool_manager.c
* app/widgets/gimpcolorpanel.c
* app/widgets/gimpcursor.c
* app/xcf/xcf-load.c
* app/xcf/xcf-save.c
* app/xcf/xcf.c
* tools/pdbgen/Makefile.am
* tools/pdbgen/app.pl
* tools/pdbgen/enums.pl
* tools/pdbgen/pdb/image.pdb
* tools/pdbgen/pdb/message.pdb
* tools/pdbgen/pdb/unit.pdb
* app/pdb/image_cmds.c
* app/pdb/message_cmds.c
* app/pdb/unit_cmds.c: changed accordingly, minor cleanups.
2001-07-11 03:16:16 +08:00
|
|
|
(unit >= _gimp_unit_get_number_of_built_in_units (gimage->gimp)))
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
2001-07-19 23:34:19 +08:00
|
|
|
g_message ("Warning, unit out of range in XCF file, "
|
|
|
|
"falling back to inches");
|
2001-07-04 02:38:56 +08:00
|
|
|
unit = GIMP_UNIT_INCH;
|
|
|
|
}
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
gimage->unit = unit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_PATHS:
|
2003-05-22 01:38:14 +08:00
|
|
|
xcf_load_old_paths (info, gimage);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_USER_UNIT:
|
|
|
|
{
|
|
|
|
gchar *unit_strings[5];
|
|
|
|
float factor;
|
|
|
|
guint32 digits;
|
|
|
|
GimpUnit unit;
|
|
|
|
gint num_units;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
info->cp += xcf_read_float (info->fp, &factor, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &digits, 1);
|
|
|
|
info->cp += xcf_read_string (info->fp, unit_strings, 5);
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
if (unit_strings[i] == NULL)
|
|
|
|
unit_strings[i] = g_strdup ("");
|
|
|
|
|
removed the gimp_busy boolean, check whether user_installation is needed
2001-07-10 Michael Natterer <mitch@gimp.org>
* app/app_procs.[ch]: removed the gimp_busy boolean, check whether
user_installation is needed here, not in user_install.c, parse
gtkrc an friends only if(!no_interface), create the Gimp object
before parsing gimp's rc files an pas it to the parse functions,
many other cleanups.
* app/appenums.h: added MessageHandlerType and StackTraceMode.
* app/appenv.h: removed MessageHandlerType, declare all global
variables from main.c (no more hidden global stuff please).
* app/errors.[ch]: added the fatal message func here (from main.c),
removed the StackTraceMode enum.
* app/gimprc.[ch]: renamed functions to gimprc_*(), pass a Gimp
pointer to some functions.
* app/gimpunit.c
* app/unitrc.h: ok, this is ugly: renamed all functions to
_gimp_unit_*() and made them public. The unit list is part
of the Gimp object now, so pass a Gimp* to all functions.
* app/libgimp_glue.[ch]: added EEKy wrappers for all gimp_unit_*()
functions which are used by widgets.
* app/main.c: cleaned up the global variables, removed the fatal
message handler, call app_init() directly, not via the
user_install stuff, misc. cleanups.
* app/user_install.[ch]: removed the check if user_installation is
needed (done by app_procs.c now).
* app/core/gimp.[ch]: added the user_unit list and the "busy"
boolean. Moved gimp_[set|unset]_busy() here. Added
gimp_initialize() which is called after unitrc and gimprc are
parsed.
* app/batch.c
* app/colormaps.c
* app/devices.c
* app/disp_callbacks.c
* app/gdisplay_ops.c
* app/gimphelp.c
* app/module_db.c
* app/nav_window.c
* app/plug_in.c
* app/core/gimpcontext.c
* app/core/gimpdatafiles.c
* app/core/gimpimage-convert.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage.c
* app/core/gimpparasite.c
* app/core/gimpparasitelist.h
* app/gui/file-open-dialog.c
* app/gui/gui.[ch]
* app/gui/info-dialog.c
* app/gui/info-window.c
* app/gui/preferences-dialog.c
* app/gui/session.c
* app/gui/tips-dialog.c
* app/gui/toolbox.c
* app/tools/gimpblendtool.c
* app/tools/gimpbucketfilltool.c
* app/tools/gimpcolorpickertool.c
* app/tools/gimpfuzzyselecttool.c
* app/tools/gimptransformtool.c
* app/tools/tool_manager.c
* app/widgets/gimpcolorpanel.c
* app/widgets/gimpcursor.c
* app/xcf/xcf-load.c
* app/xcf/xcf-save.c
* app/xcf/xcf.c
* tools/pdbgen/Makefile.am
* tools/pdbgen/app.pl
* tools/pdbgen/enums.pl
* tools/pdbgen/pdb/image.pdb
* tools/pdbgen/pdb/message.pdb
* tools/pdbgen/pdb/unit.pdb
* app/pdb/image_cmds.c
* app/pdb/message_cmds.c
* app/pdb/unit_cmds.c: changed accordingly, minor cleanups.
2001-07-11 03:16:16 +08:00
|
|
|
num_units = _gimp_unit_get_number_of_units (gimage->gimp);
|
|
|
|
|
|
|
|
for (unit = _gimp_unit_get_number_of_built_in_units (gimage->gimp);
|
2001-07-04 02:38:56 +08:00
|
|
|
unit < num_units; unit++)
|
|
|
|
{
|
|
|
|
/* if the factor and the identifier match some unit
|
|
|
|
* in unitrc, use the unitrc unit
|
|
|
|
*/
|
removed the gimp_busy boolean, check whether user_installation is needed
2001-07-10 Michael Natterer <mitch@gimp.org>
* app/app_procs.[ch]: removed the gimp_busy boolean, check whether
user_installation is needed here, not in user_install.c, parse
gtkrc an friends only if(!no_interface), create the Gimp object
before parsing gimp's rc files an pas it to the parse functions,
many other cleanups.
* app/appenums.h: added MessageHandlerType and StackTraceMode.
* app/appenv.h: removed MessageHandlerType, declare all global
variables from main.c (no more hidden global stuff please).
* app/errors.[ch]: added the fatal message func here (from main.c),
removed the StackTraceMode enum.
* app/gimprc.[ch]: renamed functions to gimprc_*(), pass a Gimp
pointer to some functions.
* app/gimpunit.c
* app/unitrc.h: ok, this is ugly: renamed all functions to
_gimp_unit_*() and made them public. The unit list is part
of the Gimp object now, so pass a Gimp* to all functions.
* app/libgimp_glue.[ch]: added EEKy wrappers for all gimp_unit_*()
functions which are used by widgets.
* app/main.c: cleaned up the global variables, removed the fatal
message handler, call app_init() directly, not via the
user_install stuff, misc. cleanups.
* app/user_install.[ch]: removed the check if user_installation is
needed (done by app_procs.c now).
* app/core/gimp.[ch]: added the user_unit list and the "busy"
boolean. Moved gimp_[set|unset]_busy() here. Added
gimp_initialize() which is called after unitrc and gimprc are
parsed.
* app/batch.c
* app/colormaps.c
* app/devices.c
* app/disp_callbacks.c
* app/gdisplay_ops.c
* app/gimphelp.c
* app/module_db.c
* app/nav_window.c
* app/plug_in.c
* app/core/gimpcontext.c
* app/core/gimpdatafiles.c
* app/core/gimpimage-convert.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage.c
* app/core/gimpparasite.c
* app/core/gimpparasitelist.h
* app/gui/file-open-dialog.c
* app/gui/gui.[ch]
* app/gui/info-dialog.c
* app/gui/info-window.c
* app/gui/preferences-dialog.c
* app/gui/session.c
* app/gui/tips-dialog.c
* app/gui/toolbox.c
* app/tools/gimpblendtool.c
* app/tools/gimpbucketfilltool.c
* app/tools/gimpcolorpickertool.c
* app/tools/gimpfuzzyselecttool.c
* app/tools/gimptransformtool.c
* app/tools/tool_manager.c
* app/widgets/gimpcolorpanel.c
* app/widgets/gimpcursor.c
* app/xcf/xcf-load.c
* app/xcf/xcf-save.c
* app/xcf/xcf.c
* tools/pdbgen/Makefile.am
* tools/pdbgen/app.pl
* tools/pdbgen/enums.pl
* tools/pdbgen/pdb/image.pdb
* tools/pdbgen/pdb/message.pdb
* tools/pdbgen/pdb/unit.pdb
* app/pdb/image_cmds.c
* app/pdb/message_cmds.c
* app/pdb/unit_cmds.c: changed accordingly, minor cleanups.
2001-07-11 03:16:16 +08:00
|
|
|
if ((ABS (_gimp_unit_get_factor (gimage->gimp,
|
|
|
|
unit) - factor) < 1e-5) &&
|
2001-07-04 02:38:56 +08:00
|
|
|
(strcmp (unit_strings[0],
|
removed the gimp_busy boolean, check whether user_installation is needed
2001-07-10 Michael Natterer <mitch@gimp.org>
* app/app_procs.[ch]: removed the gimp_busy boolean, check whether
user_installation is needed here, not in user_install.c, parse
gtkrc an friends only if(!no_interface), create the Gimp object
before parsing gimp's rc files an pas it to the parse functions,
many other cleanups.
* app/appenums.h: added MessageHandlerType and StackTraceMode.
* app/appenv.h: removed MessageHandlerType, declare all global
variables from main.c (no more hidden global stuff please).
* app/errors.[ch]: added the fatal message func here (from main.c),
removed the StackTraceMode enum.
* app/gimprc.[ch]: renamed functions to gimprc_*(), pass a Gimp
pointer to some functions.
* app/gimpunit.c
* app/unitrc.h: ok, this is ugly: renamed all functions to
_gimp_unit_*() and made them public. The unit list is part
of the Gimp object now, so pass a Gimp* to all functions.
* app/libgimp_glue.[ch]: added EEKy wrappers for all gimp_unit_*()
functions which are used by widgets.
* app/main.c: cleaned up the global variables, removed the fatal
message handler, call app_init() directly, not via the
user_install stuff, misc. cleanups.
* app/user_install.[ch]: removed the check if user_installation is
needed (done by app_procs.c now).
* app/core/gimp.[ch]: added the user_unit list and the "busy"
boolean. Moved gimp_[set|unset]_busy() here. Added
gimp_initialize() which is called after unitrc and gimprc are
parsed.
* app/batch.c
* app/colormaps.c
* app/devices.c
* app/disp_callbacks.c
* app/gdisplay_ops.c
* app/gimphelp.c
* app/module_db.c
* app/nav_window.c
* app/plug_in.c
* app/core/gimpcontext.c
* app/core/gimpdatafiles.c
* app/core/gimpimage-convert.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage.c
* app/core/gimpparasite.c
* app/core/gimpparasitelist.h
* app/gui/file-open-dialog.c
* app/gui/gui.[ch]
* app/gui/info-dialog.c
* app/gui/info-window.c
* app/gui/preferences-dialog.c
* app/gui/session.c
* app/gui/tips-dialog.c
* app/gui/toolbox.c
* app/tools/gimpblendtool.c
* app/tools/gimpbucketfilltool.c
* app/tools/gimpcolorpickertool.c
* app/tools/gimpfuzzyselecttool.c
* app/tools/gimptransformtool.c
* app/tools/tool_manager.c
* app/widgets/gimpcolorpanel.c
* app/widgets/gimpcursor.c
* app/xcf/xcf-load.c
* app/xcf/xcf-save.c
* app/xcf/xcf.c
* tools/pdbgen/Makefile.am
* tools/pdbgen/app.pl
* tools/pdbgen/enums.pl
* tools/pdbgen/pdb/image.pdb
* tools/pdbgen/pdb/message.pdb
* tools/pdbgen/pdb/unit.pdb
* app/pdb/image_cmds.c
* app/pdb/message_cmds.c
* app/pdb/unit_cmds.c: changed accordingly, minor cleanups.
2001-07-11 03:16:16 +08:00
|
|
|
_gimp_unit_get_identifier (gimage->gimp,
|
|
|
|
unit)) == 0))
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* no match */
|
|
|
|
if (unit == num_units)
|
removed the gimp_busy boolean, check whether user_installation is needed
2001-07-10 Michael Natterer <mitch@gimp.org>
* app/app_procs.[ch]: removed the gimp_busy boolean, check whether
user_installation is needed here, not in user_install.c, parse
gtkrc an friends only if(!no_interface), create the Gimp object
before parsing gimp's rc files an pas it to the parse functions,
many other cleanups.
* app/appenums.h: added MessageHandlerType and StackTraceMode.
* app/appenv.h: removed MessageHandlerType, declare all global
variables from main.c (no more hidden global stuff please).
* app/errors.[ch]: added the fatal message func here (from main.c),
removed the StackTraceMode enum.
* app/gimprc.[ch]: renamed functions to gimprc_*(), pass a Gimp
pointer to some functions.
* app/gimpunit.c
* app/unitrc.h: ok, this is ugly: renamed all functions to
_gimp_unit_*() and made them public. The unit list is part
of the Gimp object now, so pass a Gimp* to all functions.
* app/libgimp_glue.[ch]: added EEKy wrappers for all gimp_unit_*()
functions which are used by widgets.
* app/main.c: cleaned up the global variables, removed the fatal
message handler, call app_init() directly, not via the
user_install stuff, misc. cleanups.
* app/user_install.[ch]: removed the check if user_installation is
needed (done by app_procs.c now).
* app/core/gimp.[ch]: added the user_unit list and the "busy"
boolean. Moved gimp_[set|unset]_busy() here. Added
gimp_initialize() which is called after unitrc and gimprc are
parsed.
* app/batch.c
* app/colormaps.c
* app/devices.c
* app/disp_callbacks.c
* app/gdisplay_ops.c
* app/gimphelp.c
* app/module_db.c
* app/nav_window.c
* app/plug_in.c
* app/core/gimpcontext.c
* app/core/gimpdatafiles.c
* app/core/gimpimage-convert.c
* app/core/gimpimage-duplicate.c
* app/core/gimpimage.c
* app/core/gimpparasite.c
* app/core/gimpparasitelist.h
* app/gui/file-open-dialog.c
* app/gui/gui.[ch]
* app/gui/info-dialog.c
* app/gui/info-window.c
* app/gui/preferences-dialog.c
* app/gui/session.c
* app/gui/tips-dialog.c
* app/gui/toolbox.c
* app/tools/gimpblendtool.c
* app/tools/gimpbucketfilltool.c
* app/tools/gimpcolorpickertool.c
* app/tools/gimpfuzzyselecttool.c
* app/tools/gimptransformtool.c
* app/tools/tool_manager.c
* app/widgets/gimpcolorpanel.c
* app/widgets/gimpcursor.c
* app/xcf/xcf-load.c
* app/xcf/xcf-save.c
* app/xcf/xcf.c
* tools/pdbgen/Makefile.am
* tools/pdbgen/app.pl
* tools/pdbgen/enums.pl
* tools/pdbgen/pdb/image.pdb
* tools/pdbgen/pdb/message.pdb
* tools/pdbgen/pdb/unit.pdb
* app/pdb/image_cmds.c
* app/pdb/message_cmds.c
* app/pdb/unit_cmds.c: changed accordingly, minor cleanups.
2001-07-11 03:16:16 +08:00
|
|
|
unit = _gimp_unit_new (gimage->gimp,
|
|
|
|
unit_strings[0],
|
|
|
|
factor,
|
|
|
|
digits,
|
|
|
|
unit_strings[1],
|
|
|
|
unit_strings[2],
|
|
|
|
unit_strings[3],
|
|
|
|
unit_strings[4]);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
gimage->unit = unit;
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
g_free (unit_strings[i]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2003-09-09 23:46:59 +08:00
|
|
|
case PROP_VECTORS:
|
|
|
|
{
|
|
|
|
guint32 base = info->cp;
|
|
|
|
|
|
|
|
if (xcf_load_vectors (info, gimage))
|
|
|
|
{
|
|
|
|
if (base + prop_size != info->cp)
|
|
|
|
{
|
|
|
|
g_warning ("Mismatch in PROP_VECTORS size: skipping %d bytes.",
|
|
|
|
base + prop_size - info->cp);
|
|
|
|
xcf_seek_pos (info, base + prop_size, NULL);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* skip silently since we don't understand the format and
|
|
|
|
* xcf_load_vectors already explained what was wrong */
|
|
|
|
xcf_seek_pos (info, base + prop_size, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
default:
|
2003-09-01 07:46:05 +08:00
|
|
|
g_message ("unexpected/unknown image property: %d (skipping)",
|
2001-07-19 23:34:19 +08:00
|
|
|
prop_type);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
guint8 buf[16];
|
|
|
|
guint amount;
|
|
|
|
|
|
|
|
while (prop_size > 0)
|
|
|
|
{
|
|
|
|
amount = MIN (16, prop_size);
|
|
|
|
info->cp += xcf_read_int8 (info->fp, buf, amount);
|
|
|
|
prop_size -= MIN (16, amount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_layer_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage,
|
|
|
|
GimpLayer *layer,
|
|
|
|
gboolean *apply_mask,
|
|
|
|
gboolean *edit_mask,
|
|
|
|
gboolean *show_mask)
|
|
|
|
{
|
|
|
|
PropType prop_type;
|
|
|
|
guint32 prop_size;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
if (!xcf_load_prop (info, &prop_type, &prop_size))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (prop_type)
|
|
|
|
{
|
|
|
|
case PROP_END:
|
|
|
|
return TRUE;
|
|
|
|
case PROP_ACTIVE_LAYER:
|
|
|
|
info->active_layer = layer;
|
|
|
|
break;
|
|
|
|
case PROP_FLOATING_SELECTION:
|
|
|
|
info->floating_sel = layer;
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp,
|
2003-04-10 22:37:06 +08:00
|
|
|
(guint32 *) &info->floating_sel_offset, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_OPACITY:
|
2002-03-04 22:52:54 +08:00
|
|
|
{
|
|
|
|
guint32 opacity;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &opacity, 1);
|
|
|
|
layer->opacity = CLAMP ((gdouble) opacity / 255.0,
|
|
|
|
GIMP_OPACITY_TRANSPARENT,
|
|
|
|
GIMP_OPACITY_OPAQUE);
|
|
|
|
}
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_VISIBLE:
|
|
|
|
{
|
|
|
|
gboolean visible;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1);
|
|
|
|
gimp_drawable_set_visible (GIMP_DRAWABLE (layer),
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
visible ? TRUE : FALSE, FALSE);
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_LINKED:
|
2003-05-09 04:26:01 +08:00
|
|
|
{
|
|
|
|
gboolean linked;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &linked, 1);
|
2003-05-14 02:30:15 +08:00
|
|
|
gimp_item_set_linked (GIMP_ITEM (layer),
|
|
|
|
linked ? TRUE : FALSE, FALSE);
|
2003-05-09 04:26:01 +08:00
|
|
|
}
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_PRESERVE_TRANSPARENCY:
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
2003-04-10 22:37:06 +08:00
|
|
|
xcf_read_int32 (info->fp, (guint32 *) &layer->preserve_trans, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_APPLY_MASK:
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) apply_mask, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_EDIT_MASK:
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) edit_mask, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_SHOW_MASK:
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) show_mask, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_OFFSETS:
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp,
|
2003-05-08 19:52:31 +08:00
|
|
|
(guint32 *) &GIMP_ITEM (layer)->offset_x, 1);
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp,
|
2003-05-08 19:52:31 +08:00
|
|
|
(guint32 *) &GIMP_ITEM (layer)->offset_y, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_MODE:
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &layer->mode, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_TATTOO:
|
|
|
|
info->cp += xcf_read_int32 (info->fp,
|
2003-04-10 22:37:06 +08:00
|
|
|
(guint32 *) &GIMP_ITEM (layer)->tattoo,
|
2001-07-04 02:38:56 +08:00
|
|
|
1);
|
|
|
|
break;
|
|
|
|
case PROP_PARASITES:
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
|
|
|
glong base = info->cp;
|
|
|
|
GimpParasite *p;
|
|
|
|
|
|
|
|
while (info->cp - base < prop_size)
|
|
|
|
{
|
2003-04-10 22:37:06 +08:00
|
|
|
p = xcf_load_parasite (info);
|
2002-02-26 01:58:50 +08:00
|
|
|
gimp_item_parasite_attach (GIMP_ITEM (layer), p);
|
|
|
|
gimp_parasite_free (p);
|
|
|
|
}
|
|
|
|
if (info->cp - base != prop_size)
|
|
|
|
g_message ("Error detected while loading a layer's parasites");
|
|
|
|
}
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
default:
|
2003-09-01 07:46:05 +08:00
|
|
|
g_message ("unexpected/unknown layer property: %d (skipping)",
|
2001-07-19 23:34:19 +08:00
|
|
|
prop_type);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
guint8 buf[16];
|
2002-02-26 01:58:50 +08:00
|
|
|
guint amount;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
while (prop_size > 0)
|
|
|
|
{
|
|
|
|
amount = MIN (16, prop_size);
|
|
|
|
info->cp += xcf_read_int8 (info->fp, buf, amount);
|
|
|
|
prop_size -= MIN (16, amount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2003-09-03 07:07:40 +08:00
|
|
|
xcf_load_channel_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage,
|
|
|
|
GimpChannel **channel)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
PropType prop_type;
|
|
|
|
guint32 prop_size;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
if (!xcf_load_prop (info, &prop_type, &prop_size))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (prop_type)
|
|
|
|
{
|
|
|
|
case PROP_END:
|
|
|
|
return TRUE;
|
|
|
|
case PROP_ACTIVE_CHANNEL:
|
2003-09-03 07:07:40 +08:00
|
|
|
info->active_channel = *channel;
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_SELECTION:
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (gimage->selection_mask);
|
2003-09-03 07:07:40 +08:00
|
|
|
gimage->selection_mask =
|
|
|
|
gimp_selection_new (gimage,
|
|
|
|
gimp_item_width (GIMP_ITEM (*channel)),
|
|
|
|
gimp_item_height (GIMP_ITEM (*channel)));
|
|
|
|
tile_manager_unref (GIMP_DRAWABLE (gimage->selection_mask)->tiles);
|
|
|
|
GIMP_DRAWABLE (gimage->selection_mask)->tiles =
|
|
|
|
GIMP_DRAWABLE (*channel)->tiles;
|
|
|
|
GIMP_DRAWABLE (*channel)->tiles = NULL;
|
|
|
|
g_object_unref (*channel);
|
|
|
|
*channel = gimage->selection_mask;
|
|
|
|
(*channel)->boundary_known = FALSE;
|
|
|
|
(*channel)->bounds_known = FALSE;
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_OPACITY:
|
|
|
|
{
|
|
|
|
guint32 opacity;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &opacity, 1);
|
2003-09-03 07:07:40 +08:00
|
|
|
(*channel)->color.a = opacity / 255.0;
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_VISIBLE:
|
|
|
|
{
|
|
|
|
gboolean visible;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1);
|
2003-09-03 07:07:40 +08:00
|
|
|
gimp_drawable_set_visible (GIMP_DRAWABLE (*channel),
|
Made drawable/layer properties (visibility, opacity etc.) undoable (fixes
2003-03-17 Michael Natterer <mitch@gimp.org>
Made drawable/layer properties (visibility, opacity etc.)
undoable (fixes bug #73893).
* app/core/core-enums.[ch]: added undo types/groups for
visibility, mode, opacity, linked and preserve_trans.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpitemundo.[ch]: new GimpUndo subclass which holds a
ref'ed GimpItem pointer so (1) this doesn't need to be done by all
undo steps related to an item and (2) the item the undo step is
for can be determined from outside the undo system.
* app/core/gimpimage-undo.[ch]: added gimp_image_undo_push_item()
which returns a new GimpItemUndo.
* app/core/gimpimage-undo-push.[ch]: use it for all item related
undo steps. Removed lots of GimpItem, GimpLayer, GimpDrawable
and GimpVectors pointers from the private undo structs. Added
undo push functions for the new undo types added above.
* app/core/gimpdrawable.[ch] (gimp_drawable_set_visible): added
"gboolean push_undo" parameter.
* app/core/gimplayer.[ch] (gimp_layer_set_opacity, _mode,
_preserve_trans, _linked): added "gboolean push_undo" parameters.
* app/core/gimpimage-mask.c
* app/core/gimpimage-merge.c
* app/core/gimplayer-floating-sel.c
* app/tools/gimpmovetool.c
* app/xcf/xcf-load.c
* app/widgets/gimpdrawablelistitem.c
* app/widgets/gimplayerlistitem.c
* app/widgets/gimplayerlistview.c: changed accordingly.
* tools/pdbgen/pdb/channel.pdb
* tools/pdbgen/pdb/layer.pdb: ditto. Added '$undo' paramaters to
the foo_accessors() functions. Removed $func from foo_accesors()
because we don't manipulate items without using getters/setters
any longer.
* app/pdb/channel_cmds.c
* app/pdb/layer_cmds.c: regenerated.
* app/widgets/gimpcellrenderertoggle.[ch]: added "clicked" signal
which carries an additional "GdkModifierType state" parameter as
in GimpCellRendererViewable .
* app/widgets/gimpcontainertreeview.c: emit "clicked" from
the toggle renderer, not "toggled" so the callbacks get the
modifier state.
* app/widgets/gimpdrawabletreeview.c: resurrected the "exclusive
visible by <shift>+click" feature as in 1.2.
* app/widgets/gimplayertreeview.c: compress layer opacity undos by
looking at the top of the undo stack and not pushing an undo if
there already is a GIMP_UNDO_DRAWABLE_OPACITY for the active
layer.
2003-03-18 02:02:41 +08:00
|
|
|
visible ? TRUE : FALSE, FALSE);
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
break;
|
2003-05-14 02:30:15 +08:00
|
|
|
case PROP_LINKED:
|
|
|
|
{
|
|
|
|
gboolean linked;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &linked, 1);
|
2003-09-03 07:07:40 +08:00
|
|
|
gimp_item_set_linked (GIMP_ITEM (*channel),
|
2003-05-14 02:30:15 +08:00
|
|
|
linked ? TRUE : FALSE, FALSE);
|
|
|
|
}
|
|
|
|
break;
|
2001-07-04 02:38:56 +08:00
|
|
|
case PROP_SHOW_MASKED:
|
2003-09-03 07:07:40 +08:00
|
|
|
{
|
|
|
|
gboolean show_masked;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &show_masked, 1);
|
|
|
|
gimp_channel_set_show_masked (*channel, show_masked);
|
|
|
|
}
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_COLOR:
|
|
|
|
{
|
|
|
|
guchar col[3];
|
|
|
|
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int8 (info->fp, (guint8 *) col, 3);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
2003-09-03 07:07:40 +08:00
|
|
|
gimp_rgb_set_uchar (&(*channel)->color, col[0], col[1], col[2]);
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_TATTOO:
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp +=
|
2003-09-03 07:07:40 +08:00
|
|
|
xcf_read_int32 (info->fp, &GIMP_ITEM (*channel)->tattoo, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_PARASITES:
|
2002-02-26 01:58:50 +08:00
|
|
|
{
|
|
|
|
glong base = info->cp;
|
|
|
|
GimpParasite *p;
|
|
|
|
|
|
|
|
while ((info->cp - base) < prop_size)
|
|
|
|
{
|
|
|
|
p = xcf_load_parasite (info);
|
2003-09-03 07:07:40 +08:00
|
|
|
gimp_item_parasite_attach (GIMP_ITEM (*channel), p);
|
2002-02-26 01:58:50 +08:00
|
|
|
gimp_parasite_free (p);
|
|
|
|
}
|
|
|
|
if (info->cp - base != prop_size)
|
|
|
|
g_message("Error detected while loading a channel's parasites");
|
|
|
|
}
|
|
|
|
break;
|
2001-07-04 02:38:56 +08:00
|
|
|
default:
|
2003-09-01 07:46:05 +08:00
|
|
|
g_message ("unexpected/unknown channel property: %d (skipping)",
|
2001-07-19 23:34:19 +08:00
|
|
|
prop_type);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
guint8 buf[16];
|
|
|
|
guint amount;
|
|
|
|
|
|
|
|
while (prop_size > 0)
|
|
|
|
{
|
|
|
|
amount = MIN (16, prop_size);
|
|
|
|
info->cp += xcf_read_int8 (info->fp, buf, amount);
|
|
|
|
prop_size -= MIN (16, amount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_prop (XcfInfo *info,
|
|
|
|
PropType *prop_type,
|
|
|
|
guint32 *prop_size)
|
|
|
|
{
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) prop_type, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) prop_size, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpLayer *
|
|
|
|
xcf_load_layer (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpLayerMask *layer_mask;
|
2003-06-24 21:59:36 +08:00
|
|
|
GimpParasite *parasite;
|
2001-07-04 02:38:56 +08:00
|
|
|
guint32 hierarchy_offset;
|
|
|
|
guint32 layer_mask_offset;
|
|
|
|
gboolean apply_mask;
|
|
|
|
gboolean edit_mask;
|
|
|
|
gboolean show_mask;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint type;
|
|
|
|
gint add_floating_sel;
|
|
|
|
gchar *name;
|
2003-07-08 18:38:13 +08:00
|
|
|
GimpText *text = NULL;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* check and see if this is the drawable the floating selection
|
|
|
|
* is attached to. if it is then we'll do the attachment at
|
|
|
|
* the end of this function.
|
|
|
|
*/
|
|
|
|
add_floating_sel = (info->cp == info->floating_sel_offset);
|
|
|
|
|
|
|
|
/* read in the layer width, height, type and name */
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &type, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
|
|
|
|
/* create a new layer */
|
2003-09-01 07:46:05 +08:00
|
|
|
layer = gimp_layer_new (gimage, width, height,
|
2001-12-09 07:12:59 +08:00
|
|
|
type, name, 255, GIMP_NORMAL_MODE);
|
2001-07-04 02:38:56 +08:00
|
|
|
g_free (name);
|
2003-06-24 21:59:36 +08:00
|
|
|
if (! layer)
|
2001-07-04 02:38:56 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* read in the layer properties */
|
2003-06-24 21:59:36 +08:00
|
|
|
if (! xcf_load_layer_props (info, gimage, layer,
|
|
|
|
&apply_mask, &edit_mask, &show_mask))
|
2001-07-04 02:38:56 +08:00
|
|
|
goto error;
|
|
|
|
|
2003-06-24 21:59:36 +08:00
|
|
|
/* check for a gimp-text parasite */
|
|
|
|
parasite = gimp_item_parasite_find (GIMP_ITEM (layer),
|
|
|
|
gimp_text_parasite_name ());
|
|
|
|
if (parasite)
|
|
|
|
{
|
2003-07-08 18:38:13 +08:00
|
|
|
text = gimp_text_from_parasite (parasite);
|
2003-06-24 21:59:36 +08:00
|
|
|
|
|
|
|
if (text)
|
2003-07-08 18:38:13 +08:00
|
|
|
gimp_parasite_list_remove (GIMP_ITEM (layer)->parasites,
|
|
|
|
gimp_parasite_name (parasite));
|
2003-06-24 21:59:36 +08:00
|
|
|
}
|
2003-06-25 03:45:55 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* check for a GDynText parasite */
|
|
|
|
parasite = gimp_item_parasite_find (GIMP_ITEM (layer),
|
|
|
|
gimp_text_gdyntext_parasite_name ());
|
|
|
|
|
|
|
|
if (parasite)
|
2003-07-08 18:38:13 +08:00
|
|
|
text = gimp_text_from_gdyntext_parasite (parasite);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if there's a text object, convert the layer to a text layer */
|
|
|
|
if (text)
|
|
|
|
{
|
|
|
|
gboolean active = (info->active_layer == layer);
|
|
|
|
gboolean floating = (info->floating_sel == layer);
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2003-07-08 18:38:13 +08:00
|
|
|
layer = gimp_text_layer_from_layer (layer, text);
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2003-07-08 18:38:13 +08:00
|
|
|
if (active)
|
2003-09-01 07:46:05 +08:00
|
|
|
info->active_layer = layer;
|
2003-07-08 18:38:13 +08:00
|
|
|
if (floating)
|
|
|
|
info->floating_sel = layer;
|
2003-06-25 03:45:55 +08:00
|
|
|
}
|
2003-06-24 21:59:36 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* read the hierarchy and layer mask offsets */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &layer_mask_offset, 1);
|
|
|
|
|
|
|
|
/* read in the hierarchy */
|
2003-06-24 21:59:36 +08:00
|
|
|
if (! xcf_seek_pos (info, hierarchy_offset, NULL))
|
2002-12-20 14:26:34 +08:00
|
|
|
goto error;
|
|
|
|
|
2003-06-24 21:59:36 +08:00
|
|
|
if (! xcf_load_hierarchy (info, GIMP_DRAWABLE (layer)->tiles))
|
2001-07-04 02:38:56 +08:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* read in the layer mask */
|
|
|
|
if (layer_mask_offset != 0)
|
|
|
|
{
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, layer_mask_offset, NULL))
|
|
|
|
goto error;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
layer_mask = xcf_load_layer_mask (info, gimage);
|
2003-06-24 21:59:36 +08:00
|
|
|
if (! layer_mask)
|
2001-07-04 02:38:56 +08:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* set the offsets of the layer_mask */
|
2003-05-08 19:52:31 +08:00
|
|
|
GIMP_ITEM (layer_mask)->offset_x = GIMP_ITEM (layer)->offset_x;
|
|
|
|
GIMP_ITEM (layer_mask)->offset_y = GIMP_ITEM (layer)->offset_y;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
gimp_layer_add_mask (layer, layer_mask, FALSE);
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (layer_mask);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
layer->mask->apply_mask = apply_mask;
|
|
|
|
layer->mask->edit_mask = edit_mask;
|
|
|
|
layer->mask->show_mask = show_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attach the floating selection... */
|
|
|
|
if (add_floating_sel)
|
2003-07-08 18:38:13 +08:00
|
|
|
floating_sel_attach (info->floating_sel, GIMP_DRAWABLE (layer));
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
return layer;
|
|
|
|
|
|
|
|
error:
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (layer);
|
2001-07-04 02:38:56 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpChannel *
|
|
|
|
xcf_load_channel (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
GimpChannel *channel;
|
|
|
|
guint32 hierarchy_offset;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
2003-05-19 06:07:36 +08:00
|
|
|
gboolean add_floating_sel;
|
|
|
|
gboolean is_qmask = FALSE;
|
2001-07-04 02:38:56 +08:00
|
|
|
gchar *name;
|
2002-03-04 01:38:12 +08:00
|
|
|
GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* check and see if this is the drawable the floating selection
|
|
|
|
* is attached to. if it is then we'll do the attachment at
|
|
|
|
* the end of this function.
|
|
|
|
*/
|
|
|
|
add_floating_sel = (info->cp == info->floating_sel_offset);
|
|
|
|
|
|
|
|
/* read in the layer width, height and name */
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
|
2003-05-19 06:07:36 +08:00
|
|
|
if (name)
|
|
|
|
is_qmask = (strcmp (name, "Qmask") == 0);
|
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* create a new channel */
|
|
|
|
channel = gimp_channel_new (gimage, width, height, name, &color);
|
|
|
|
g_free (name);
|
|
|
|
if (!channel)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* read in the channel properties */
|
2003-09-03 07:07:40 +08:00
|
|
|
if (!xcf_load_channel_props (info, gimage, &channel))
|
2001-07-04 02:38:56 +08:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* read the hierarchy and layer mask offsets */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
|
|
|
|
|
|
|
|
/* read in the hierarchy */
|
2002-12-20 14:26:34 +08:00
|
|
|
if (!xcf_seek_pos (info, hierarchy_offset, NULL))
|
|
|
|
goto error;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (channel)->tiles))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* attach the floating selection... */
|
|
|
|
if (add_floating_sel)
|
|
|
|
{
|
|
|
|
GimpLayer *floating_sel;
|
|
|
|
|
|
|
|
floating_sel = info->floating_sel;
|
|
|
|
floating_sel_attach (floating_sel, GIMP_DRAWABLE (channel));
|
|
|
|
}
|
|
|
|
|
2003-05-19 06:07:36 +08:00
|
|
|
if (is_qmask)
|
|
|
|
gimage->qmask_state = TRUE;
|
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
return channel;
|
|
|
|
|
2003-04-10 22:15:24 +08:00
|
|
|
error:
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (channel);
|
2001-07-04 02:38:56 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpLayerMask *
|
|
|
|
xcf_load_layer_mask (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
GimpLayerMask *layer_mask;
|
|
|
|
guint32 hierarchy_offset;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint add_floating_sel;
|
|
|
|
gchar *name;
|
2002-03-04 01:38:12 +08:00
|
|
|
GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* check and see if this is the drawable the floating selection
|
|
|
|
* is attached to. if it is then we'll do the attachment at
|
|
|
|
* the end of this function.
|
|
|
|
*/
|
|
|
|
add_floating_sel = (info->cp == info->floating_sel_offset);
|
|
|
|
|
|
|
|
/* read in the layer width, height and name */
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
|
|
|
|
/* create a new layer mask */
|
|
|
|
layer_mask = gimp_layer_mask_new (gimage, width, height, name, &color);
|
|
|
|
g_free (name);
|
|
|
|
if (!layer_mask)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* read in the layer_mask properties */
|
2003-09-03 07:07:40 +08:00
|
|
|
if (!xcf_load_channel_props (info, gimage, (GimpChannel **) &layer_mask))
|
2001-07-04 02:38:56 +08:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* read the hierarchy and layer mask offsets */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
|
|
|
|
|
|
|
|
/* read in the hierarchy */
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, hierarchy_offset, NULL))
|
|
|
|
goto error;
|
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer_mask)->tiles))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* attach the floating selection... */
|
|
|
|
if (add_floating_sel)
|
|
|
|
{
|
|
|
|
GimpLayer *floating_sel;
|
|
|
|
|
|
|
|
floating_sel = info->floating_sel;
|
|
|
|
floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer_mask));
|
|
|
|
}
|
|
|
|
|
|
|
|
return layer_mask;
|
|
|
|
|
2003-04-10 22:15:24 +08:00
|
|
|
error:
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (layer_mask);
|
2001-07-04 02:38:56 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_hierarchy (XcfInfo *info,
|
|
|
|
TileManager *tiles)
|
|
|
|
{
|
|
|
|
guint32 saved_pos;
|
|
|
|
guint32 offset;
|
|
|
|
guint32 junk;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint bpp;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &bpp, 1);
|
|
|
|
|
|
|
|
/* make sure the values in the file correspond to the values
|
|
|
|
* calculated when the TileManager was created.
|
|
|
|
*/
|
|
|
|
if (width != tile_manager_width (tiles) ||
|
|
|
|
height != tile_manager_height (tiles) ||
|
|
|
|
bpp != tile_manager_bpp (tiles))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* load in the levels...we make sure that the number of levels
|
|
|
|
* calculated when the TileManager was created is the same
|
|
|
|
* as the number of levels found in the file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &offset, 1); /* top level */
|
|
|
|
|
|
|
|
/* discard offsets for layers below first, if any.
|
|
|
|
*/
|
2003-09-01 07:46:05 +08:00
|
|
|
do
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &junk, 1);
|
|
|
|
}
|
|
|
|
while (junk != 0);
|
|
|
|
|
|
|
|
/* save the current position as it is where the
|
|
|
|
* next level offset is stored.
|
|
|
|
*/
|
|
|
|
saved_pos = info->cp;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* seek to the level offset */
|
2002-12-20 14:26:34 +08:00
|
|
|
if (!xcf_seek_pos (info, offset, NULL))
|
|
|
|
return FALSE;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* read in the level */
|
|
|
|
if (!xcf_load_level (info, tiles))
|
|
|
|
return FALSE;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* restore the saved position so we'll be ready to
|
|
|
|
* read the next offset.
|
|
|
|
*/
|
2002-12-20 14:26:34 +08:00
|
|
|
if (!xcf_seek_pos (info, saved_pos, NULL))
|
|
|
|
return FALSE;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_level (XcfInfo *info,
|
|
|
|
TileManager *tiles)
|
|
|
|
{
|
|
|
|
guint32 saved_pos;
|
|
|
|
guint32 offset, offset2;
|
|
|
|
guint ntiles;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint i;
|
|
|
|
gint fail;
|
|
|
|
Tile *previous;
|
|
|
|
Tile *tile;
|
|
|
|
|
2003-04-10 22:37:06 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &height, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
if (width != tile_manager_width (tiles) ||
|
|
|
|
height != tile_manager_height (tiles))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* read in the first tile offset.
|
|
|
|
* if it is '0', then this tile level is empty
|
|
|
|
* and we can simply return.
|
|
|
|
*/
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &offset, 1);
|
|
|
|
if (offset == 0)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* Initialise the reference for the in-memory tile-compression
|
|
|
|
*/
|
|
|
|
previous = NULL;
|
|
|
|
|
|
|
|
ntiles = tiles->ntile_rows * tiles->ntile_cols;
|
|
|
|
for (i = 0; i < ntiles; i++)
|
|
|
|
{
|
|
|
|
fail = FALSE;
|
|
|
|
|
|
|
|
if (offset == 0)
|
|
|
|
{
|
|
|
|
g_message ("not enough tiles found in level");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* save the current position as it is where the
|
|
|
|
* next tile offset is stored.
|
|
|
|
*/
|
|
|
|
saved_pos = info->cp;
|
|
|
|
|
|
|
|
/* read in the offset of the next tile so we can calculate the amount
|
|
|
|
of data needed for this tile*/
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &offset2, 1);
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* if the offset is 0 then we need to read in the maximum possible
|
|
|
|
allowing for negative compression */
|
|
|
|
if (offset2 == 0)
|
2003-09-01 07:46:05 +08:00
|
|
|
offset2 = offset + TILE_WIDTH * TILE_WIDTH * 4 * 1.5;
|
2001-07-04 02:38:56 +08:00
|
|
|
/* 1.5 is probably more
|
|
|
|
than we need to allow */
|
|
|
|
|
|
|
|
/* seek to the tile offset */
|
2002-12-20 14:26:34 +08:00
|
|
|
if (! xcf_seek_pos (info, offset, NULL))
|
|
|
|
return FALSE;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* get the tile from the tile manager */
|
|
|
|
tile = tile_manager_get (tiles, i, TRUE, TRUE);
|
|
|
|
|
|
|
|
/* read in the tile */
|
|
|
|
switch (info->compression)
|
|
|
|
{
|
|
|
|
case COMPRESS_NONE:
|
|
|
|
if (!xcf_load_tile (info, tile))
|
|
|
|
fail = TRUE;
|
|
|
|
break;
|
|
|
|
case COMPRESS_RLE:
|
|
|
|
if (!xcf_load_tile_rle (info, tile, offset2 - offset))
|
|
|
|
fail = TRUE;
|
|
|
|
break;
|
|
|
|
case COMPRESS_ZLIB:
|
|
|
|
g_error ("xcf: zlib compression unimplemented");
|
|
|
|
fail = TRUE;
|
|
|
|
break;
|
|
|
|
case COMPRESS_FRACTAL:
|
|
|
|
g_error ("xcf: fractal compression unimplemented");
|
|
|
|
fail = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2003-09-01 07:46:05 +08:00
|
|
|
if (fail)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
tile_release (tile, TRUE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
/* To potentially save memory, we compare the
|
|
|
|
* newly-fetched tile against the last one, and
|
|
|
|
* if they're the same we copy-on-write mirror one against
|
|
|
|
* the other.
|
|
|
|
*/
|
2003-09-01 07:46:05 +08:00
|
|
|
if (previous != NULL)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
tile_lock (previous);
|
|
|
|
if (tile_ewidth (tile) == tile_ewidth (previous) &&
|
|
|
|
tile_eheight (tile) == tile_eheight (previous) &&
|
|
|
|
tile_bpp (tile) == tile_bpp (previous) &&
|
2003-09-01 07:46:05 +08:00
|
|
|
memcmp (tile_data_pointer (tile, 0, 0),
|
2001-07-04 02:38:56 +08:00
|
|
|
tile_data_pointer (previous, 0, 0),
|
|
|
|
tile_size (tile)) == 0)
|
|
|
|
tile_manager_map (tiles, i, previous);
|
|
|
|
tile_release (previous, FALSE);
|
|
|
|
}
|
|
|
|
tile_release (tile, TRUE);
|
|
|
|
previous = tile_manager_get (tiles, i, FALSE, FALSE);
|
|
|
|
|
|
|
|
/* restore the saved position so we'll be ready to
|
|
|
|
* read the next offset.
|
|
|
|
*/
|
2002-12-20 14:26:34 +08:00
|
|
|
if (!xcf_seek_pos (info, saved_pos, NULL))
|
|
|
|
return FALSE;
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
/* read in the offset of the next tile */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &offset, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset != 0)
|
|
|
|
{
|
|
|
|
g_message ("encountered garbage after reading level: %d", offset);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_tile (XcfInfo *info,
|
|
|
|
Tile *tile)
|
|
|
|
{
|
|
|
|
#ifdef SWAP_FROM_FILE
|
|
|
|
|
|
|
|
if (!info->swap_num)
|
|
|
|
{
|
|
|
|
info->ref_count = g_new (int, 1);
|
2003-09-01 07:46:05 +08:00
|
|
|
info->swap_num = tile_swap_add (info->filename,
|
|
|
|
xcf_swap_func,
|
2001-07-04 02:38:56 +08:00
|
|
|
info->ref_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
tile->swap_num = info->swap_num;
|
|
|
|
tile->swap_offset = info->cp;
|
|
|
|
*info->ref_count += 1;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2003-09-01 07:46:05 +08:00
|
|
|
info->cp += xcf_read_int8 (info->fp, tile_data_pointer(tile, 0, 0),
|
2001-07-04 02:38:56 +08:00
|
|
|
tile_size (tile));
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_tile_rle (XcfInfo *info,
|
|
|
|
Tile *tile,
|
|
|
|
int data_length)
|
|
|
|
{
|
|
|
|
guchar *data;
|
|
|
|
guchar val;
|
|
|
|
gint size;
|
|
|
|
gint count;
|
|
|
|
gint length;
|
|
|
|
gint bpp;
|
|
|
|
gint i, j;
|
|
|
|
gint nmemb_read_successfully;
|
|
|
|
guchar *xcfdata, *xcfodata, *xcfdatalimit;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
data = tile_data_pointer (tile, 0, 0);
|
|
|
|
bpp = tile_bpp (tile);
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
xcfdata = xcfodata = g_malloc (data_length);
|
|
|
|
|
|
|
|
/* we have to use fread instead of xcf_read_* because we may be
|
|
|
|
reading past the end of the file here */
|
2003-04-10 22:37:06 +08:00
|
|
|
nmemb_read_successfully = fread ((gchar *) xcfdata, sizeof (gchar),
|
2001-07-04 02:38:56 +08:00
|
|
|
data_length, info->fp);
|
|
|
|
info->cp += nmemb_read_successfully;
|
|
|
|
|
|
|
|
xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
for (i = 0; i < bpp; i++)
|
|
|
|
{
|
2003-04-10 22:37:06 +08:00
|
|
|
data = (guchar *) tile_data_pointer (tile, 0, 0) + i;
|
2001-07-04 02:38:56 +08:00
|
|
|
size = tile_ewidth (tile) * tile_eheight (tile);
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
while (size > 0)
|
|
|
|
{
|
|
|
|
if (xcfdata > xcfdatalimit)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = *xcfdata++;
|
|
|
|
|
|
|
|
length = val;
|
|
|
|
if (length >= 128)
|
|
|
|
{
|
|
|
|
length = 255 - (length - 1);
|
|
|
|
if (length == 128)
|
|
|
|
{
|
|
|
|
if (xcfdata >= xcfdatalimit)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
length = (*xcfdata << 8) + xcfdata[1];
|
|
|
|
xcfdata += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
count += length;
|
|
|
|
size -= length;
|
|
|
|
|
|
|
|
if (size < 0)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (&xcfdata[length-1] > xcfdatalimit)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (length-- > 0)
|
|
|
|
{
|
|
|
|
*data = *xcfdata++;
|
|
|
|
data += bpp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
length += 1;
|
|
|
|
if (length == 128)
|
|
|
|
{
|
|
|
|
if (xcfdata >= xcfdatalimit)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
length = (*xcfdata << 8) + xcfdata[1];
|
|
|
|
xcfdata += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
count += length;
|
|
|
|
size -= length;
|
|
|
|
|
|
|
|
if (size < 0)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xcfdata > xcfdatalimit)
|
|
|
|
{
|
|
|
|
goto bogus_rle;
|
|
|
|
}
|
|
|
|
|
|
|
|
val = *xcfdata++;
|
|
|
|
|
|
|
|
for (j = 0; j < length; j++)
|
|
|
|
{
|
|
|
|
*data = val;
|
|
|
|
data += bpp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_free (xcfodata);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
bogus_rle:
|
|
|
|
if (xcfodata)
|
|
|
|
g_free (xcfodata);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2003-05-15 03:21:42 +08:00
|
|
|
static GimpParasite *
|
|
|
|
xcf_load_parasite (XcfInfo *info)
|
|
|
|
{
|
|
|
|
GimpParasite *p;
|
|
|
|
|
|
|
|
p = g_new (GimpParasite, 1);
|
|
|
|
info->cp += xcf_read_string (info->fp, &p->name, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &p->flags, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &p->size, 1);
|
|
|
|
p->data = g_new (gchar, p->size);
|
|
|
|
info->cp += xcf_read_int8 (info->fp, p->data, p->size);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2003-05-22 01:38:14 +08:00
|
|
|
static gboolean
|
2003-05-15 03:21:42 +08:00
|
|
|
xcf_load_old_paths (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
2003-05-22 01:38:14 +08:00
|
|
|
guint32 num_paths;
|
|
|
|
guint32 last_selected_row;
|
2003-05-15 03:21:42 +08:00
|
|
|
GimpVectors *active_vectors;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &last_selected_row, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &num_paths, 1);
|
|
|
|
|
|
|
|
while (num_paths-- > 0)
|
2003-05-22 01:38:14 +08:00
|
|
|
xcf_load_old_path (info, gimage);
|
2003-05-15 03:21:42 +08:00
|
|
|
|
|
|
|
active_vectors = (GimpVectors *)
|
|
|
|
gimp_container_get_child_by_index (gimage->vectors, last_selected_row);
|
|
|
|
|
|
|
|
if (active_vectors)
|
|
|
|
gimp_image_set_active_vectors (gimage, active_vectors);
|
|
|
|
|
2003-05-22 01:38:14 +08:00
|
|
|
return TRUE;
|
2003-05-15 03:21:42 +08:00
|
|
|
}
|
|
|
|
|
2003-05-22 01:38:14 +08:00
|
|
|
static gboolean
|
2003-05-15 03:21:42 +08:00
|
|
|
xcf_load_old_path (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
2003-05-23 03:02:38 +08:00
|
|
|
gchar *name;
|
|
|
|
guint32 locked;
|
|
|
|
guint8 state;
|
|
|
|
guint32 closed;
|
|
|
|
guint32 num_points;
|
|
|
|
guint32 version; /* changed from num_paths */
|
|
|
|
GimpTattoo tattoo = 0;
|
|
|
|
GimpVectors *vectors;
|
|
|
|
GimpVectorsCompatPoint *points;
|
|
|
|
gint i;
|
2003-05-15 03:21:42 +08:00
|
|
|
|
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &locked, 1);
|
|
|
|
info->cp += xcf_read_int8 (info->fp, &state, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &closed, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &num_points, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &version, 1);
|
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
if (version == 2)
|
2003-05-15 03:21:42 +08:00
|
|
|
{
|
2003-05-22 01:38:14 +08:00
|
|
|
guint32 dummy;
|
|
|
|
|
2003-05-15 03:21:42 +08:00
|
|
|
/* Had extra type field and points are stored as doubles */
|
2003-05-22 01:38:14 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &dummy, 1);
|
2003-05-15 03:21:42 +08:00
|
|
|
}
|
|
|
|
else if (version == 3)
|
|
|
|
{
|
2003-05-22 01:38:14 +08:00
|
|
|
guint32 dummy;
|
|
|
|
|
2003-05-15 03:21:42 +08:00
|
|
|
/* Has extra tatto field */
|
2003-05-23 03:02:38 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &dummy, 1);
|
2003-05-15 03:21:42 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &tattoo, 1);
|
|
|
|
}
|
2003-05-23 03:02:38 +08:00
|
|
|
else if (version != 1)
|
2003-05-15 03:21:42 +08:00
|
|
|
{
|
|
|
|
g_warning ("Unknown path type. Possibly corrupt XCF file");
|
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
2003-05-15 03:21:42 +08:00
|
|
|
|
2003-09-09 23:46:59 +08:00
|
|
|
/* skip empty compatibility paths */
|
|
|
|
if (num_points == 0)
|
|
|
|
return FALSE;
|
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
points = g_new0 (GimpVectorsCompatPoint, num_points);
|
2003-05-22 01:38:14 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
for (i = 0; i < num_points; i++)
|
2003-05-15 20:32:53 +08:00
|
|
|
{
|
2003-05-23 03:02:38 +08:00
|
|
|
if (version == 1)
|
2003-05-15 20:32:53 +08:00
|
|
|
{
|
2003-05-23 03:02:38 +08:00
|
|
|
gint32 x;
|
|
|
|
gint32 y;
|
2003-05-15 20:32:53 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, &points[i].type, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &x, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &y, 1);
|
2003-05-15 20:32:53 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
points[i].x = x;
|
|
|
|
points[i].y = y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gfloat x;
|
|
|
|
gfloat y;
|
2003-09-01 07:46:05 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, &points[i].type, 1);
|
|
|
|
info->cp += xcf_read_float (info->fp, &x, 1);
|
|
|
|
info->cp += xcf_read_float (info->fp, &y, 1);
|
2003-05-19 00:36:10 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
points[i].x = x;
|
|
|
|
points[i].y = y;
|
|
|
|
}
|
|
|
|
}
|
2003-05-19 00:36:10 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
vectors = gimp_vectors_compat_new (gimage, name, points, num_points, closed);
|
2003-05-15 20:32:53 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
g_free (points);
|
2003-05-15 03:21:42 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
GIMP_ITEM (vectors)->linked = locked;
|
2003-05-15 20:32:53 +08:00
|
|
|
|
2003-05-23 03:02:38 +08:00
|
|
|
if (tattoo)
|
|
|
|
GIMP_ITEM (vectors)->tattoo = tattoo;
|
2003-05-15 03:21:42 +08:00
|
|
|
|
|
|
|
gimp_image_add_vectors (gimage, vectors,
|
|
|
|
gimp_container_num_children (gimage->vectors));
|
|
|
|
|
2003-05-22 01:38:14 +08:00
|
|
|
return TRUE;
|
2003-05-15 03:21:42 +08:00
|
|
|
}
|
|
|
|
|
2003-09-09 23:46:59 +08:00
|
|
|
static gboolean
|
|
|
|
xcf_load_vectors (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
guint32 num_paths;
|
|
|
|
guint32 last_selected_row;
|
|
|
|
guint32 version;
|
|
|
|
GimpVectors *active_vectors;
|
|
|
|
guint32 base;
|
|
|
|
|
|
|
|
g_printerr ("xcf_load_vectors\n");
|
|
|
|
|
|
|
|
base = info->cp;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &version, 1);
|
|
|
|
|
|
|
|
if (version != 1)
|
|
|
|
{
|
|
|
|
g_warning ("Unknown vectors type %d. Possibly corrupt XCF file", version);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &last_selected_row, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &num_paths, 1);
|
|
|
|
|
|
|
|
g_printerr ("%d paths (active: %d)\n", num_paths, last_selected_row);
|
|
|
|
|
|
|
|
while (num_paths-- > 0)
|
|
|
|
xcf_load_vector (info, gimage);
|
|
|
|
|
|
|
|
active_vectors = (GimpVectors *)
|
|
|
|
gimp_container_get_child_by_index (gimage->vectors, last_selected_row);
|
|
|
|
|
|
|
|
if (active_vectors)
|
|
|
|
gimp_image_set_active_vectors (gimage, active_vectors);
|
|
|
|
|
|
|
|
g_printerr ("xcf_load_vectors: loaded %d bytes\n", info->cp - base);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_load_vector (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
gchar *name;
|
|
|
|
guint32 locked;
|
|
|
|
guint32 num_strokes;
|
|
|
|
GimpTattoo tattoo = 0;
|
|
|
|
GimpVectors *vectors;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
g_printerr ("xcf_load_vector\n");
|
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &locked, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &tattoo, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &num_strokes, 1);
|
|
|
|
|
|
|
|
g_printerr ("name: %s, locked: %d, tattoo: %d, num_strokes %d\n", name, locked, tattoo, num_strokes);
|
|
|
|
|
|
|
|
vectors = gimp_vectors_new (gimage, name);
|
|
|
|
|
|
|
|
for (i = 0; i < num_strokes; i++)
|
|
|
|
{
|
|
|
|
gint stroke_type_id;
|
|
|
|
gint closed;
|
|
|
|
gint num_axes;
|
|
|
|
gint num_control_points;
|
|
|
|
gint type;
|
|
|
|
gfloat coords[6] = { 0.0, 0.0, 1.0, 0.5, 0.5, 0.5 };
|
|
|
|
GimpStroke *stroke;
|
|
|
|
|
|
|
|
GValueArray *control_points;
|
|
|
|
GValue value = { 0, };
|
|
|
|
GimpAnchor anchor;
|
|
|
|
GType stroke_type;
|
|
|
|
|
|
|
|
g_value_init (&value, gimp_anchor_get_type ());
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &stroke_type_id, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &closed, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &num_axes, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &num_control_points, 1);
|
|
|
|
|
|
|
|
g_printerr ("stroke_type: %d, closed: %d, num_axes %d, len %d\n",
|
|
|
|
stroke_type_id, closed, num_axes, num_control_points);
|
|
|
|
|
|
|
|
switch (stroke_type_id)
|
|
|
|
{
|
|
|
|
case XCF_STROKETYPE_BEZIER_STROKE:
|
|
|
|
stroke_type = gimp_bezier_stroke_get_type ();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_printerr ("skipping unknown stroke type\n");
|
2003-09-10 18:40:57 +08:00
|
|
|
xcf_seek_pos (info,
|
2003-09-09 23:46:59 +08:00
|
|
|
info->cp + 4 * num_axes * num_control_points,
|
|
|
|
NULL);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
control_points = g_value_array_new (num_control_points);
|
|
|
|
|
|
|
|
anchor.selected = FALSE;
|
|
|
|
|
|
|
|
for (j=0; j < num_control_points; j++)
|
|
|
|
{
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &type, 1);
|
|
|
|
info->cp += xcf_read_float (info->fp, coords, num_axes);
|
|
|
|
|
|
|
|
anchor.type = type;
|
|
|
|
anchor.position.x = coords[0];
|
|
|
|
anchor.position.y = coords[1];
|
|
|
|
anchor.position.pressure = coords[2];
|
|
|
|
anchor.position.xtilt = coords[3];
|
|
|
|
anchor.position.ytilt = coords[4];
|
|
|
|
anchor.position.wheel = coords[5];
|
|
|
|
|
|
|
|
g_value_set_boxed (&value, &anchor);
|
|
|
|
g_value_array_append (control_points, &value);
|
|
|
|
|
|
|
|
g_printerr ("Anchor: %d, (%f, %f, %f, %f, %f, %f)\n", type,
|
|
|
|
coords[0], coords[1], coords[2], coords[3],
|
|
|
|
coords[4], coords[5]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
g_value_unset (&value);
|
|
|
|
|
|
|
|
/* here the stroke has to be created */
|
|
|
|
stroke = GIMP_STROKE (g_object_new (stroke_type,
|
|
|
|
"closed", closed,
|
|
|
|
"control-points", control_points,
|
|
|
|
NULL));
|
|
|
|
|
|
|
|
gimp_vectors_stroke_add (vectors, stroke);
|
|
|
|
}
|
|
|
|
|
|
|
|
GIMP_ITEM (vectors)->linked = locked;
|
|
|
|
|
|
|
|
if (tattoo)
|
|
|
|
GIMP_ITEM (vectors)->tattoo = tattoo;
|
|
|
|
|
|
|
|
gimp_image_add_vectors (gimage, vectors,
|
|
|
|
gimp_container_num_children (gimage->vectors));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2001-07-04 02:38:56 +08:00
|
|
|
#ifdef SWAP_FROM_FILE
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
xcf_swap_func (gint fd,
|
|
|
|
Tile *tile,
|
|
|
|
gint cmd,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
gint bytes;
|
|
|
|
gint err;
|
|
|
|
gint nleft;
|
|
|
|
gint *ref_count;
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case SWAP_IN:
|
|
|
|
lseek (fd, tile->swap_offset, SEEK_SET);
|
|
|
|
|
|
|
|
bytes = tile_size (tile);
|
|
|
|
tile_alloc (tile);
|
|
|
|
|
|
|
|
nleft = bytes;
|
|
|
|
while (nleft > 0)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
err = read (fd, tile->data + bytes - nleft, nleft);
|
|
|
|
} while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR)));
|
|
|
|
|
|
|
|
if (err <= 0)
|
|
|
|
{
|
2001-07-19 23:34:19 +08:00
|
|
|
g_message ("unable to read tile data from xcf file: "
|
|
|
|
"%d ( %d ) bytes read", err, nleft);
|
2001-07-04 02:38:56 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nleft -= err;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWAP_OUT:
|
|
|
|
case SWAP_DELETE:
|
|
|
|
case SWAP_COMPRESS:
|
|
|
|
ref_count = user_data;
|
|
|
|
*ref_count -= 1;
|
|
|
|
if (*ref_count == 0)
|
|
|
|
{
|
|
|
|
tile_swap_remove (tile->swap_num);
|
|
|
|
g_free (ref_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
tile->swap_num = 1;
|
|
|
|
tile->swap_offset = -1;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|