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/gimpchannel.h"
|
|
|
|
#include "core/gimpcontainer.h"
|
|
|
|
#include "core/gimpdrawable.h"
|
|
|
|
#include "core/gimpimage.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"
|
2001-07-11 20:39:49 +08:00
|
|
|
#include "core/gimpunit.h"
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
#include "xcf-private.h"
|
|
|
|
#include "xcf-load.h"
|
|
|
|
#include "xcf-read.h"
|
|
|
|
#include "xcf-seek.h"
|
|
|
|
|
|
|
|
#include "path.h"
|
|
|
|
#include "pathP.h"
|
|
|
|
|
|
|
|
#include "libgimp/gimpintl.h"
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
#ifdef SWAP_FROM_FILE
|
|
|
|
static gboolean xcf_swap_func (gint fd,
|
|
|
|
Tile *tile,
|
|
|
|
gint cmd,
|
|
|
|
gpointer user_data);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static GimpParasite *
|
2001-07-19 23:34:19 +08:00
|
|
|
xcf_load_parasite (XcfInfo *info)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PathPoint*
|
2001-07-19 23:34:19 +08:00
|
|
|
xcf_load_bz_point_version1 (XcfInfo *info)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
PathPoint *ptr;
|
|
|
|
guint32 type;
|
|
|
|
gint32 x;
|
|
|
|
gint32 y;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &type, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*)&x, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*)&y, 1);
|
|
|
|
|
|
|
|
ptr = path_point_new (type, (gdouble)x, (gdouble)y);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PathPoint *
|
2001-07-19 23:34:19 +08:00
|
|
|
xcf_load_bz_point (XcfInfo *info)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
PathPoint *ptr;
|
|
|
|
guint32 type;
|
|
|
|
gfloat x;
|
|
|
|
gfloat y;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &type, 1);
|
|
|
|
info->cp += xcf_read_float (info->fp, &x, 1);
|
|
|
|
info->cp += xcf_read_float (info->fp, &y, 1);
|
|
|
|
|
|
|
|
ptr = path_point_new (type, (gdouble)x, (gdouble)y);
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Path *
|
2001-07-19 23:34:19 +08:00
|
|
|
xcf_load_path (GimpImage *gimage,
|
2001-07-04 02:38:56 +08:00
|
|
|
XcfInfo *info)
|
|
|
|
{
|
2001-08-17 22:27:31 +08:00
|
|
|
Path *bzp;
|
|
|
|
gchar *name;
|
|
|
|
guint32 locked;
|
|
|
|
guint8 state;
|
|
|
|
guint32 closed;
|
|
|
|
guint32 num_points;
|
|
|
|
guint32 version; /* changed from num_paths */
|
|
|
|
GimpTattoo tattoo = 0;
|
|
|
|
GSList *pts_list = NULL;
|
|
|
|
PathType ptype;
|
2001-07-04 02:38:56 +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);
|
|
|
|
|
|
|
|
if (version == 1)
|
|
|
|
{
|
|
|
|
ptype = BEZIER;
|
|
|
|
while (num_points-- > 0)
|
|
|
|
{
|
|
|
|
PathPoint *bpt;
|
|
|
|
/* Read in a path */
|
2001-07-19 23:34:19 +08:00
|
|
|
bpt = xcf_load_bz_point_version1 (info);
|
2001-07-04 02:38:56 +08:00
|
|
|
pts_list = g_slist_append (pts_list, bpt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (version == 2)
|
|
|
|
{
|
|
|
|
/* Had extra type field and points are stored as doubles */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *)&ptype, 1);
|
|
|
|
while(num_points-- > 0)
|
|
|
|
{
|
|
|
|
PathPoint *bpt;
|
|
|
|
/* Read in a path */
|
2001-07-19 23:34:19 +08:00
|
|
|
bpt = xcf_load_bz_point (info);
|
2001-07-04 02:38:56 +08:00
|
|
|
pts_list = g_slist_append (pts_list, bpt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (version == 3)
|
|
|
|
{
|
|
|
|
/* Has extra tatto field */
|
2001-08-17 22:27:31 +08:00
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &ptype, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &tattoo, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
while (num_points-- > 0)
|
|
|
|
{
|
|
|
|
PathPoint *bpt;
|
|
|
|
/* Read in a path */
|
2001-07-19 23:34:19 +08:00
|
|
|
bpt = xcf_load_bz_point (info);
|
2001-07-04 02:38:56 +08:00
|
|
|
pts_list = g_slist_append (pts_list, bpt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Unknown path type. Possibly corrupt XCF file");
|
|
|
|
}
|
|
|
|
|
2001-07-19 23:34:19 +08:00
|
|
|
bzp = path_new (gimage,
|
|
|
|
ptype, pts_list, closed, (gint)state, locked, tattoo, name);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
return bzp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PathList *
|
2001-07-19 23:34:19 +08:00
|
|
|
xcf_load_bzpaths (GimpImage *gimage,
|
|
|
|
XcfInfo *info)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
guint32 num_paths;
|
|
|
|
guint32 last_selected_row;
|
|
|
|
PathList *paths;
|
|
|
|
GSList *bzp_list = NULL;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
Path *bzp;
|
|
|
|
/* Read in a path */
|
2001-07-19 23:34:19 +08:00
|
|
|
bzp = xcf_load_path (gimage, info);
|
2001-07-04 02:38:56 +08:00
|
|
|
bzp_list = g_slist_append (bzp_list, bzp);
|
|
|
|
}
|
|
|
|
|
|
|
|
paths = path_list_new (gimage, last_selected_row, bzp_list);
|
|
|
|
|
|
|
|
return paths;
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpImage *
|
2001-07-05 03:31:35 +08:00
|
|
|
xcf_load_image (Gimp *gimp,
|
|
|
|
XcfInfo *info)
|
2001-07-04 02:38:56 +08:00
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpChannel *channel;
|
|
|
|
guint32 saved_pos;
|
|
|
|
guint32 offset;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint image_type;
|
|
|
|
gint num_successful_elements = 0;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
xcf_seek_pos (info, offset);
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
xcf_seek_pos (info, saved_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
|
|
|
xcf_seek_pos (info, offset);
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
xcf_seek_pos (info, saved_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
hard_error:
|
|
|
|
g_message ("XCF: This file is corrupt! I could not even\n"
|
|
|
|
"salvage any partial image data from it.");
|
|
|
|
|
2001-07-25 21:21:57 +08:00
|
|
|
g_object_unref (G_OBJECT (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:
|
|
|
|
if (info->file_version == 0)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
g_message (_("XCF warning: version 0 of XCF file format\n"
|
|
|
|
"did not save indexed colormaps correctly.\n"
|
|
|
|
"Substituting grayscale map."));
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
gimage->cmap = g_new (guchar, gimage->num_cols*3);
|
|
|
|
xcf_seek_pos (info, info->cp + gimage->num_cols);
|
|
|
|
for (i = 0; i<gimage->num_cols; i++)
|
|
|
|
{
|
|
|
|
gimage->cmap[i*3+0] = i;
|
|
|
|
gimage->cmap[i*3+1] = i;
|
|
|
|
gimage->cmap[i*3+2] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp, (guint32*) &gimage->num_cols, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
gimage->cmap = g_new (guchar, gimage->num_cols*3);
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int8 (info->fp,
|
|
|
|
(guint8*) gimage->cmap, gimage->num_cols*3);
|
2001-07-04 02:38:56 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_COMPRESSION:
|
|
|
|
{
|
|
|
|
guint8 compression;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int8 (info->fp, (guint8*) &compression, 1);
|
|
|
|
|
|
|
|
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:
|
|
|
|
{
|
|
|
|
GimpGuide *guide;
|
|
|
|
gint32 position;
|
|
|
|
gint8 orientation;
|
|
|
|
gint i, nguides;
|
|
|
|
|
|
|
|
nguides = prop_size / (4 + 1);
|
|
|
|
for (i = 0; i < nguides; i++)
|
|
|
|
{
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp, (guint32 *) &position, 1);
|
|
|
|
info->cp +=
|
|
|
|
xcf_read_int8 (info->fp, (guint8 *) &orientation, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
|
|
|
|
switch (orientation)
|
|
|
|
{
|
|
|
|
case ORIENTATION_HORIZONTAL:
|
|
|
|
guide = gimp_image_add_hguide (gimage);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ORIENTATION_VERTICAL:
|
|
|
|
guide = gimp_image_add_vguide (gimage);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_message ("guide orientation out of range in XCF file");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
guide->position = position;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &unit, 1);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
gimage->unit = unit;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_PATHS:
|
|
|
|
{
|
2001-07-19 23:34:19 +08:00
|
|
|
PathList *paths = xcf_load_bzpaths (gimage, info);
|
2001-07-04 02:38:56 +08:00
|
|
|
/* add to gimage */
|
|
|
|
gimp_image_set_paths (gimage, paths);
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
default:
|
2001-07-19 23:34:19 +08:00
|
|
|
g_message ("unexpected/unknown image property: %d (skipping)",
|
|
|
|
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;
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp,
|
|
|
|
(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),
|
|
|
|
visible ? TRUE : FALSE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_LINKED:
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &layer->linked, 1);
|
|
|
|
break;
|
|
|
|
case PROP_PRESERVE_TRANSPARENCY:
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp, (guint32*) &layer->preserve_trans, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_APPLY_MASK:
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) apply_mask, 1);
|
|
|
|
break;
|
|
|
|
case PROP_EDIT_MASK:
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) edit_mask, 1);
|
|
|
|
break;
|
|
|
|
case PROP_SHOW_MASK:
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) show_mask, 1);
|
|
|
|
break;
|
|
|
|
case PROP_OFFSETS:
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp,
|
|
|
|
(guint32*) &GIMP_DRAWABLE(layer)->offset_x, 1);
|
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp,
|
|
|
|
(guint32*) &GIMP_DRAWABLE(layer)->offset_y, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_MODE:
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &layer->mode, 1);
|
|
|
|
break;
|
|
|
|
case PROP_TATTOO:
|
|
|
|
info->cp += xcf_read_int32 (info->fp,
|
2002-02-26 01:58:50 +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)
|
|
|
|
{
|
|
|
|
p = xcf_load_parasite(info);
|
|
|
|
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:
|
2001-07-19 23:34:19 +08:00
|
|
|
g_message ("unexpected/unknown layer property: %d (skipping)",
|
|
|
|
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
|
|
|
|
xcf_load_channel_props (XcfInfo *info,
|
|
|
|
GimpImage *gimage,
|
|
|
|
GimpChannel *channel)
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
info->active_channel = channel;
|
|
|
|
break;
|
|
|
|
case PROP_SELECTION:
|
2001-07-25 21:21:57 +08:00
|
|
|
g_object_unref (G_OBJECT (gimage->selection_mask));
|
2001-07-04 02:38:56 +08:00
|
|
|
gimage->selection_mask = channel;
|
|
|
|
channel->boundary_known = FALSE;
|
|
|
|
channel->bounds_known = FALSE;
|
|
|
|
break;
|
|
|
|
case PROP_OPACITY:
|
|
|
|
{
|
|
|
|
guint32 opacity;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &opacity, 1);
|
|
|
|
channel->color.a = opacity / 255.0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_VISIBLE:
|
|
|
|
{
|
|
|
|
gboolean visible;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32 *) &visible, 1);
|
|
|
|
gimp_drawable_set_visible (GIMP_DRAWABLE (channel),
|
|
|
|
visible ? TRUE : FALSE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_SHOW_MASKED:
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
|
|
|
xcf_read_int32 (info->fp, (guint32*) &channel->show_masked, 1);
|
2001-07-04 02:38:56 +08:00
|
|
|
break;
|
|
|
|
case PROP_COLOR:
|
|
|
|
{
|
|
|
|
guchar col[3];
|
|
|
|
|
|
|
|
info->cp += xcf_read_int8 (info->fp, (guint8*) col, 3);
|
|
|
|
|
|
|
|
gimp_rgb_set_uchar (&channel->color, col[0], col[1], col[2]);
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PROP_TATTOO:
|
2001-07-19 23:34:19 +08:00
|
|
|
info->cp +=
|
2002-02-26 01:58:50 +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);
|
|
|
|
gimp_item_parasite_attach (GIMP_ITEM (channel), p);
|
|
|
|
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:
|
2001-07-19 23:34:19 +08:00
|
|
|
g_message ("unexpected/unknown channel property: %d (skipping)",
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) prop_type, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) prop_size, 1);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpLayer *
|
|
|
|
xcf_load_layer (XcfInfo *info,
|
|
|
|
GimpImage *gimage)
|
|
|
|
{
|
|
|
|
GimpLayer *layer;
|
|
|
|
GimpLayerMask *layer_mask;
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
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);
|
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
|
|
|
|
/* create a new layer */
|
2001-12-09 07:12:59 +08:00
|
|
|
layer = gimp_layer_new (gimage, width, height,
|
|
|
|
type, name, 255, GIMP_NORMAL_MODE);
|
2001-07-04 02:38:56 +08:00
|
|
|
g_free (name);
|
|
|
|
if (!layer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* read in the layer properties */
|
|
|
|
if (!xcf_load_layer_props (info, gimage, layer,
|
|
|
|
&apply_mask, &edit_mask, &show_mask))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
xcf_seek_pos (info, hierarchy_offset);
|
|
|
|
if (!xcf_load_hierarchy (info, GIMP_DRAWABLE(layer)->tiles))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* read in the layer mask */
|
|
|
|
if (layer_mask_offset != 0)
|
|
|
|
{
|
|
|
|
xcf_seek_pos (info, layer_mask_offset);
|
|
|
|
|
|
|
|
layer_mask = xcf_load_layer_mask (info, gimage);
|
|
|
|
if (!layer_mask)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* set the offsets of the layer_mask */
|
|
|
|
GIMP_DRAWABLE (layer_mask)->offset_x = GIMP_DRAWABLE (layer)->offset_x;
|
|
|
|
GIMP_DRAWABLE (layer_mask)->offset_y = GIMP_DRAWABLE (layer)->offset_y;
|
|
|
|
|
|
|
|
gimp_layer_add_mask (layer, layer_mask, FALSE);
|
2002-09-07 17:40:53 +08:00
|
|
|
g_object_unref (G_OBJECT (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)
|
|
|
|
{
|
|
|
|
GimpLayer *floating_sel;
|
|
|
|
|
|
|
|
floating_sel = info->floating_sel;
|
|
|
|
floating_sel_attach (floating_sel, GIMP_DRAWABLE (layer));
|
|
|
|
}
|
|
|
|
|
|
|
|
return layer;
|
|
|
|
|
|
|
|
error:
|
2001-07-25 21:21:57 +08:00
|
|
|
g_object_unref (G_OBJECT (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;
|
|
|
|
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 */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &height, 1);
|
|
|
|
info->cp += xcf_read_string (info->fp, &name, 1);
|
|
|
|
|
|
|
|
/* 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 */
|
|
|
|
if (!xcf_load_channel_props (info, gimage, channel))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* read the hierarchy and layer mask offsets */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
|
|
|
|
|
|
|
|
/* read in the hierarchy */
|
|
|
|
xcf_seek_pos (info, hierarchy_offset);
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
return channel;
|
|
|
|
|
|
|
|
error:
|
2001-07-25 21:21:57 +08:00
|
|
|
g_object_unref (G_OBJECT (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 */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &height, 1);
|
|
|
|
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 */
|
|
|
|
if (!xcf_load_channel_props (info, gimage, GIMP_CHANNEL (layer_mask)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* read the hierarchy and layer mask offsets */
|
|
|
|
info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
|
|
|
|
|
|
|
|
/* read in the hierarchy */
|
|
|
|
xcf_seek_pos (info, hierarchy_offset);
|
|
|
|
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;
|
|
|
|
|
|
|
|
error:
|
2001-07-25 21:21:57 +08:00
|
|
|
g_object_unref (G_OBJECT (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.
|
|
|
|
*/
|
|
|
|
do
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* seek to the level offset */
|
|
|
|
xcf_seek_pos (info, offset);
|
|
|
|
|
|
|
|
/* read in the level */
|
|
|
|
if (!xcf_load_level (info, tiles))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* restore the saved position so we'll be ready to
|
|
|
|
* read the next offset.
|
|
|
|
*/
|
|
|
|
xcf_seek_pos (info, saved_pos);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &width, 1);
|
|
|
|
info->cp += xcf_read_int32 (info->fp, (guint32*) &height, 1);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* if the offset is 0 then we need to read in the maximum possible
|
|
|
|
allowing for negative compression */
|
|
|
|
if (offset2 == 0)
|
|
|
|
offset2 = offset + TILE_WIDTH * TILE_WIDTH * 4* 1.5;
|
|
|
|
/* 1.5 is probably more
|
|
|
|
than we need to allow */
|
|
|
|
|
|
|
|
/* seek to the tile offset */
|
|
|
|
xcf_seek_pos (info, offset);
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fail)
|
|
|
|
{
|
|
|
|
tile_release (tile, TRUE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
if (previous != NULL)
|
|
|
|
{
|
|
|
|
tile_lock (previous);
|
|
|
|
if (tile_ewidth (tile) == tile_ewidth (previous) &&
|
|
|
|
tile_eheight (tile) == tile_eheight (previous) &&
|
|
|
|
tile_bpp (tile) == tile_bpp (previous) &&
|
|
|
|
memcmp (tile_data_pointer (tile, 0, 0),
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
xcf_seek_pos (info, saved_pos);
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
info->swap_num = tile_swap_add (info->filename,
|
|
|
|
xcf_swap_func,
|
|
|
|
info->ref_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
tile->swap_num = info->swap_num;
|
|
|
|
tile->swap_offset = info->cp;
|
|
|
|
*info->ref_count += 1;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
info->cp += xcf_read_int8 (info->fp, tile_data_pointer(tile, 0, 0),
|
|
|
|
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;
|
|
|
|
|
|
|
|
data = tile_data_pointer (tile, 0, 0);
|
|
|
|
bpp = tile_bpp (tile);
|
|
|
|
|
|
|
|
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 */
|
|
|
|
nmemb_read_successfully = fread ((gchar*) xcfdata, sizeof (char),
|
|
|
|
data_length, info->fp);
|
|
|
|
info->cp += nmemb_read_successfully;
|
|
|
|
|
|
|
|
xcfdatalimit = &xcfodata[nmemb_read_successfully - 1];
|
|
|
|
|
|
|
|
for (i = 0; i < bpp; i++)
|
|
|
|
{
|
|
|
|
data = (guchar*) tile_data_pointer (tile, 0, 0) + i;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#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
|