22
22
#include "graphicshandler.h"
23
23
#include "document.h"
24
#include "conversion.h"
25
#include <wv2/src/olestream.h>
26
26
#include <wv2/src/ms_odraw.h>
27
28
#include "generated/leinputstream.h"
28
29
#include "drawstyle.h"
30
#include "ODrawToOdf.h"
30
33
#include <KoStoreDevice.h>
31
34
#include <KoGenStyle.h>
32
35
#include <kdebug.h>
33
36
#include <kmimetype.h>
37
#include <QtGui/QColor>
36
40
using namespace wvWare;
37
41
using namespace MSO;
43
using Conversion::twipsToPt;
39
45
#define IMG_BUF_SIZE 2048L
42
KWordPictureHandler::KWordPictureHandler(Document* doc, KoXmlWriter* bodyWriter,
43
KoXmlWriter* manifestWriter, KoStore* store, KoGenStyles* mainStyles)
44
: QObject(), m_doc(doc), m_pictureCount(0), m_officeArtCount(0)
47
m_bodyWriter = bodyWriter;
48
m_manifestWriter = manifestWriter;
50
m_mainStyles = mainStyles;
53
void KWordPictureHandler::setBodyWriter(KoXmlWriter* writer)
55
m_bodyWriter = writer;
60
void KWordPictureHandler::bitmapData(OLEImageReader& reader, SharedPtr<const Word97::PICF> /*picf*/)
62
kDebug(30513) << "Bitmap data found ->>>>>>>>>>>>>>>>>>>>>>>>>>>>> size=" << reader.size();
66
void KWordPictureHandler::escherData(OLEImageReader& reader, SharedPtr<const Word97::PICF> picf, int type, wvWare::U32 pib)
68
kDebug(30513) << "Escher data found";
71
ODTProcessing(&picName, picf, type, pib);
73
if (m_pictureName.contains(pib)) {
74
//image data already loaded once
78
//insert the picture name into hash table
79
m_pictureName.insert(pib, picName);
81
//write picture data to file
82
m_store->open(picName);//open picture file
84
long len = reader.size();
86
kDebug(30513) << "len = " << len;
87
wvWare::U8* buf = new wvWare::U8[IMG_BUF_SIZE];
88
size_t n = reader.read(buf, qMin(len, IMG_BUF_SIZE));
89
long n1 = m_store->write((const char*)buf, n);
90
kDebug(30513) << "n=" << n << ", n1=" << n1 << "; buf contains " << (void*) buf;
94
if ((n == 0 && len != 0) || //endless loop
95
(size_t)n1 != n) { //read/wrote different lengths
96
m_store->close(); //close picture file before returning
97
return; //ouch - we're in an endless loop!
99
//Q_ASSERT( (size_t)n1 == n );
102
m_store->close(); //close picture file
106
//use this version when the data had to be decompressed
107
//so we don't have to convert the data back to an OLEImageReader
108
void KWordPictureHandler::escherData(std::vector<wvWare::U8> data, SharedPtr<const Word97::PICF> picf, int type, wvWare::U32 pib)
110
kDebug(30513) << "Escher data found";
113
ODTProcessing(&picName, picf, type, pib);
115
if (m_pictureName.contains(pib)) {
116
//image data already loaded once
120
//insert the picture name into hash table
121
m_pictureName.insert(pib, picName);
123
//write picture data to file
124
m_store->open(picName);//open picture file
126
long len = data.size();
127
int index = 0; //index for reading from vector
129
kDebug(30513) << "len = " << len;
130
wvWare::U8* buf = new wvWare::U8[IMG_BUF_SIZE];
131
//instead of a read command, we'll copy that number of bytes
132
//from the vector into the buffer
133
int n = qMin(len, IMG_BUF_SIZE);
134
for (int i = 0; i < n; i++) {
135
buf[i] = data[index];
138
//size_t n = reader.read( buf, qMin( len, IMG_BUF_SIZE ) );
139
long n1 = m_store->write((const char*)buf, n);
140
kDebug(30513) << "n=" << n << ", n1=" << n1 << "; buf contains " << (void*) buf;
144
if ((n == 0 && len != 0) || //endless loop
145
(size_t)n1 != n) { //read/wrote different lengths
146
m_store->close(); //close picture file before returning
147
return; //ouch - we're in an endless loop!
149
//Q_ASSERT( (size_t)n1 == n );
152
m_store->close(); //close picture file
156
void KWordPictureHandler::officeArt(wvWare::OfficeArtProperties *artProperties)
158
if (artProperties->shapeType == msosptLine) {
159
officeArtLine(artProperties);
163
#endif // IMAGE_IMPORT
165
void KWordPictureHandler::officeArtLine(wvWare::OfficeArtProperties *artProperties)
167
//TODO: properties like horizontal align should be applied to the picture,
168
//but it has anchor type "as-char", let's check how to implement this.
170
//Check if a picture is comming, this will be displayed instead of a line.
171
if (artProperties->pib) {
176
QString xPos = QString::number(0.0f).append("in");
178
switch (artProperties->align) {
179
case wvWare::hAlignLeft:
180
hrAlign = QString("left");
181
xPos = QString::number(0.0f).append("in");
183
case wvWare::hAlignCenter:
184
hrAlign = QString("center");
185
xPos = QString::number((6.1378f/2.0f) - ((artProperties->width * 6.1378f) / 200.0f)).append("in");
187
case wvWare::hAlignRight:
188
hrAlign = QString("right");
189
xPos = QString::number(6.1378f - (artProperties->width * 6.1378f) / 100.0f).append("in");
194
// create a graphic style
195
QString styleName("gr");
196
styleName.append(QString::number(m_officeArtCount));
197
KoGenStyle *style = new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic", "Graphics");
199
//in case a header or footer is processed, save the style into styles.xml
200
if (m_doc->writingHeader()) {
201
style->setAutoStyleInStylesDotXml(true);
204
QString colorStr = QString("#%1%2%3").arg((int)artProperties->color.r, 2, 16, QChar('0')).arg((int)artProperties->color.g, 2, 16, QChar('0')).arg((int)artProperties->color.b, 2, 16, QChar('0'));
205
style->addProperty("draw:fill","solid");
206
style->addProperty("draw:fill-color", colorStr);
207
style->addProperty("draw:textarea-horizontal-align",hrAlign);
208
style->addProperty("draw:textarea-vertical-align","top");
209
style->addProperty("draw:shadow","hidden");
210
style->addProperty("style:run-through","foreground");
212
styleName = m_mainStyles->insert(*style, styleName, KoGenStyles::DontAddNumberToName);
215
//--------------------
216
// create a custom shape
217
m_bodyWriter->startElement("draw:custom-shape");
218
m_bodyWriter->addAttribute("text:anchor-type", "as-char");
220
QString heightStr = QString::number(artProperties->height).append("in");
221
m_bodyWriter->addAttribute("svg:height", heightStr);
223
QString widthStr = QString::number((artProperties->width * 6.1378f) / 100.0f).append("in");
224
m_bodyWriter->addAttribute("svg:width", widthStr);
225
m_bodyWriter->addAttribute("svg:x", xPos);
226
m_bodyWriter->addAttribute("draw:style-name", styleName.toUtf8());
228
//--------------------
229
m_bodyWriter->startElement("draw:enhanced-geometry");
230
m_bodyWriter->addAttribute("svg:viewBox", "0 0 21600 21600");
231
m_bodyWriter->addAttribute("draw:type", "rectangle");
232
m_bodyWriter->addAttribute("draw:enhanced-path", "M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N");
233
m_bodyWriter->endElement();
234
//--------------------
235
m_bodyWriter->endElement(); // end draw:custom-shape
238
void KWordPictureHandler::ODTProcessing(QString* picName, SharedPtr<const Word97::PICF> picf, int type, wvWare::U32 pib)
240
//check if the referred pib is already in hash table
241
//NOTE: the wmfData function has no pib to pass
242
if (m_pictureName.contains(pib)) {
243
picName->append(m_pictureName.value(pib));
247
picName->append("Pictures/");
248
picName->append(QString::number(m_pictureCount));
250
//the type coming in corresponds to MSOBLIPTYPE see wv2/src/graphics.h
252
picName->append(".jpg");
254
picName->append(".png");
256
picName->append(".wmf");
258
picName->append(".emf");
260
kWarning() << "Unhandled file type (" << type << ") - pictures won't be displayed.";
263
//add entry in manifest file
264
QString mimetype(KMimeType::findByPath(*picName, 0, true)->name());
265
m_manifestWriter->addManifestEntry(*picName, mimetype);
268
QString styleName("fr");
269
styleName.append(QString::number(m_pictureCount));
270
KoGenStyle* style = new KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic", "Graphics");
272
//in case a header or footer is processed, save the style into styles.xml
273
if (m_doc->writingHeader()) {
274
style->setAutoStyleInStylesDotXml(true);
277
styleName = m_mainStyles->insert(*style, styleName, KoGenStyles::DontAddNumberToName);
280
//start frame tag for the picture
281
m_bodyWriter->startElement("draw:frame");
282
m_bodyWriter->addAttribute("draw:style-name", styleName.toUtf8());
283
m_bodyWriter->addAttribute("text:anchor-type", "as-char");
284
//mx, my = horizontal & vertical user scaling in .001 %
285
double horiz_scale = picf->mx / 1000.0;
286
double vert_scale = picf->my / 1000.0;
287
double height = ((double) picf->dyaGoal * vert_scale) / 20.0; //twips -> pt
288
double width = ((double) picf->dxaGoal * horiz_scale) / 20.0; //twips -> pt
289
m_bodyWriter->addAttributePt("svg:height", height);
290
m_bodyWriter->addAttributePt("svg:width", width);
291
//start the actual image tag
292
m_bodyWriter->startElement("draw:image");
293
m_bodyWriter->addAttribute("xlink:href", *picName);
294
m_bodyWriter->addAttribute("xlink:type", "simple");
295
m_bodyWriter->addAttribute("xlink:show", "embed");
296
m_bodyWriter->addAttribute("xlink:actuate", "onLoad");
297
m_bodyWriter->endElement();//draw:image
298
m_bodyWriter->endElement();//draw:frame
301
void KWordPictureHandler::wmfData(OLEImageReader& reader, SharedPtr<const Word97::PICF> picf)
303
wvWare::U8* buf = new wvWare::U8[IMG_BUF_SIZE];
305
kDebug(30513) << "WMF data found. Size=" << reader.size();
309
// Read the first bytes of the picture. We need this to determine
310
// if the contents is a WMF or an EMF.
311
long len = reader.size();
312
size_t n = reader.read(buf, qMin(len, IMG_BUF_SIZE));
314
// Pass 2 for emf image and 3 for wmf image
315
// An EMF has the string " EMF" at the start + offset 40.
316
if (len > 44 && buf[40] == ' ' && buf[41] == 'E' && buf[42] == 'M' && buf[43] == 'F') {
317
kDebug(30513) << "Found an EMF file";
318
ODTProcessing(&picName, picf, 2, 0);
321
kDebug(30513) << "Found a WMF file";
322
ODTProcessing(&picName, picf, 3, 0);
325
// Write picture data to file.
326
m_store->open(picName);//open picture file
328
kDebug(30513) << "len = " << len;
330
// Write the bytes that we have in the buffer.
331
ulong n1 = m_store->write((const char*)buf, n);
332
kDebug(30513) << "n=" << n << ", n1=" << n1 << "; buf contains " << (void*) buf;
335
// Break if something went wrong with the writing.
342
// Read the next batch.
343
size_t n = reader.read(buf, qMin(len, IMG_BUF_SIZE));
346
if (n == 0 && len != 0)
352
m_store->close(); //close picture file
355
void KWordPictureHandler::externalImage(const UString& name, SharedPtr<const Word97::PICF> picf)
360
DrawingWriter::DrawingWriter(KoXmlWriter& xmlWriter, KoGenStyles& kostyles, bool stylesxml_)
361
: Writer(xmlWriter,kostyles,stylesxml_),
50
const char* dashses[11] = {
51
"", "Dash_20_2", "Dash_20_3", "Dash_20_2", "Dash_20_2", "Dash_20_2",
52
"Dash_20_4", "Dash_20_6", "Dash_20_5", "Dash_20_7", "Dash_20_8"
54
const char* arrowHeads[6] = {
55
"", "msArrowEnd_20_5", "msArrowStealthEnd_20_5", "msArrowDiamondEnd_20_5",
56
"msArrowOvalEnd_20_5", "msArrowOpenEnd_20_5"
58
QString format(double v) {
59
static const QString f("%1");
60
static const QString e("");
61
static const QRegExp r("\\.?0+$");
62
return f.arg(v, 0, 'f').replace(r, e);
64
QString pt(double v) {
65
static const QString pt("pt");
66
return format(v) + pt;
68
QString percent(double v) {
69
return format(v) + '%';
71
QString mm(double v) {
72
static const QString mm("mm");
73
return format(v) + mm;
78
* ************************************************
80
* ************************************************
82
DrawingWriter::DrawingWriter(KoXmlWriter& xmlWriter, KoGenStyles& kostyles,
83
bool stylesxml_, bool inlineObj)
84
: Writer(xmlWriter, kostyles, stylesxml_),
367
95
scaleX = 25.4 / 1440;
368
96
scaleY = 25.4 / 1440;
371
QString DrawingWriter::vLength()
99
qreal DrawingWriter::vLength()
373
101
return Writer::vLength(yBottom - yTop);
376
QString DrawingWriter::hLength()
104
qreal DrawingWriter::hLength()
378
106
return Writer::hLength(xRight - xLeft);
381
QString DrawingWriter::vOffset()
109
qreal DrawingWriter::vOffset()
383
111
return Writer::vOffset(yTop);
386
QString DrawingWriter::hOffset()
114
qreal DrawingWriter::hOffset()
388
116
return Writer::hOffset(xLeft);
423
151
yBottom = anchor.yBottom;
426
KWordDrawingHandler::KWordDrawingHandler(Document* doc, KoGenStyles* mainStyles, KoXmlWriter* bodyWriter): QObject()
155
* ************************************************
157
* ************************************************
159
KWordGraphicsHandler::KWordGraphicsHandler(Document* doc, KoXmlWriter* bodyWriter,
160
KoXmlWriter* manifestWriter, KoStore* store,
161
KoGenStyles* mainStyles)
165
, m_bodyWriter(bodyWriter)
166
, m_manifestWriter(manifestWriter)
428
167
, m_mainStyles(mainStyles)
429
, m_bodyWriter(bodyWriter)
431
170
, m_pOfficeArtHeaderDgContainer(0)
432
171
, m_pOfficeArtBodyDgContainer(0)
437
KWordDrawingHandler::~KWordDrawingHandler()
177
KWordGraphicsHandler::~KWordGraphicsHandler()
439
179
delete m_pOfficeArtHeaderDgContainer;
440
180
delete m_pOfficeArtBodyDgContainer;
443
void KWordDrawingHandler::init(Drawings * pDrawings, wvWare::OLEStreamReader* table,const wvWare::Word97::FIB &fib)
184
* NOTE: All containers parsed by this function are optional.
186
void KWordGraphicsHandler::init(Drawings * pDrawings, const wvWare::Word97::FIB &fib)
447
parseOfficeArtContainer(table,fib);
449
// create default draw style
450
// KoGenStyle style(KoGenStyle::GraphicStyle, "graphic");
451
// style.setDefaultStyle(true);
453
// defineDefaultGraphicProperties(&style,pDrawings);
455
// //add default draw style to styles
456
// m_mainStyles->insert(style, "");
190
//TODO: do not use POLE storage here, get the pointer to the stream, have
191
//to access FIB first in mswordodfimport.cpp
192
parseOfficeArtContainer(m_document->storage(), fib);
194
//create default GraphicStyle using information from OfficeArtDggContainer
195
defineDefaultGraphicStyle(m_mainStyles);
197
//parse and store floating pictures
198
parseFloatingPictures();
199
m_picNames = createFloatingPictures(m_store, m_manifestWriter);
458
201
m_drawings = pDrawings;
461
void KWordDrawingHandler::drawingData(unsigned int globalCP)
202
m_fib = const_cast<wvWare::Word97::FIB *>(&fib);
204
//Provide the backgroud color information to the Document, if present.
205
DrawStyle ds = getDrawingStyle();
207
MSO::OfficeArtCOLORREF fc = ds.fillColor();
208
QColor color = QColor(fc.red, fc.green, fc.blue);
209
QString tmp = color.name();
210
if (tmp != m_document->currentBgColor()) {
211
m_document->updateBgColor(tmp);
217
void KWordGraphicsHandler::handleInlineObject(const wvWare::PictureData& data)
220
// going to parse and process the Data stream content
221
LEInputStream* in = m_document->data_stream();
222
int size = (data.picf->lcb - data.picf->cbHeader);
224
kDebug(30513) << "\nCurrent stream position: " << in->getPosition()
225
<< "\nOfficeArtInlineSpContainer offset: " << data.fcPic
226
<< "\nPICF size: " << data.picf->cbHeader
227
<< "\nOfficeArtData size: " << size;
229
// parse the OfficeArtInlineSpContainer and rewind the stream
230
LEInputStream::Mark _zero;
231
_zero = in->setMark();
232
in->skip(data.fcPic);
233
OfficeArtInlineSpContainer co;
234
parseOfficeArtInlineSpContainer(*in, co);
236
int n = (data.fcPic + size) - in->getPosition();
238
kDebug(30513) << "Warning: " << n
239
<< " bytes left while parsing OfficeArtInlineSpContainer";
243
// store picture data if present and update m_picNames
244
PictureReference ref;
245
m_store->enterDirectory("Pictures");
246
foreach (const OfficeArtBStoreContainerFileBlock& block, co.rgfb) {
247
const OfficeArtFBSE* fbse = block.anon.get<MSO::OfficeArtFBSE>();
249
kDebug(30513) << "Warning: FBSE container not found, skipping ";
252
//check if this BLIP is already in hash table
253
if (m_picNames.contains(fbse->rgbUid)) {
254
ref.uid = fbse->rgbUid;
258
ref = savePicture(block, m_store);
259
if (ref.name.length() == 0) {
260
kDebug(30513) << "empty name in picture reference";
263
m_manifestWriter->addManifestEntry("Pictures/" + ref.name, ref.mimetype);
264
m_picNames[ref.uid] = ref.name;
268
m_store->leaveDirectory();
270
DrawingWriter out(*m_bodyWriter, *m_mainStyles, true, true);
271
out.m_picf = data.picf;
272
out.m_rgbUid = ref.uid;
274
OfficeArtSpContainer* o = &(co.shape);
275
processDrawingObject(*o, out);
278
void KWordGraphicsHandler::handleFloatingObject(unsigned int globalCP)
280
kDebug(30513) << "globalCP" << globalCP ;
465
281
// draw shape or group of shapes
466
if(m_drawings == NULL) {
282
if (m_drawings == NULL) {
470
286
PLCF<Word97::FSPA>* fspa = m_drawings->getSpaMom();
288
PLCFIterator<Word97::FSPA> it(fspa->at(0));
290
//search for drawing in main body
291
for (size_t i = 0; i < fspa->count(); i++, ++it) {
292
kDebug(30513) << "FSPA start:" << it.currentStart();
293
kDebug(30513) << "FSPA spid:" << it.current()->spid;
295
if (it.currentStart() == globalCP) {
296
DrawingWriter out(*m_bodyWriter, *m_mainStyles, true, false);
297
out.m_pSpa = it.current();
298
out.m_bodyDrawing = true;
299
locateDrawing((m_pOfficeArtBodyDgContainer->groupShape).data(), out,
300
it.current(), (uint) it.current()->spid);
475
PLCFIterator<Word97::FSPA> it( fspa->at( 0 ) );
477
kDebug(30513) << "globalCP" << globalCP ;
480
for(size_t i = 0; i < fspa->count(); i++, ++it) {
481
kDebug(30513) << "FSPA start:" << it.currentStart();
482
kDebug(30513) << "FSPA spid:" << it.current()->spid;
484
if(it.currentStart() == globalCP) {
485
KoGenStyles tmpStyles; //not used yet
486
DrawingWriter out(*m_bodyWriter,tmpStyles,true);
487
drawObject((uint) it.current()->spid, m_pOfficeArtBodyDgContainer, out,it.current());
306
fspa = m_drawings->getSpaHdr();
308
PLCFIterator<Word97::FSPA> itHeader(fspa->at(0));
309
//search for drawing in header
310
for (size_t i = 0; i < fspa->count(); i++, ++itHeader) {
311
kDebug(30513) << "FSPA start:" << itHeader.currentStart() + m_fib->ccpText + m_fib->ccpFtn;
312
kDebug(30513) << "FSPA spid:" << itHeader.current()->spid;
314
if ((itHeader.currentStart() + m_fib->ccpText + m_fib->ccpFtn) == globalCP) {
315
DrawingWriter out(*m_bodyWriter, *m_mainStyles, true, false);
316
out.m_pSpa = itHeader.current();
317
out.m_bodyDrawing = false;
318
locateDrawing((m_pOfficeArtHeaderDgContainer->groupShape).data(), out,
319
itHeader.current(), (uint) itHeader.current()->spid);
493
void KWordDrawingHandler::setBodyWriter(KoXmlWriter* writer)
326
void KWordGraphicsHandler::setBodyWriter(KoXmlWriter* writer)
495
328
m_bodyWriter = writer;
498
DrawStyle KWordDrawingHandler::getDrawingStyle()
331
DrawStyle KWordGraphicsHandler::getDrawingStyle()
500
if(m_pOfficeArtBodyDgContainer != NULL) {
501
if(m_pOfficeArtBodyDgContainer->shape.isNull() == false) {
502
if((*m_pOfficeArtBodyDgContainer->shape).shapePrimaryOptions.isNull() == false ) {
503
return DrawStyle(m_OfficeArtDggContainer,NULL,m_pOfficeArtBodyDgContainer->shape.data());
333
if (m_pOfficeArtBodyDgContainer != NULL) {
334
if (m_pOfficeArtBodyDgContainer->shape.isNull() == false) {
335
if ((*m_pOfficeArtBodyDgContainer->shape).shapePrimaryOptions.isNull() == false) {
336
return DrawStyle(m_OfficeArtDggContainer, NULL, m_pOfficeArtBodyDgContainer->shape.data());
507
340
return DrawStyle(m_OfficeArtDggContainer);
510
void KWordDrawingHandler::drawObject(uint spid, MSO::OfficeArtDgContainer * dg, DrawingWriter& out
511
, wvWare::Word97::FSPA* spa)
343
void KWordGraphicsHandler::locateDrawing(const MSO::OfficeArtSpgrContainer* spgr, DrawingWriter& out,
344
wvWare::Word97::FSPA* spa, uint spid)
516
foreach(const OfficeArtSpgrContainerFileBlock& co, dg->groupShape.rgfb) {
517
//if spgr is in root, find out if his first item is sp with right spid
351
//FIXME: combine childAnchor, shapeGroup coordinates with information from
352
//clientAnchor pointing to the SPA structure!
354
//NOTE: The OfficeArtSpgrContainer record specifies a container for groups
355
//(4) of shapes. The group (4) container contains a variable number of
356
//shape containers and other group (4) containers. Each group (4) is a
357
//shape. The first container MUST be an OfficeArtSpContainer record, which
358
//MUST contain shape information for the group. MS-ODRAW, 2.2.16
360
foreach (const OfficeArtSpgrContainerFileBlock& co, spgr->rgfb) {
518
362
if (co.anon.is<OfficeArtSpgrContainer>()) {
519
const OfficeArtSpContainer* first =
520
(*co.anon.get<OfficeArtSpgrContainer>()).rgfb[0].anon.get<OfficeArtSpContainer>();
522
if(first && first->shapeProp.spid == spid) {
523
out.SetRectangle(*spa);
524
processObjectForBody(*co.anon.get<OfficeArtSpgrContainer>(), out); //draw group
528
else //if sp is in root, find out if it has the right spid
530
const OfficeArtSpContainer & spCo = *co.anon.get<OfficeArtSpContainer>();
532
if(spCo.shapeProp.spid == spid) {
533
out.SetRectangle(*spa);
534
processObjectForBody(spCo, out); //draw object
363
const OfficeArtSpContainer* first =
364
(*co.anon.get<OfficeArtSpgrContainer>()).rgfb[0].anon.get<OfficeArtSpContainer>();
365
if (first && first->shapeProp.spid == spid) {
366
out.SetRectangle(*spa);
367
processGroup(*co.anon.get<OfficeArtSpgrContainer>(), out);
370
m_zIndex = m_zIndex + (*co.anon.get<OfficeArtSpgrContainer>()).rgfb.size();
373
const OfficeArtSpContainer &sp = *co.anon.get<OfficeArtSpContainer>();
374
if (sp.shapeProp.fGroup) {
376
out.SetGroupRectangle(*sp.shapeGroup);
378
if (sp.shapeProp.spid == spid) {
379
kDebug(30513) << "An unprocessed shape storing information for the group is referred from text!";
381
} else if (sp.shapeProp.spid == spid) {
382
out.SetRectangle(*spa);
383
processDrawingObject(sp, out);
541
void KWordDrawingHandler::processObjectForBody(const MSO::OfficeArtSpgrContainer& o, DrawingWriter& out)
391
void KWordGraphicsHandler::processGroup(const MSO::OfficeArtSpgrContainer& o, DrawingWriter& out)
543
if (o.rgfb.size() < 2) return;
393
if (o.rgfb.size() < 2) {
396
//TODO: create corresponding style and apply style properties
545
397
out.xml.startElement("draw:g");
547
398
const OfficeArtSpContainer *first = o.rgfb[0].anon.get<OfficeArtSpContainer>();
548
if(first && first->shapeGroup) {
549
out.SetGroupRectangle(*first->shapeGroup); //set group rectangle
400
if (first && first->shapeGroup) {
401
//process shape information for the group
402
out.SetGroupRectangle(*first->shapeGroup);
552
405
for (int i = 1; i < o.rgfb.size(); ++i) {
553
if(o.rgfb[i].anon.is<OfficeArtSpContainer>()) {
555
OfficeArtSpContainer tempSp = *o.rgfb[i].anon.get<OfficeArtSpContainer>();
557
if(tempSp.childAnchor) {
558
out.SetClientRectangle(*tempSp.childAnchor); //set child rectangle
406
if (o.rgfb[i].anon.is<OfficeArtSpContainer>()) {
407
OfficeArtSpContainer sp = *o.rgfb[i].anon.get<OfficeArtSpContainer>();
408
if (sp.childAnchor) {
409
out.SetClientRectangle(*sp.childAnchor); //set child rectangle
561
processObjectForBody(tempSp, out); //draw objects
411
processDrawingObject(sp, out); //draw objects
413
//TODO: another group shape can be here! We should call locateDrawing
565
416
out.xml.endElement(); // draw:g
568
void KWordDrawingHandler::processObjectForBody(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
419
void KWordGraphicsHandler::processDrawingObject(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
423
DrawStyle ds(NULL, &o);
425
// check the shape type and process it
426
kDebug(30513) << "shapeType: " << hex << o.shapeProp.rh.recInstance;
427
kDebug(30513) << "grupShape: " << o.shapeProp.fGroup;
428
kDebug(30513) << "Selected properties: ";
429
kDebug(30513) << "pib: " << ds.pib();
572
431
// textbox can be msosptTextBox or msosptRectangle or ...
573
if(!o.clientTextbox.isNull()) {
432
if (!o.clientTextbox.isNull()) {
574
433
kDebug(30513)<< "processing text box";
575
434
parseTextBox(o, out);
580
438
switch (o.shapeProp.rh.recInstance)
440
case msosptRectangle: {
441
kDebug(30513)<< "processing rectangle";
442
//check group shape boolean properties for details
443
if (ds.fHorizRule()) {
444
kDebug(30513)<< "processing a line shape";
445
processLineShape(o, out);
447
processRectangle(o, out);
451
kDebug(30513)<< "processing ellipse";
582
453
case msosptPictureFrame:
583
kDebug(30513)<< "processing picture frame";
584
processPictureFrame(o, out);
454
kDebug(30513)<< "processing a frame shape";
456
processInlinePictureFrame(o, out);
459
processFloatingPictureFrame(o, out);
586
462
case msosptHostControl:
587
463
kDebug(30513)<< "processing host control";
708
if (stream.getPosition() != buffer.size()) {
709
kDebug(30513) << (uint)(buffer.size() - stream.getPosition())
585
if (in.getPosition() != buffer.size()) {
586
kDebug(30513) << (uint)(buffer.size() - in.getPosition())
710
587
<< "bytes left at the end of parseOfficeArtDggContainer,"
711
588
<< " parseOfficeArtDgContainer, so probably an error at position "
712
<< (uint)stream.getMaxPosition();
717
void KWordDrawingHandler::parseTextBox(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
719
out.xml.startElement("draw:frame");
589
<< (uint) in.getMaxPosition();
595
void KWordGraphicsHandler::defineDefaultGraphicStyle(KoGenStyles* styles)
597
// write style <style:default-style style:family="graphic">
598
KoGenStyle style(KoGenStyle::GraphicStyle, "graphic");
599
DrawStyle ds(m_OfficeArtDggContainer);
600
style.setDefaultStyle(true);
601
defineGraphicProperties(style, ds);
602
styles->insert(style);
605
void KWordGraphicsHandler::defineGraphicProperties(KoGenStyle& style, const DrawStyle& ds,
606
const QString& listStyle)
608
MSO::OfficeArtCOLORREF clr;
609
const KoGenStyle::PropertyType gt = KoGenStyle::GraphicType;
610
// dr3d:ambient-color
612
// dr3d:backface-culling
616
// dr3d:diffuse-color
617
// dr3d:edge-rounding
618
// dr3d:edge-rounding-mode
619
// dr3d:emissive-color
621
// dr3d:horizontal-segments
622
// dr3d:lighting-mode
623
// dr3d:normals-direction
627
// dr3d:specular-color
628
// dr3d:texture-filter
629
// dr3d:texture-generation-mode-x
630
// dr3d:texture-generation-mode-y
633
// dr3d:vertical-segments
634
// draw:auto-grow-height
635
// draw:auto-grow-width
637
// draw:caption-angle
638
// draw:caption-angle-type
639
// draw:caption-escape
640
// draw:caption-escape-direction
641
// draw:caption-fit-line-length
643
// draw:caption-line-length
645
// draw:color-inversion
648
// draw:decimal-places
650
// draw:end-line-spacing-horizontal
651
// draw:end-line-spacing-vertical
653
// NOTE: fFilled specifies whether fill of the shape is render based on the
654
// properties of the "fill style" property set.
656
qint32 fillType = ds.fillType();
657
// draw:fill ("bitmap", "gradient", "hatch", "none" or "solid")
658
style.addProperty("draw:fill", getFillType(fillType), gt);
659
// NOTE: only set the color if the fill type is 'solid' because OOo
660
// ignores fill='none' if the color is set
662
clr = ds.fillColor();
663
style.addProperty("draw:fill-color", QColor(clr.red, clr.green, clr.blue).name(), gt);
666
style.addProperty("draw:fill", "none", gt);
668
// draw:fill-gradient-name
669
// draw:fill-hatch-name
670
// draw:fill-hatch-solid
671
// draw:fill-image-name
672
// draw:fill-image-ref-point
673
// draw:fill-image-ref-point-x
674
// draw:fill-image-ref-point-y
675
// draw:fill-image-height
676
// draw:fill-image-width
677
// draw:fit-to-contour
679
// draw:frame-display-border
680
// draw:frame-display-scrollbar
681
// draw:frame-margin-horizontal
682
// draw:frame-margin-vertical
684
// draw:gradient-step-count
686
// draw:guide-distance
687
// draw:guide-overhang
688
// draw:image-opacity
689
// draw:line-distance
692
quint32 lineEndArrowhead = ds.lineEndArrowhead();
693
if (lineEndArrowhead > 0 && lineEndArrowhead < 6) {
694
style.addProperty("draw:marker-end", arrowHeads[lineEndArrowhead], gt);
696
// draw:marker-end-center
697
// draw:marker-end-width
698
qreal lineWidthPt = ds.lineWidth() / 12700.;
699
style.addProperty("draw:marker-end-width",
700
pt(lineWidthPt*4*(1+ds.lineEndArrowWidth())), gt);
702
quint32 lineStartArrowhead = ds.lineStartArrowhead();
703
if (lineStartArrowhead > 0 && lineStartArrowhead < 6) {
704
style.addProperty("draw:marker-start", arrowHeads[lineStartArrowhead],
707
// draw:marker-start-center
708
// draw:marker-start-width
709
style.addProperty("draw:marker-start-width",
710
pt(lineWidthPt*4*(1+ds.lineStartArrowWidth())), gt);
711
// draw:measure-align
712
// draw:measure-vertical-align
713
// draw:ole-draw-aspect
719
// draw:secondary-fill-color
721
// NOTE: fShadow property specifies whether the shape has a shadow.
724
style.addProperty("draw:shadow", "visible", gt);
726
clr = ds.shadowColor();
727
style.addProperty("draw:shadow-color", QColor(clr.red, clr.green, clr.blue).name(), gt);
728
//shadowOffset* properties MUST exist if shadowType property equals
729
//msoshadowOffset or msoshadowDouble, otherwise MUST be ignored,
731
quint32 type = ds.shadowType();
732
if ((type == 0) || (type == 1)) {
733
// draw:shadow-offset-x
734
style.addProperty("draw:shadow-offset-x", pt(ds.shadowOffsetX()/12700.), gt);
735
// draw:shadow-offset-y
736
style.addProperty("draw:shadow-offset-y", pt(ds.shadowOffsetY()/12700.), gt);
738
// draw:shadow-opacity
739
float shadowOpacity = toQReal(ds.shadowOpacity());
740
style.addProperty("draw:shadow-opacity", percent(100*shadowOpacity), gt);
742
style.addProperty("draw:shadow", "hidden");
746
// draw:start-line-spacing-horizontal
747
// draw:start-line-spacing-vertical
748
// draw:stroke ('dash', 'none' or 'solid')
749
quint32 lineDashing = ds.lineDashing();
750
// OOo interprets solid line with with 0 as hairline, so if
751
// width == 0, stroke *must* be none to avoid OOo from
753
if (lineWidthPt == 0) {
754
style.addProperty("draw:stroke", "none", gt);
755
} else if (ds.fLine() || ds.fNoLineDrawDash()) {
756
if (lineDashing > 0 && lineDashing < 11) {
757
style.addProperty("draw:stroke", "dash", gt);
759
style.addProperty("draw:stroke", "solid", gt);
762
style.addProperty("draw:stroke", "none", gt);
764
// draw:stroke-dash from 2.3.8.17 lineDashing
765
if (lineDashing > 0 && lineDashing < 11) {
766
style.addProperty("draw:stroke-dash", dashses[lineDashing], gt);
768
// draw:stroke-dash-names
769
// draw:stroke-linejoin
771
// draw:textarea-horizontal-align
772
// draw:textarea-vertical-align
773
// draw:tile-repeat-offset
775
// draw:visible-area-height
776
// draw:visible-area-left
777
// draw:visible-area-top
778
// draw:visible-area-width
779
// draw:wrap-influence-on-position
780
// fo:background-color
797
// style:border-line-width
798
// style:border-line-width-bottom
799
// style:border-line-width-left
800
// style:border-line-width-right
801
// style:border-line-width-top
803
// style:flow-with-text
805
// style:overflow-behavior
806
// style:print-content
813
// svg:stroke-color from 2.3.8.1 lineColor
814
clr = ds.lineColor();
815
QColor lineColor(clr.red,clr.green,clr.blue);
816
style.addProperty("svg:stroke-color", lineColor.name(), gt);
817
// svg:stroke-opacity from 2.3.8.2 lineOpacity
818
style.addProperty("svg:stroke-opacity",
819
percent(100.0 * ds.lineOpacity() / 0x10000), gt);
820
// svg:stroke-width from 2.3.8.14 lineWidth
821
style.addProperty("svg:stroke-width", pt(lineWidthPt), gt);
825
// text:anchor-page-number
828
// text:animation-delay
829
// text:animation-direction
830
// text:animation-repeat
831
// text:animation-start-inside
832
// text:animation-steps
833
// text:animation-stop-inside
835
/* associate with a text:list-style element */
836
if (!listStyle.isNull()) {
837
style.addAttribute("style:list-style-name", listStyle);
841
void KWordGraphicsHandler::defineAnchorProperties(KoGenStyle& style, const DrawStyle& ds)
843
// style:horizontal-pos MS-ODRAW - 2.3.4.19
844
quint32 posH = ds.posH();
845
if (posH == 0) { // msophAbs
846
style.addProperty("style:horizontal-pos","from-left");
847
} else if (posH == 1) { // msophLeft
848
style.addProperty("style:horizontal-pos","left");
849
} else if (posH == 2) { // msophCenter
850
style.addProperty("style:horizontal-pos","center");
851
} else if (posH == 3) { // msophRight
852
style.addProperty("style:horizontal-pos","right");
853
} else if (posH == 4) { // msophInside
854
style.addProperty("style:horizontal-pos","inside");
855
} else if (posH == 5) { // msophOutside
856
style.addProperty("style:horizontal-pos","outside");
859
// style:horizontal-rel MS-ODRAW 2.3.4.20
860
quint32 posRelH = ds.posRelH();
862
if (posRelH == 0) {//msoprhMargin
863
style.addProperty("style:horizontal-rel","page-content");
864
} else if (posRelH == 1) {//msoprhPage
865
style.addProperty("style:horizontal-rel","page");
866
} else if (posRelH == 2) {//msoprhText
867
style.addProperty("style:horizontal-rel","paragraph");
868
} else if (posRelH == 3) {//msoprhChar
869
style.addProperty("style:horizontal-rel","char");
871
style.addProperty("style:horizontal-rel","page-content");
874
// style:vertical-pos MS-ODRAW - 2.3.4.21
875
quint32 posV = ds.posV();
876
if (posV == 0) { // msophAbs
877
style.addProperty("style:vertical-pos","from-top");
878
} else if (posV == 1) { // msophTop
879
style.addProperty("style:vertical-pos","top");
880
} else if (posV == 2) { // msophCenter
881
style.addProperty("style:vertical-pos","middle");
882
} else if (posV == 3) { // msophBottom
883
style.addProperty("style:vertical-pos","bottom");
884
} else if (posV == 4) { // msophInside - not possible to write it into odf
885
style.addProperty("style:vertical-pos","top");
886
} else if (posV == 5) { // msophOutside - not possible to write it into odf
887
style.addProperty("style:vertical-pos","bottom");
890
// style:vertical-rel MS-ODRAW 2.3.4.22
891
quint32 posRelV = ds.posRelV();
892
if (posRelV == 0) {//msoprvMargin
893
style.addProperty("style:vertical-rel","page-content");
894
} else if (posRelV == 1) {//msoprvPage
895
style.addProperty("style:vertical-rel","page");
896
} else if (posRelV == 2) {//msoprvText
897
style.addProperty("style:vertical-rel","paragraph");
898
} else if (posRelV == 3) { //msoprvLine
899
style.addProperty("style:vertical-rel","line");
901
style.addProperty("style:vertical-rel","page-content");
905
void KWordGraphicsHandler::defineWrappingProperties(KoGenStyle& style, const DrawStyle& ds, const wvWare::Word97::FSPA* spa)
907
//process the wrapping style, (MS-DOC, page 464)
909
bool check_wrk = false;
911
//wrap around the object
914
else if (spa->wr == 1) {
915
//top and bottom wrapping
916
style.addProperty("style:wrap", "none");
918
else if (spa->wr == 2) {
922
else if (spa->wr == 3) {
923
//in front or behind the text
924
style.addProperty("style:wrap", "run-through");
925
//check if shape is behind the text
926
if ((spa->fBelowText == 1) || (ds.fBehindDocument())) {
927
style.addProperty("style:run-through", "background");
929
style.addProperty("style:run-through", "foreground");
932
else if (spa->wr == 4) {
935
style.addProperty("style:wrap-contour", "true");
936
style.addProperty("style:wrap-contour-mode", "outside");
938
else if (spa->wr == 5) {
941
style.addProperty("style:wrap-contour", "true");
942
style.addProperty("style:wrap-contour-mode", "full");
944
//check details of the text wrapping around this shape
947
style.addProperty("style:wrap", "parallel");
949
else if (spa->wrk == 1) {
950
style.addProperty("style:wrap", "left");
952
else if (spa->wrk == 2) {
953
style.addProperty("style:wrap", "right");
955
else if (spa->wrk == 3) {
956
style.addProperty("style:wrap", "biggest");
960
//no information from plcfSpa available
962
style.addProperty("style:wrap", "run-through");
963
if (ds.fBehindDocument()) {
964
style.addProperty("style:run-through", "background");
966
style.addProperty("style:run-through", "foreground");
970
//margins are related to text wrapping,
971
style.addPropertyPt("style:margin-left", ds.dxWrapDistLeft()/12700.);
972
style.addPropertyPt("style:margin-right", ds.dxWrapDistRight()/12700.);
973
style.addPropertyPt("style:margin-top", ds.dyWrapDistTop()/12700.);
974
style.addPropertyPt("style:margin-bottom", ds.dyWrapDistBottom()/12700.);
976
// style:number-wrapped-paragraphs
977
// style:wrap-dynamic-treshold
980
void KWordGraphicsHandler::SetAnchorTypeAttribute(DrawingWriter& out)
983
out.xml.addAttribute("text:anchor-type","as-char");
985
out.xml.addAttribute("text:anchor-type","char");
989
void KWordGraphicsHandler::SetZIndexAttribute(DrawingWriter& out)
991
out.xml.addAttribute("draw:z-index",m_zIndex);
994
void KWordGraphicsHandler::parseTextBox(const MSO::OfficeArtSpContainer& o, DrawingWriter out)
997
DrawStyle ds(m_OfficeArtDggContainer,&o);
721
998
DrawStyle drawStyle(m_OfficeArtDggContainer,NULL,&o);
999
wvWare::Word97::FSPA* spa = out.m_pSpa;
1000
KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
1002
if (!out.m_bodyDrawing) {
1003
style.setAutoStyleInStylesDotXml(true);
1005
defineGraphicProperties(style, ds);
1006
defineWrappingProperties(style, ds, spa);
1007
defineAnchorProperties(style, ds);
1008
styleName = out.styles.insert(style);
1010
out.xml.startElement("draw:frame");
1011
out.xml.addAttribute("draw:style-name", styleName);
1012
SetAnchorTypeAttribute(out);
1013
SetZIndexAttribute(out);
723
1015
switch(drawStyle.txflTextFlow()) {
724
1016
case 1: //msotxflTtoBA up-down
725
1017
case 3: //msotxflTtoBN up-down
726
1018
case 5: //msotxflVertN up-down
727
out.xml.addAttribute("svg:width", out.vLength());
728
out.xml.addAttribute("svg:height",out.hLength());
1019
out.xml.addAttribute("svg:width", mm(out.vLength()));
1020
out.xml.addAttribute("svg:height", mm(out.hLength()));
729
1021
out.xml.addAttribute("draw:transform","matrix(0 1 -1 0 " +
730
((Writer *)&out)->hOffset(out.xRight) + " " + out.vOffset() + ")");
1022
mm(((Writer *)&out)->hOffset(out.xRight)) + " " + mm(out.vOffset()) + ")");
732
1024
case 2: //msotxflBtoT down-up
733
out.xml.addAttribute("svg:width", out.vLength());
734
out.xml.addAttribute("svg:height",out.hLength());
1025
out.xml.addAttribute("svg:width", mm(out.vLength()));
1026
out.xml.addAttribute("svg:height", mm(out.hLength()));
735
1027
out.xml.addAttribute("draw:transform","matrix(0 -1 1 0 " +
736
out.hOffset() + " " + ((Writer *)&out)->vOffset(out.yBottom) + ")");
1028
mm(out.hOffset()) + " " + mm(((Writer *)&out)->vOffset(out.yBottom)) + ")");
738
1030
default : //standard text flow
739
out.xml.addAttribute("svg:width", out.hLength());
740
out.xml.addAttribute("svg:height", out.vLength());
741
out.xml.addAttribute("svg:x", out.hOffset());
742
out.xml.addAttribute("svg:y", out.vOffset());
745
out.xml.startElement("draw:text-box");
747
emit textBoxFound(o.shapeProp.spid , &out.xml);
749
out.xml.endElement(); //draw:text-box
750
out.xml.endElement(); // draw:frame
753
void KWordDrawingHandler::processPictureFrame(const MSO::OfficeArtSpContainer&/* o*/,DrawingWriter&/* out*/)
1031
out.xml.addAttribute("svg:width", mm(out.hLength()));
1032
out.xml.addAttribute("svg:height", mm(out.vLength()));
1033
out.xml.addAttribute("svg:x", mm(out.hOffset()));
1034
out.xml.addAttribute("svg:y", mm(out.vOffset()));
1037
out.xml.startElement("draw:text-box");
1039
emit textBoxFound(o.shapeProp.spid , out.m_bodyDrawing);
1041
out.xml.endElement(); //draw:text-box
1042
out.xml.endElement(); //draw:frame
1045
void KWordGraphicsHandler::processRectangle(const MSO::OfficeArtSpContainer& o,DrawingWriter& out)
1048
DrawStyle ds(m_OfficeArtDggContainer,&o);
1049
wvWare::Word97::FSPA* spa = out.m_pSpa;
1050
KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
1052
if (!out.m_bodyDrawing) {
1053
style.setAutoStyleInStylesDotXml(true);
1055
defineGraphicProperties(style, ds);
1056
defineWrappingProperties(style, ds, spa);
1057
defineAnchorProperties(style, ds);
1058
styleName = out.styles.insert(style);
1060
out.xml.startElement("draw:frame");
1061
out.xml.addAttribute("draw:style-name", styleName);
1062
SetAnchorTypeAttribute(out);
1063
SetZIndexAttribute(out);
1064
out.xml.addAttribute("draw:layer", "layout");
1065
out.xml.addAttribute("svg:width", mm(out.hLength()));
1066
out.xml.addAttribute("svg:height", mm(out.vLength()));
1067
out.xml.addAttribute("svg:x", mm(out.hOffset()));
1068
out.xml.addAttribute("svg:y", mm(out.vOffset()));
1070
out.xml.startElement("draw:text-box");
1071
out.xml.endElement(); //draw:text-box
1072
out.xml.endElement(); //draw:frame
1075
void KWordGraphicsHandler::processInlinePictureFrame(const MSO::OfficeArtSpContainer& o, DrawingWriter& out)
1080
DrawStyle ds(NULL, &o);
1081
KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
1083
//in case a header or footer is processed, save the style into styles.xml
1084
if (m_document->writingHeader()) {
1085
style.setAutoStyleInStylesDotXml(true);
1087
defineGraphicProperties(style, ds);
1088
styleName = out.styles.insert(style);
1091
QString name = m_picNames.value(out.m_rgbUid);
1092
if (!name.isEmpty()) {
1093
url.append("Pictures/");
1096
out.xml.startElement("draw:frame");
1097
if (url.isEmpty()) {
1098
// if the image cannot be found, just place an empty frame
1099
out.xml.endElement(); //draw:frame
1102
out.xml.addAttribute("draw:style-name", styleName);
1103
out.xml.addAttribute("text:anchor-type","as-char");
1105
double hscale = out.m_picf->mx / 1000.0;
1106
double vscale = out.m_picf->my / 1000.0;
1108
out.xml.addAttributePt("svg:width", twipsToPt(out.m_picf->dxaGoal) * hscale);
1109
out.xml.addAttributePt("svg:height", twipsToPt(out.m_picf->dyaGoal) * vscale);
1111
//TODO: process border information (complex properties)
1113
out.xml.startElement("draw:image");
1114
out.xml.addAttribute("xlink:href", url);
1115
out.xml.addAttribute("xlink:type", "simple");
1116
out.xml.addAttribute("xlink:show", "embed");
1117
out.xml.addAttribute("xlink:actuate", "onLoad");
1118
out.xml.endElement(); //draw:image
1119
out.xml.endElement(); //draw:frame
1123
void KWordGraphicsHandler::processFloatingPictureFrame(const MSO::OfficeArtSpContainer& o, DrawingWriter& out)
1128
DrawStyle ds(m_OfficeArtDggContainer, &o);
1129
wvWare::Word97::FSPA* spa = out.m_pSpa;
1130
KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
1132
//in case a header or footer is processed, save the style into styles.xml
1133
if (m_document->writingHeader()) {
1134
style.setAutoStyleInStylesDotXml(true);
1136
defineGraphicProperties(style, ds);
1137
defineWrappingProperties(style, ds, spa);
1138
defineAnchorProperties(style, ds);
1140
//ODF-1.2: specifies the number of paragraphs that can wrap around a frame
1141
//if wrap mode is in {left, right, parallel, dynamic} and anchor type is in
1144
if ((spa->wr != 1) && (spa->wr != 3)) {
1145
style.addProperty("style:number-wrapped-paragraphs", "no-limit");
1148
styleName = out.styles.insert(style);
1152
url = getPicturePath(ds.pib());
1154
out.xml.startElement("draw:frame");
1155
if (url.isEmpty()) {
1156
//if the image cannot be found, just place an empty frame
1157
out.xml.endElement(); //draw:frame
1160
out.xml.addAttribute("draw:style-name", styleName);
1161
out.xml.addAttribute("text:anchor-type","char");
1162
SetZIndexAttribute(out);
1163
out.xml.addAttribute("svg:width", mm(out.hLength()));
1164
out.xml.addAttribute("svg:height", mm(out.vLength()));
1165
out.xml.addAttribute("svg:x", mm(out.hOffset()));
1166
out.xml.addAttribute("svg:y", mm(out.vOffset()));
1168
out.xml.startElement("draw:image");
1169
out.xml.addAttribute("xlink:href", url);
1170
out.xml.addAttribute("xlink:type", "simple");
1171
out.xml.addAttribute("xlink:show", "embed");
1172
out.xml.addAttribute("xlink:actuate", "onLoad");
1173
out.xml.endElement(); //draw:image
1175
//check for user edited wrap points
1176
if (ds.fEditedWrap()) {
1178
IMsoArray _v = ds.pWrapPolygonVertices_complex();
1179
if (_v.data.size()) {
1180
//_v.data is an array of POINTs, MS-ODRAW, page 89
1184
for (int i = 0, offset = 0; i < _v.nElems; i++, offset += _v.cbElem) {
1185
// x coordinate of this point
1186
a = _v.data.mid(offset, _v.cbElem);
1187
a2 = a.mid(0, _v.cbElem / 2);
1188
p = (int*) a2.data();
1189
points.append(QString::number(twipsToPt(*p)));
1191
// y coordinate of this point
1192
a2 = a.mid(_v.cbElem / 2, _v.cbElem / 2);
1193
p = (int*) a2.data();
1194
points.append(QString::number(twipsToPt(*p)));
1197
points.chop(1); //remove last space
1199
out.xml.startElement("draw:contour-polygon");
1200
out.xml.addAttribute("draw:points", points);
1201
out.xml.endElement(); //draw:contour-polygon
1203
out.xml.endElement(); //draw:frame
1207
void KWordGraphicsHandler::processLineShape(const MSO::OfficeArtSpContainer& o, DrawingWriter& out)
1212
DrawStyle ds(NULL, &o);
1213
KoGenStyle style(KoGenStyle::GraphicAutoStyle, "graphic");
1215
//in case a header or footer is processed, save the style into styles.xml
1216
if (m_document->writingHeader()) {
1217
style.setAutoStyleInStylesDotXml(true);
1219
defineGraphicProperties(style, ds);
1221
//NOTE: also the dxWidthHR propertie may store the width information
1222
float width = ds.pctHR() / 10.0;
1225
QString xPos = QString::number(0.0f).append("in");
1226
const float base_width = 6.1378;
1228
switch (ds.alignHR()) {
1229
case wvWare::hAlignLeft:
1230
hrAlign = QString("left");
1231
xPos = QString::number(0.0f).append("in");
1233
case wvWare::hAlignCenter:
1234
hrAlign = QString("center");
1235
xPos = QString::number((base_width / 2.0) - ((width * base_width) / 200.0)).append("in");
1237
case wvWare::hAlignRight:
1238
hrAlign = QString("right");
1239
xPos = QString::number(base_width - (width * base_width) / 100.0).append("in");
1242
//process the content of HR specific properties
1243
style.addProperty("draw:textarea-horizontal-align", hrAlign);
1244
style.addProperty("draw:textarea-vertical-align", "top");
1245
if (ds.fNoshadeHR()) {
1246
style.addProperty("draw:shadow", "hidden");
1249
style.addProperty("draw:shadow", "visible");
1251
styleName = out.styles.insert(style);
1253
//create a custom shape
1254
out.xml.startElement("draw:custom-shape");
1255
out.xml.addAttribute("draw:style-name", styleName);
1256
SetAnchorTypeAttribute(out);
1257
SetZIndexAttribute(out);
1259
QString height = QString::number(ds.dxHeightHR() / 1440.0f).append("in");
1260
out.xml.addAttribute("svg:height", height);
1262
QString width_str = QString::number(width * base_width / 100.0f).append("in");
1263
out.xml.addAttribute("svg:width", width_str);
1264
out.xml.addAttribute("svg:x", xPos);
1266
//--------------------
1267
out.xml.startElement("draw:enhanced-geometry");
1268
out.xml.addAttribute("svg:viewBox", "0 0 21600 21600");
1269
out.xml.addAttribute("draw:type", "rectangle");
1270
out.xml.addAttribute("draw:enhanced-path", "M 0 0 L 21600 0 21600 21600 0 21600 0 0 Z N");
1271
out.xml.endElement(); //enhanced-geometry
1272
out.xml.endElement(); //custom-shape
1275
void KWordGraphicsHandler::parseFloatingPictures(void)
1279
// WordDocument stream equals the Delay stream (DOC)
1280
LEInputStream* in = m_document->wdocument_stream();
1282
const OfficeArtBStoreContainer* blipStore = m_OfficeArtDggContainer.blipStore.data();
1284
for (int i = 0; i < blipStore->rgfb.size(); i++) {
1285
OfficeArtBStoreContainerFileBlock block = blipStore->rgfb[i];
1287
//we are looking for the missing content of OfficeArtFBSE
1288
if (block.anon.is<OfficeArtFBSE>()) {
1289
OfficeArtFBSE* fbse = block.anon.get<OfficeArtFBSE>();
1290
if (!fbse->embeddedBlip) {
1292
//NOTE: An foDelay value of 0xffffffff specifies that the
1293
//file is not in the delay stream and cRef must be zero.
1295
//NOTE: A cRef value of 0x00000000 specifies an empty slot
1296
//in the OfficeArtBStoreContainer.
1298
if (fbse->foDelay != 0xffffffff) {
1300
kDebug(30513) << "Strange, no references to this BLIP, skipping";
1303
LEInputStream::Mark _zero;
1304
_zero = in->setMark();
1305
in->skip(fbse->foDelay);
1307
//let's check the record header if there's a BLIP stored
1308
LEInputStream::Mark _m;
1310
OfficeArtRecordHeader rh;
1311
parseOfficeArtRecordHeader(*in, rh);
1313
if ( !(rh.recType >= 0xF018 && rh.recType <= 0xF117) ) {
1316
fbse->embeddedBlip = QSharedPointer<OfficeArtBlip>(new OfficeArtBlip(fbse));
1317
parseOfficeArtBlip(*in, *(fbse->embeddedBlip.data()));
1321
} //else there's an OfficeArtBlip inside
1327
QMap<QByteArray, QString>
1328
KWordGraphicsHandler::createFloatingPictures(KoStore* store, KoXmlWriter* manifest)
1330
PictureReference ref;
1331
QMap<QByteArray, QString> fileNames;
1333
const OfficeArtBStoreContainer* blipStore = m_OfficeArtDggContainer.blipStore.data();
1335
store->enterDirectory("Pictures");
1336
foreach (const OfficeArtBStoreContainerFileBlock& block, blipStore->rgfb) {
1337
ref = savePicture(block, store);
1338
if (ref.name.length() == 0) {
1339
kDebug(30513) << "Note: Empty picture reference, probably an empty slot";
1342
manifest->addManifestEntry("Pictures/" + ref.name, ref.mimetype);
1343
fileNames[ref.uid] = ref.name;
1345
store->leaveDirectory();
1350
QString KWordGraphicsHandler::getPicturePath(int pib) const
1355
// return 16 byte rgbuid for this given blip id
1356
const OfficeArtBStoreContainer* blipStore = m_OfficeArtDggContainer.blipStore.data();
1358
if ((n < blipStore->rgfb.size()) &&
1359
blipStore->rgfb[n].anon.is<MSO::OfficeArtFBSE>())
1361
rgbUid = blipStore->rgfb[n].anon.get<MSO::OfficeArtFBSE>()->rgbUid;
1364
kDebug(30513) << "Could not find image for pib " << pib;
1367
return rgbUid.length() ? "Pictures/" + m_picNames[rgbUid] : "";
757
1371
#include "graphicshandler.moc"