1
/* This file is part of the KDE project
3
* Copyright (C) 2009 - 2010 Inge Wallin <inge@lysator.liu.se>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Library General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Library General Public License for more details.
15
* You should have received a copy of the GNU Library General Public License
16
* along with this library; see the file COPYING.LIB. If not, write to
17
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301, USA.
23
#include "VectorShape.h"
33
#include <QDataStream>
43
#include "KoXmlReader.h"
44
#include <KoShapeLoadingContext.h>
45
#include <KoOdfLoadingContext.h>
46
#include <KoShapeSavingContext.h>
47
#include <WmfPainter.h>
50
#include "libemf/EmfParser.h"
51
#include "libemf/EmfOutputPainterStrategy.h"
52
#include "libemf/EmfOutputDebugStrategy.h"
55
VectorShape::VectorShape()
56
: KoFrameShape( KoXmlNS::draw, "image" )
57
, m_type(VectorTypeNone)
63
setShapeId(VectorShape_SHAPEID);
65
// Default size of the shape.
66
KoShape::setSize( QSizeF( CM_TO_POINT( 8 ), CM_TO_POINT( 5 ) ) );
69
VectorShape::~VectorShape()
73
void VectorShape::setVectorBytes( char *bytes, int size, bool takeOwnership )
75
if (m_bytes != 0 && m_ownsBytes)
80
m_ownsBytes = takeOwnership;
83
char *VectorShape::vectorBytes()
88
int VectorShape::vectorSize()
94
void VectorShape::paint(QPainter &painter, const KoViewConverter &converter)
96
applyConversion(painter, converter);
100
void VectorShape::paintDecorations(QPainter &painter, const KoViewConverter &converter,
101
const KoCanvasBase *canvas)
105
if (1 || !m_printable) {
106
applyConversion(painter, converter);
107
painter.setRenderHint(QPainter::Antialiasing);
113
void VectorShape::draw(QPainter &painter) const
115
// If the data is uninitialized, e.g. because loading failed, draw the null shape
121
// Actually draw the contents
137
void VectorShape::drawNull(QPainter &painter) const
139
QRectF rect(QPointF(0,0), size());
142
// Draw a simple cross in a rectangle just to indicate that there is something here.
143
painter.setPen(QPen(QColor(172, 196, 206)));
144
painter.drawRect(rect);
145
painter.drawLine(rect.topLeft(), rect.bottomRight());
146
painter.drawLine(rect.bottomLeft(), rect.topRight());
151
void VectorShape::drawWmf(QPainter &painter) const
156
WmfPainter wmfPainter;
157
QByteArray emfArray(m_bytes, m_size);
159
// FIXME: Switch name from emfArray
160
if (!wmfPainter.load(emfArray)) {
167
// Position the bitmap to the right place and resize it to fit.
168
QRect wmfBoundingRect = wmfPainter.boundingRect(); // FIXME: Should this be made QRectF?
169
QSizeF shapeSize = size();
171
//kDebug(31000) << "wmfBoundingRect: " << wmfBoundingRect;
172
//kDebug(31000) << "shapeSize: " << shapeSize;
174
// Create a transformation that makes the Wmf fit perfectly into the shape size.
175
painter.scale(shapeSize.width() / wmfBoundingRect.width(),
176
shapeSize.height() / wmfBoundingRect.height());
177
painter.translate(-wmfBoundingRect.left(), -wmfBoundingRect.top());
179
// Actually paint the WMF.
180
wmfPainter.play(painter, true);
185
void VectorShape::drawEmf(QPainter &painter) const
187
// FIXME: Make emfOutput use QSizeF
188
QSize sizeInt( size().width(), size().height() );
189
//kDebug(31000) << "-------------------------------------------";
190
//kDebug(31000) << "size: " << sizeInt << size();
191
//kDebug(31000) << "position: " << position();
192
//kDebug(31000) << "-------------------------------------------";
194
// Create a QBuffer to read from...
195
QByteArray emfArray(m_bytes, m_size);
196
QBuffer emfBuffer(&emfArray);
197
emfBuffer.open(QIODevice::ReadOnly);
199
// ...but what we really want is a stream.
200
QDataStream emfStream;
201
emfStream.setDevice(&emfBuffer);
202
emfStream.setByteOrder(QDataStream::LittleEndian);
204
// FIXME: Make it static to save time?
205
Libemf::Parser emfParser;
207
// Create a new painter output strategy. Last param = true means keep aspect ratio.
208
Libemf::OutputPainterStrategy emfPaintOutput( painter, sizeInt, true );
209
emfParser.setOutput( &emfPaintOutput );
211
Libemf::OutputDebugStrategy emfDebugOutput;
212
emfParser.setOutput( &emfDebugOutput );
214
emfParser.loadFromStream(emfStream);
219
void VectorShape::saveOdf(KoShapeSavingContext & context) const
226
bool VectorShape::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
228
//kDebug(31000) <<"Loading ODF frame in the vector shape. Element = " << element.tagName();
229
loadOdfAttributes(element, context, OdfAllAttributes);
230
return loadOdfFrame(element, context);
234
inline static int read32(const char *buffer, const int offset)
237
int result = (int) buffer[offset];
238
result |= (int) buffer[offset+1] << 8;
239
result |= (int) buffer[offset+2] << 16;
240
result |= (int) buffer[offset+3] << 24;
245
// Load the actual contents within the vector shape.
246
bool VectorShape::loadOdfFrameElement(const KoXmlElement & element,
247
KoShapeLoadingContext &context)
249
//kDebug(31000) <<"Loading ODF element: " << element.tagName();
251
// Get the reference to the vector file. If there is no href, then just return.
252
const QString href = element.attribute("href");
256
// Try to open the embedded file.
257
KoStore *store = context.odfLoadingContext().store();
258
bool result = store->open(href);
263
// Store the size and make a sanity check.
264
// The size of the minimum EMF header record is 88.
265
m_size = store->size();
271
if (m_bytes && m_ownsBytes) {
275
m_bytes = new char[m_size];
278
qint64 bytesRead = store->read(m_bytes, m_size);
280
if (bytesRead < m_size) {
281
kDebug(31000) << "Too few bytes read: " << bytesRead << " instead of " << m_size;
286
m_type = VectorTypeWmf;
288
m_type = VectorTypeEmf;
290
m_type = VectorTypeNone;
292
// Return true if we managed to identify the type.
293
return m_type != VectorTypeNone;
297
bool VectorShape::isWmf() const
299
kDebug(31000) << "Check for WMF";
304
// This is how the 'file' command identifies a WMF.
305
if (m_bytes[0] == '\327' && m_bytes[1] == '\315' && m_bytes[2] == '\306' && m_bytes[3] == '\232')
307
// FIXME: Is this a compressed wmf? Check it up.
308
kDebug(31000) << "WMF identified: header 1";
312
if (m_bytes[0] == '\002' && m_bytes[1] == '\000' && m_bytes[2] == '\011' && m_bytes[3] == '\000')
314
kDebug(31000) << "WMF identified: header 2";
318
if (m_bytes[0] == '\001' && m_bytes[1] == '\000' && m_bytes[2] == '\011' && m_bytes[3] == '\000')
320
kDebug(31000) << "WMF identified: header 3";
327
bool VectorShape::isEmf() const
329
kDebug(31000) << "Check for EMF";
331
// This is how the 'file' command identifies an EMF.
333
qint32 mark = read32(m_bytes, 0);
334
if (mark != 0x00000001) {
335
//kDebug(31000) << "Not an EMF: mark = " << mark << " instead of 0x00000001";
339
// 2. An EMF has the string " EMF" at the start + offset 40.
340
if (m_size > 44 && m_bytes[40] == ' '
341
&& m_bytes[41] == 'E' && m_bytes[42] == 'M' && m_bytes[43] == 'F')
343
kDebug(31000) << "EMF identified";
351
void VectorShape::setPrintable(bool on)
353
if (m_printable == on)