You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kopainter/kogradientmanager.cpp

560 lines
14 KiB

/* This file is part of the KDE project
Copyright (C) 2005 Tim Beaulen <tbscope@gmail.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kogradientmanager.h"
#include "svgnamedcolors.h"
#include <tqtextstream.h>
#include <tqcstring.h>
#include <kdebug.h>
KoGradientManager::KoGradientManager()
{
}
KoGradientManager::~KoGradientManager()
{
// XXX: Should we delete the gradients here?
}
KoGradient* KoGradientManager::loadGradient(const TQString& filename)
{
TQString strExt;
const int result=filename.findRev('.');
if (result>=0)
{
strExt=filename.mid(result).lower();
}
TQFile f(filename);
if(f.open(IO_ReadOnly))
{
if(strExt == ".ggr")
{
return loadChalkGradient(&f);
}
else if(strExt==".kgr")
{
return loadKarbonGradient(&f);
}
else if(strExt==".svg")
{
return loadSvgGradient(&f);
}
}
return 0;
}
KoGradient* KoGradientManager::loadKarbonGradient(TQFile* file)
{
TQDomDocument doc;
if(!(doc.setContent(file)))
file->close();
else
{
TQDomElement e;
TQDomNode n = doc.documentElement().firstChild();
if(!n.isNull())
{
e = n.toElement();
if(!e.isNull())
if( e.tagName() == "GRADIENT" )
return parseKarbonGradient(e);
}
}
return 0;
}
KoGradient* KoGradientManager::loadChalkGradient(TQFile* file)
{
KoGradient* grad = new KoGradient();
TQByteArray m_data = file->readAll();
file->close();
TQTextIStream fileContent(m_data);
fileContent.setEncoding(TQTextStream::UnicodeUTF8);
TQString header = fileContent.readLine();
if (header != "GIMP Gradient")
{
delete grad;
return 0;
}
TQString nameDefinition = fileContent.readLine();
TQString numSegmentsText;
if (nameDefinition.startsWith("Name: "))
{
TQString nameText = nameDefinition.right(nameDefinition.length() - 6);
numSegmentsText = fileContent.readLine();
}
else
{
// Older format without name.
numSegmentsText = nameDefinition;
}
int numSegments;
bool ok;
numSegments = numSegmentsText.toInt(&ok);
if (!ok || numSegments < 1)
{
return 0;
}
for (int i = 0; i < numSegments; i++)
{
KoColorStop *stop = new KoColorStop();
TQString segmentText = fileContent.readLine();
TQTextIStream segmentFields(&segmentText);
double leftOffset;
double middleOffset;
double rightOffset;
segmentFields >> leftOffset >> middleOffset >> rightOffset;
double leftRed;
double leftGreen;
double leftBlue;
double leftAlpha;
segmentFields >> leftRed >> leftGreen >> leftBlue >> leftAlpha;
double rightRed;
double rightGreen;
double rightBlue;
double rightAlpha;
segmentFields >> rightRed >> rightGreen >> rightBlue >> rightAlpha;
int interpolationType;
int colorInterpolationType;
segmentFields >> interpolationType >> colorInterpolationType;
middleOffset = (middleOffset - leftOffset) / (rightOffset - leftOffset);
stop->opacity = leftAlpha;
stop->midpoint = middleOffset;
stop->offset = leftOffset;
stop->color1 = leftRed;
stop->color2 = leftGreen;
stop->color3 = leftBlue;
stop->color4 = 0.0;
stop->colorType = colorInterpolationType;
stop->interpolation = interpolationType;
grad->colorStops.append(stop);
if(rightOffset == 1.0)
{
KoColorStop *lastStop = new KoColorStop();
lastStop->opacity = rightAlpha;
lastStop->midpoint = middleOffset;
lastStop->offset = rightOffset;
lastStop->color1 = rightRed;
lastStop->color2 = rightGreen;
lastStop->color3 = rightBlue;
lastStop->color4 = 0.0;
lastStop->colorType = colorInterpolationType;
lastStop->interpolation = interpolationType;
grad->colorStops.append(lastStop);
}
}
if (!grad->colorStops.isEmpty())
{
grad->originX = 0.0;
grad->originY = 1.0;
grad->vectorX = 0.0;
grad->vectorY = 0.0;
grad->focalpointX = 0.0;
grad->focalpointY = 0.0;
grad->gradientType = gradient_type_linear;
grad->gradientRepeatMethod = repeat_method_none;
return grad;
}
else
{
delete grad;
return 0;
}
}
KoGradient* KoGradientManager::loadSvgGradient(TQFile* file)
{
TQDomDocument doc;
if(!(doc.setContent(file)))
file->close();
else
{
for( TQDomNode n = doc.documentElement().firstChild(); !n.isNull(); n = n.nextSibling() )
{
TQDomElement e = n.toElement();
if( e.isNull() ) continue;
if( e.tagName() == "linearGradient" || e.tagName() == "radialGradient" )
return parseSvgGradient(e);
}
}
return 0;
}
KoGradient* KoGradientManager::parseKarbonGradient(const TQDomElement& element)
{
KoGradient* grad = new KoGradient();
grad->originX = element.attribute("originX", "0.0").toDouble();
grad->originY = element.attribute("originY", "0.0").toDouble();
grad->focalpointX = element.attribute("focalX", "0.0").toDouble();
grad->focalpointY = element.attribute("focalY", "0.0").toDouble();
grad->vectorX = element.attribute("vectorX", "0.0").toDouble();
grad->vectorY = element.attribute("vectorY", "0.0").toDouble();
grad->gradientType = (KoGradientType)element.attribute("type", 0).toInt();
grad->gradientRepeatMethod = (KoGradientRepeatMethod)element.attribute("repeatMethod", 0).toInt();
grad->colorStops.clear();
// load stops
TQDomNodeList list = element.childNodes();
for( uint i = 0; i < list.count(); ++i )
{
if( list.item( i ).isElement() )
{
TQDomElement colorstop = list.item( i ).toElement();
if( colorstop.tagName() == "COLORSTOP" )
{
KoColorStop *stop = new KoColorStop();
TQDomElement e = colorstop.firstChild().toElement();
switch(e.attribute("colorSpace").toUShort())
{
case 1: // cmyk
stop->color1 = e.attribute( "v1", "0.0" ).toFloat();
stop->color2 = e.attribute( "v2", "0.0" ).toFloat();
stop->color3 = e.attribute( "v3", "0.0" ).toFloat();
stop->color4 = e.attribute( "v4", "0.0" ).toFloat();
stop->colorType = color_type_cmyk;
stop->interpolation = interpolation_linear;
break;
case 2: // hsv
stop->color1 = e.attribute( "v1", "0.0" ).toFloat();
stop->color2 = e.attribute( "v2", "0.0" ).toFloat();
stop->color3 = e.attribute( "v3", "0.0" ).toFloat();
stop->color4 = 0.0;
stop->colorType = color_type_hsv_cw;
stop->interpolation = interpolation_linear;
break;
case 3: // gray
stop->color1 = e.attribute( "v1", "0.0" ).toFloat();
stop->color2 = 0.0;
stop->color3 = 0.0;
stop->color4 = 0.0;
stop->colorType = color_type_gray;
stop->interpolation = interpolation_linear;
break;
default: // rgb
stop->color1 = e.attribute( "v1", "0.0" ).toFloat();
stop->color2 = e.attribute( "v2", "0.0" ).toFloat();
stop->color3 = e.attribute( "v3", "0.0" ).toFloat();
stop->color4 = 0.0;
stop->colorType = color_type_rgb;
stop->interpolation = interpolation_linear;
}
stop->opacity = e.attribute("opacity", "1.0").toFloat();
stop->offset = colorstop.attribute("ramppoint", "0.0").toFloat();
stop->midpoint = colorstop.attribute("midpoint", "0.5").toFloat();
grad->colorStops.append(stop);
}
}
}
return grad;
}
KoGradient* KoGradientManager::parseSvgGradient(const TQDomElement& element)
{
KoGradient* grad = new KoGradient;
grad->colorStops.clear();
grad->gradientRepeatMethod = repeat_method_none;
/*TQString href = e.attribute( "xlink:href" ).mid( 1 );
if( !href.isEmpty() )
{
}*/
bool bbox = element.attribute( "gradientUnits" ) != "userSpaceOnUse";
if( element.tagName() == "linearGradient" )
{
if( bbox )
{
TQString s;
s = element.attribute( "x1", "0%" );
double xOrigin;
if( s.endsWith( "%" ) )
xOrigin = s.remove( '%' ).toDouble();
else
xOrigin = s.toDouble() * 100.0;
s = element.attribute( "y1", "0%" );
double yOrigin;
if( s.endsWith( "%" ) )
yOrigin = s.remove( '%' ).toDouble();
else
yOrigin = s.toDouble() * 100.0;
s = element.attribute( "x2", "100%" );
double xVector;
if( s.endsWith( "%" ) )
xVector = s.remove( '%' ).toDouble();
else
xVector = s.toDouble() * 100.0;
s = element.attribute( "y2", "0%" );
double yVector;
if( s.endsWith( "%" ) )
yVector = s.remove( '%' ).toDouble();
else
yVector = s.toDouble() * 100.0;
grad->originX = xOrigin;
grad->originY = yOrigin;
grad->vectorX = xVector;
grad->vectorY = yVector;
}
else
{
grad->originX = element.attribute( "x1" ).toDouble();
grad->originY = element.attribute( "y1" ).toDouble();
grad->vectorX = element.attribute( "x2" ).toDouble();
grad->vectorY = element.attribute( "y2" ).toDouble();
}
grad->gradientType = gradient_type_linear;
}
else
{
if( bbox )
{
TQString s;
s = element.attribute( "cx", "50%" );
double xOrigin;
if( s.endsWith( "%" ) )
xOrigin = s.remove( '%' ).toDouble();
else
xOrigin = s.toDouble() * 100.0;
s = element.attribute( "cy", "50%" );
double yOrigin;
if( s.endsWith( "%" ) )
yOrigin = s.remove( '%' ).toDouble();
else
yOrigin = s.toDouble() * 100.0;
s = element.attribute( "cx", "50%" );
double xVector;
if( s.endsWith( "%" ) )
xVector = s.remove( '%' ).toDouble();
else
xVector = s.toDouble() * 100.0;
s = element.attribute( "r", "50%" );
if( s.endsWith( "%" ) )
xVector += s.remove( '%' ).toDouble();
else
xVector += s.toDouble() * 100.0;
s = element.attribute( "cy", "50%" );
double yVector;
if( s.endsWith( "%" ) )
yVector = s.remove( '%' ).toDouble();
else
yVector = s.toDouble() * 100.0;
s = element.attribute( "fx", "50%" );
double xFocal;
if( s.endsWith( "%" ) )
xFocal = s.remove( '%' ).toDouble();
else
xFocal = s.toDouble() * 100.0;
s = element.attribute( "fy", "50%" );
double yFocal;
if( s.endsWith( "%" ) )
yFocal = s.remove( '%' ).toDouble();
else
yFocal = s.toDouble() * 100.0;
grad->originX = xOrigin;
grad->originY = yOrigin;
grad->vectorX = xVector;
grad->vectorY = yVector;
grad->focalpointX = xFocal;
grad->focalpointY = yFocal;
}
else
{
grad->originX = element.attribute( "cx" ).toDouble();
grad->originY = element.attribute( "cy" ).toDouble();
grad->vectorX = element.attribute( "cx" ).toDouble() + element.attribute( "r" ).toDouble();
grad->vectorY = element.attribute( "cy" ).toDouble();
grad->focalpointX = element.attribute( "fx" ).toDouble();
grad->focalpointY = element.attribute( "fy" ).toDouble();
}
grad->gradientType = gradient_type_radial;
}
// handle spread method
TQString spreadMethod = element.attribute( "spreadMethod" );
if( !spreadMethod.isEmpty() )
{
if( spreadMethod == "reflect" )
grad->gradientRepeatMethod = repeat_method_reflect;
else if( spreadMethod == "repeat" )
grad->gradientRepeatMethod = repeat_method_repeat;
}
for( TQDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() )
{
TQDomElement colorstop = n.toElement();
if( colorstop.tagName() == "stop" )
{
KoColorStop *stop = new KoColorStop();
TQColor c;
float off;
TQString temp = colorstop.attribute( "offset" );
if( temp.contains( '%' ) )
{
temp = temp.left( temp.length() - 1 );
off = temp.toFloat() / 100.0;
}
else
off = temp.toFloat();
if( !colorstop.attribute( "stop-color" ).isEmpty() )
parseSvgColor( c, colorstop.attribute( "stop-color" ) );
else
{
// try style attr
TQString style = colorstop.attribute( "style" ).simplifyWhiteSpace();
TQStringList substyles = TQStringList::split( ';', style );
for( TQStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
{
TQStringList substyle = TQStringList::split( ':', (*it) );
TQString command = substyle[0].stripWhiteSpace();
TQString params = substyle[1].stripWhiteSpace();
if( command == "stop-color" )
parseSvgColor( c, params );
if( command == "stop-opacity" )
stop->opacity = params.toDouble();
}
}
if( !colorstop.attribute( "stop-opacity" ).isEmpty() )
stop->opacity = colorstop.attribute( "stop-opacity" ).toDouble();
stop->offset = off;
stop->midpoint = 0.5;
stop->color1 = c.red() / 255.0;
stop->color2 = c.green() / 255.0;
stop->color3 = c.blue() / 255.0;
stop->color4 = 0.0;
stop->colorType = color_type_rgb;
stop->interpolation = interpolation_linear;
grad->colorStops.append(stop);
}
}
return grad;
}
void KoGradientManager::parseSvgColor(TQColor &color, const TQString &s)
{
if( s.startsWith( "rgb(" ) )
{
TQString parse = s.stripWhiteSpace();
TQStringList colors = TQStringList::split( ',', parse );
TQString r = colors[0].right( ( colors[0].length() - 4 ) );
TQString g = colors[1];
TQString b = colors[2].left( ( colors[2].length() - 1 ) );
if( r.contains( "%" ) )
{
r = r.left( r.length() - 1 );
r = TQString::number( int( ( double( 255 * r.toDouble() ) / 100.0 ) ) );
}
if( g.contains( "%" ) )
{
g = g.left( g.length() - 1 );
g = TQString::number( int( ( double( 255 * g.toDouble() ) / 100.0 ) ) );
}
if( b.contains( "%" ) )
{
b = b.left( b.length() - 1 );
b = TQString::number( int( ( double( 255 * b.toDouble() ) / 100.0 ) ) );
}
color = TQColor( r.toInt(), g.toInt(), b.toInt() );
}
else
{
TQString rgbColor = s.stripWhiteSpace();
TQColor c;
if( rgbColor.startsWith( "#" ) )
c.setNamedColor( rgbColor );
else
{
int r, g, b;
svgNamedColorToRGB( rgbColor, r, g, b );
c = TQColor( r, g, b );
}
color = c;
}
}