sp-image.cpp revision f76f0d94b4b87bb6c1ba98e14d120aac94e415d0
#define __SP_IMAGE_C__
/*
* SVG <image> implementation
*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Edward Flick (EAF)
*
* Copyright (C) 1999-2005 Authors
* Copyright (C) 2000-2001 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <libnr/nr-matrix-fns.h>
//#define GDK_PIXBUF_ENABLE_BACKEND 1
//#include <gdk-pixbuf/gdk-pixbuf-io.h>
#include "display/nr-arena-image.h"
//Added for preserveAspectRatio support -- EAF
#include "enums.h"
#include "attributes.h"
#include "print.h"
#include "brokenimage.xpm"
#include "document.h"
#include "sp-image.h"
#include "sp-clippath.h"
#include <png.h>
#if ENABLE_LCMS
#include "color-profile-fns.h"
#include "color-profile.h"
//#define DEBUG_LCMS
#ifdef DEBUG_LCMS
#include "prefs-utils.h"
#include <gtk/gtkmessagedialog.h>
#endif // DEBUG_LCMS
#endif // ENABLE_LCMS
/*
* SPImage
*/
static Inkscape::XML::Node *sp_image_write (SPObject *object, Inkscape::XML::Node *repr, guint flags);
static void sp_image_bbox(SPItem const *item, NRRect *bbox, NR::Matrix const &transform, unsigned const flags);
static NRArenaItem *sp_image_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags);
static SPItemClass *parent_class;
extern "C"
{
}
#ifdef DEBUG_LCMS
extern guint update_in_progress;
#define DEBUG_MESSAGE(key, ...) \
{\
if ( dump )\
{\
g_message( __VA_ARGS__ );\
\
}\
if ( dumpD )\
{\
);\
dialog); \
}\
}
#endif // DEBUG_LCMS
namespace Inkscape {
namespace IO {
class PushPull
{
public:
fp(0),
scratch(0),
size(0),
used(0),
offset(0),
loader(0) {};
{
if ( offset )
{
offset = 0;
}
{
if ( got )
{
if ( loader )
{
//g_message( " __read %d bytes", (int)got );
{
//g_message("_error writing pixbuf data");
}
}
}
else
{
}
}
return good;
}
{
}
{
{
}
{
offset = 0;
used = 0;
}
return giving;
}
void clear()
{
offset = 0;
used = 0;
}
private:
};
{
// g_message( "user_read_data(%d)", length );
{
{
}
}
// g_message("things out");
}
{
//g_message( "user_write_data(%d)", length );
}
{
//g_message( "user_flush_data" );
}
{
//buf = gdk_pixbuf_new_from_file( filename, error );
if ( fp )
{
if ( loader )
{
// short buffer
//png_infop endPtr = NULL;
{
{
{
//g_message( "First data chunk" );
//g_message( " png? %s", (isPng ? "Yes":"No") );
if ( isPng )
{
NULL,//(png_voidp)user_error_ptr,
NULL,//user_error_fn,
NULL//user_warning_fn
);
if ( pngPtr )
{
//endPtr = png_create_info_struct( pngPtr );
//g_message( "In" );
//png_read_info( pngPtr, infoPtr );
//g_message("out");
//png_read_end(pngPtr, endPtr);
/*
if ( png_get_valid( pngPtr, infoPtr, PNG_INFO_pHYs ) )
{
g_message("pHYs chunk now valid" );
}
if ( png_get_valid( pngPtr, infoPtr, PNG_INFO_sCAL ) )
{
g_message("sCAL chunk now valid" );
}
*/
png_uint_32 res_x = 0;
png_uint_32 res_y = 0;
int unit_type = 0;
{
// g_message( "pHYs yes (%d, %d) %d (%s)", (int)res_x, (int)res_y, unit_type,
// (unit_type == 1? "per meter" : "unknown")
// );
// g_message( " dpi: (%d, %d)",
// (int)(0.5 + ((double)res_x)/39.37),
// (int)(0.5 + ((double)res_y)/39.37) );
if ( unit_type == PNG_RESOLUTION_METER )
{
// TODO come up with a more accurate DPI setting
}
}
else
{
// g_message( "pHYs no" );
}
/*
double width = 0;
double height = 0;
int unit = 0;
if ( png_get_sCAL(pngPtr, infoPtr, &unit, &width, &height) )
{
gchar* vals[] = {
"unknown", // PNG_SCALE_UNKNOWN
"meter", // PNG_SCALE_METER
"radian", // PNG_SCALE_RADIAN
"last", //
NULL
};
g_message( "sCAL: (%f, %f) %d (%s)",
width, height, unit,
((unit >= 0 && unit < 3) ? vals[unit]:"???")
);
}
*/
// now clean it up.
}
else
{
g_message("Error when creating PNG read struct");
}
}
}
else if ( !latter )
{
//g_message(" READing latter");
}
// Now clear out the buffer so we can read more.
// (dumping out unused)
}
}
if ( ok )
{
if ( buf )
{
if ( dpiX )
{
if ( tmp )
{
//gdk_pixbuf_set_option( buf, "Inkscape::DpiX", tmp );
}
}
if ( dpiY )
{
if ( tmp )
{
//gdk_pixbuf_set_option( buf, "Inkscape::DpiY", tmp );
}
}
}
}
else
{
// do something
g_message("error loading pixbuf at close");
}
}
else
{
g_message("error when creating pixbuf loader");
}
}
else
{
}
/*
if ( buf )
{
const gchar* bloop = gdk_pixbuf_get_option( buf, "Inkscape::DpiX" );
if ( bloop )
{
g_message("DPI X is [%s]", bloop);
}
bloop = gdk_pixbuf_get_option( buf, "Inkscape::DpiY" );
if ( bloop )
{
g_message("DPI Y is [%s]", bloop);
}
}
*/
return buf;
}
}
}
sp_image_get_type (void)
{
static GType image_type = 0;
if (!image_type) {
GTypeInfo image_info = {
sizeof (SPImageClass),
NULL, /* base_init */
NULL, /* base_finalize */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (SPImage),
16, /* n_preallocs */
NULL, /* value_table */
};
}
return image_type;
}
static void
{
}
static void
{
}
static void
{
/* Register */
}
static void
{
if (SP_OBJECT_DOCUMENT (object)) {
/* Unregister ourselves */
}
}
}
#if ENABLE_LCMS
if (image->color_profile) {
}
#endif // ENABLE_LCMS
}
}
static void
{
switch (key) {
case SP_ATTR_XLINK_HREF:
break;
case SP_ATTR_X:
/* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
}
break;
case SP_ATTR_Y:
/* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
}
break;
case SP_ATTR_WIDTH:
/* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
}
break;
case SP_ATTR_HEIGHT:
/* fixme: em, ex, % are probably valid, but require special treatment (Lauris) */
}
break;
/* Do setup before, so we can use break to escape */
if (value) {
int len;
gchar c[256];
const gchar *p, *e;
p = value;
while (*p && *p == 32) p += 1;
if (!*p) break;
e = p;
while (*e && *e != 32) e += 1;
len = e - p;
if (len > 8) break;
c[len] = 0;
/* Now the actual part */
if (!strcmp (c, "none")) {
} else if (!strcmp (c, "xMinYMin")) {
} else if (!strcmp (c, "xMidYMin")) {
} else if (!strcmp (c, "xMaxYMin")) {
} else if (!strcmp (c, "xMinYMid")) {
} else if (!strcmp (c, "xMidYMid")) {
} else if (!strcmp (c, "xMaxYMid")) {
} else if (!strcmp (c, "xMinYMax")) {
} else if (!strcmp (c, "xMidYMax")) {
} else if (!strcmp (c, "xMaxYMax")) {
} else {
break;
}
while (*e && *e == 32) e += 1;
if (e) {
if (!strcmp (e, "meet")) {
} else if (!strcmp (e, "slice")) {
} else {
break;
}
}
}
break;
#if ENABLE_LCMS
case SP_PROP_COLOR_PROFILE:
if ( image->color_profile ) {
}
#ifdef DEBUG_LCMS
if ( value ) {
} else {
}
#endif // DEBUG_LCMS
// TODO check on this HREF_MODIFIED flag
break;
#endif // ENABLE_LCMS
default:
break;
}
}
static void
{
if (flags & SP_IMAGE_HREF_MODIFIED_FLAG) {
}
if (pixbuf) {
// BLIP
#if ENABLE_LCMS
if ( image->color_profile )
{
if ( px ) {
#ifdef DEBUG_LCMS
#endif // DEBUG_LCMS
image->color_profile );
if ( prof ) {
if ( profileClass != icSigNamedColorClass ) {
int intent = INTENT_PERCEPTUAL;
switch ( profIntent ) {
break;
break;
break;
case Inkscape::RENDERING_INTENT_UNKNOWN:
case Inkscape::RENDERING_INTENT_AUTO:
default:
}
intent, 0 );
if ( transf ) {
for ( int y = 0; y < imageheight; y++ ) {
// Since the types are the same size, we can do the transformation in-place
}
}
#ifdef DEBUG_LCMS
else
{
}
#endif // DEBUG_LCMS
}
#ifdef DEBUG_LCMS
else
{
DEBUG_MESSAGE( lcmsSeven, "in <image>'s sp_image_update. Profile type is named color. Can't transform." );
}
#endif // DEBUG_LCMS
}
#ifdef DEBUG_LCMS
else
{
}
#endif // DEBUG_LCMS
}
}
#endif // ENABLE_LCMS
}
}
}
// preserveAspectRatio calculate bounds / clipping rectangle -- EAF
int imagewidth, imageheight;
double x,y;
switch (image->aspect_align) {
case SP_ASPECT_XMIN_YMIN:
x = 0.0;
y = 0.0;
break;
case SP_ASPECT_XMID_YMIN:
x = 0.5;
y = 0.0;
break;
case SP_ASPECT_XMAX_YMIN:
x = 1.0;
y = 0.0;
break;
case SP_ASPECT_XMIN_YMID:
x = 0.0;
y = 0.5;
break;
case SP_ASPECT_XMID_YMID:
x = 0.5;
y = 0.5;
break;
case SP_ASPECT_XMAX_YMID:
x = 1.0;
y = 0.5;
break;
case SP_ASPECT_XMIN_YMAX:
x = 0.0;
y = 1.0;
break;
case SP_ASPECT_XMID_YMAX:
x = 0.5;
y = 1.0;
break;
case SP_ASPECT_XMAX_YMAX:
x = 1.0;
y = 1.0;
break;
default:
x = 0.0;
y = 0.0;
break;
}
// Pixels aspect is wider than bounding box
image->trimwidth = static_cast<int>(static_cast<double>(imageheight) * image->width.computed / image->height.computed);
} else {
// Pixels aspect is taller than bounding box
image->trimheight = static_cast<int>(static_cast<double>(imagewidth) * image->height.computed / image->width.computed);
}
} else {
// Otherwise, assume SP_ASPECT_MEET
// Pixels aspect is wider than bounding boz
} else {
// Pixels aspect is taller than bounding box
}
}
}
}
{
}
/* fixme: Reset attribute if needed (Lauris) */
#if ENABLE_LCMS
#endif // ENABLE_LCMS
return repr;
}
static void
{
}
}
static void
{
pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
/* fixme: (Lauris) */
} else { // preserveAspectRatio
}
nr_matrix_multiply (&t, &s, &tp);
nr_matrix_multiply (&t, &ti, &t);
else // preserveAspectRatio
sp_print_image_R8G8B8A8_N (ctx, px + image->trimx*pixskip + image->trimy*rs, image->trimwidth, image->trimheight, rs, &t, SP_OBJECT_STYLE (item));
}
static gchar *
{
char *href_desc;
? g_strdup(_("embedded"))
} else {
g_warning("Attempting to call strncmp() with a null pointer.");
}
: g_strdup_printf(_("<b>Image</b> %d × %d: %s"),
href_desc) );
return ret;
}
static NRArenaItem *
{
pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
rs);
else // preserveAspectRatio
rs);
} else {
}
nr_arena_image_set_geometry (NR_ARENA_IMAGE (ai), image->x.computed, image->y.computed, image->width.computed, image->height.computed);
else // preserveAspectRatio
nr_arena_image_set_geometry (NR_ARENA_IMAGE (ai), image->viewx, image->viewy, image->viewwidth, image->viewheight);
return ai;
}
/*
* utility function to try loading image from href
*
* absolute_src
*
*/
{
if (fullname) {
// TODO check this. Was doing a UTF-8 to filename conversion here.
}
/* data URI - embedded image */
filename += 5;
} else {
if (!g_path_is_absolute (filename)) {
/* try to load from relative pos combined with document base*/
// document base can be wrong (on the temporary doc when importing bitmap from a
// different dir) or unset (when doc is not saved yet), so we check for base+href existence first,
// and if it fails, we also try to use bare href regardless of its g_path_is_absolute
}
}
/* try filename as absolute */
}
}
}
/* at last try to load from sp absolute path name */
// using absref is outside of SVG rules, so we must at least warn the user
g_warning ("<image xlink:href=\"%s\"> did not resolve to a valid image file (base dir is %s), now trying sodipodi:absref=\"%s\"", href, base, absref);
else
g_warning ("xlink:href did not resolve to a valid image file, now trying sodipodi:absref=\"%s\"", absref);
}
/* Nope: We do not find any valid pixmap file :-( */
/* It should be included xpm, so if it still does not does load, */
/* our libraries are broken */
return pixbuf;
}
static GdkPixbuf *
{
return newbuf;
}
/* We assert that realpixbuf is either NULL or identical size to pixbuf */
static void
{
SPItemView *v;
/* fixme: We are slightly violating spec here (Lauris) */
}
}
}
pixskip = gdk_pixbuf_get_n_channels (image->pixbuf) * gdk_pixbuf_get_bits_per_sample (image->pixbuf) / 8;
rs);
} else { // preserveAspectRatio
rs);
}
}
}
{
/* An image doesn't have any nodes to snap, but still we want to be able snap one image
to another. Therefore we will create some snappoints at the corner, similar to a rect. If
the image is rotated, then the snappoints will rotate with it. Again, just like a rect.
*/
//We are looking at a clipped image: do not return any snappoints, as these might be
//far far away from the visible part from the clipped image
} else {
// The image has not been clipped: return its corners, which might be rotated for example
}
}
/*
* Initially we'll do:
* Transform x, y, set x, y, clear translation
*/
{
/* Calculate position in parent coords. */
/* This function takes care of translation and scaling, we return whatever parts we can't
handle. */
} else {
ret[0] = 1.0;
}
} else {
}
/* Find position in item coords */
return ret;
}
static GdkPixbuf *
gint data_is_image = 0;
gint data_is_base64 = 0;
while (*data) {
/* base64-encoding */
data_is_base64 = 1;
data_is_image = 1; // Illustrator produces embedded images without MIME type, so we assume it's image no matter what
data += 6;
}
/* PNG image */
data_is_image = 1;
data += 9;
}
/* JPEG image */
data_is_image = 1;
data += 9;
}
/* JPEG image */
data_is_image = 1;
data += 10;
}
else { /* unrecognized option; skip it */
while (*data) {
data++;
}
}
if ((*data) == ';') {
data++;
continue;
}
if ((*data) == ',') {
data++;
break;
}
}
}
return pixbuf;
}
static GdkPixbuf *
gint j;
gint k;
gint l;
gint b;
loader = gdk_pixbuf_loader_new ();
while (eos == 0) {
l = 0;
for (j = 0; j < 19; j++) {
len = 0;
for (k = 0; k < 4; k++) {
if ((*btr) == '\0') break;
btr++;
}
if (eos) {
ud[k] = 0;
continue;
}
eos = 1;
ud[k] = 0;
continue;
}
ud[k] = 64;
for (b = 0; b < 64; b++) { /* There must a faster way to do this... ?? */
break;
}
}
eos = 1;
ud[k] = 0;
continue;
}
btr++;
len++;
}
if (len > 2) {
}
if (len > 3) {
}
}
failed = 1;
break;
}
}
return pixbuf;
}
static void
{
//create a curve at the image's boundary for snapping
if ((image->height.computed < 1e-18) || (image->width.computed < 1e-18) || (image->clip_ref->getObject())) {
}
return;
}
SPCurve *c = sp_curve_new();
sp_curve_moveto(c, x, y);
sp_curve_lineto(c, x + w, y);
sp_curve_lineto(c, x + w, y + h);
sp_curve_lineto(c, x, y + h);
sp_curve_lineto(c, x, y);
}
if (c) {
}
sp_curve_unref(c);
}
/**
* Return duplicate of curve (if any exists) or NULL if there is no curve
*/
SPCurve *
{
}
return NULL;
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :