1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7
8 #include "slaoutput.h"
9
10 #include <poppler/GlobalParams.h>
11 #include <poppler/poppler-config.h>
12 #include <poppler/FileSpec.h>
13 #include <poppler/fofi/FoFiTrueType.h>
14 #include <QApplication>
15 #include <QFile>
16 #include "commonstrings.h"
17 #include "loadsaveplugin.h"
18 #include "sccolorengine.h"
19 #include "util.h"
20 #include "util_math.h"
21 #include <tiffio.h>
22
23 //#ifndef DEBUG_TEXT_IMPORT
24 // #define DEBUG_TEXT_IMPORT
25 //#endif
26
27 namespace
28 {
29 // Compute the intersection of two paths while considering the fillrule of each of them.
30 // QPainterPath has the right interface to do the operation but is currently buggy.
31 // See for example https://bugreports.qt.io/browse/QTBUG-83102. Thus this function
32 // applies some heuristics to find the best result. As soon QPainterPath is fixed
33 // one can just use a.intersected(b) wherever this function is called.
34 // TODO: Find an alternative to QPainterPath that works for different fill rules.
intersection(QPainterPath const & a,QPainterPath const & b)35 QPainterPath intersection(QPainterPath const &a, QPainterPath const &b)
36 {
37 // An empty path is treated like the whole area.
38 if (a.elementCount() == 0)
39 return b;
40 if (b.elementCount() == 0)
41 return a;
42
43 QPainterPath ret_a = a.intersected(b);
44 QPainterPath ret_b = b.intersected(a);
45 // Sometimes the resulting paths are not closed even though they should.
46 // Close them now.
47 ret_a.closeSubpath();
48 ret_b.closeSubpath();
49
50 // Most of the time one of the two operations returns an empty path while the other
51 // gives us the desired result. Return the non-empty one.
52 if (ret_a.elementCount() == 0)
53 return ret_b;
54 if (ret_b.elementCount() == 0)
55 return ret_a;
56
57 // There are cases where both intersections are not empty but one of them is quite
58 // complicated with several subpaths, etc. We return the simpler one.
59 return (ret_a.elementCount() <= ret_b.elementCount()) ? ret_a : ret_b;
60 }
61
62 // Invert preblending matte values into the color values. Assuming that c and alpha are RGBA components
63 // between 0 and 255.
unblendMatte(int c,int alpha,int matte)64 int unblendMatte(int c, int alpha, int matte)
65 {
66 if (alpha == 0)
67 return matte;
68 int ret = matte + ((c - matte) * 255) / alpha;
69 if (ret < 0)
70 return 0;
71 if (ret > 255)
72 return 255;
73 return ret;
74 }
75 }
76
LinkSubmitForm(Object * actionObj)77 LinkSubmitForm::LinkSubmitForm(Object *actionObj)
78 {
79 if (!actionObj->isDict())
80 return;
81
82 Object obj1 = actionObj->dictLookup("F");
83 if (!obj1.isNull())
84 {
85 if (obj1.isDict())
86 {
87 Object obj3 = obj1.dictLookup("FS");
88 if (!obj3.isNull())
89 {
90 if (obj3.isName())
91 {
92 POPPLER_CONST char *name = obj3.getName();
93 if (!strcmp(name, "URL"))
94 {
95 Object obj2 = obj1.dictLookup("F");
96 if (!obj2.isNull())
97 fileName = obj2.getString()->copy();
98 }
99 }
100 }
101 }
102 }
103 obj1 = actionObj->dictLookup("Flags");
104 if (!obj1.isNull())
105 {
106 if (obj1.isNum())
107 m_flags = obj1.getInt();
108 }
109 }
110
~LinkSubmitForm()111 LinkSubmitForm::~LinkSubmitForm()
112 {
113 delete fileName;
114 }
115
LinkImportData(Object * actionObj)116 LinkImportData::LinkImportData(Object *actionObj)
117 {
118 if (!actionObj->isDict())
119 return;
120 Object obj1 = actionObj->dictLookup("F");
121 if (obj1.isNull())
122 return;
123
124 Object obj3 = getFileSpecNameForPlatform(&obj1);
125 if (!obj3.isNull())
126 fileName = obj3.getString()->copy();
127 }
128
~LinkImportData()129 LinkImportData::~LinkImportData()
130 {
131 delete fileName;
132 }
133
~AnoOutputDev()134 AnoOutputDev::~AnoOutputDev()
135 {
136 delete fontName;
137 delete itemText;
138 }
139
AnoOutputDev(ScribusDoc * doc,QStringList * importedColors)140 AnoOutputDev::AnoOutputDev(ScribusDoc* doc, QStringList *importedColors)
141 {
142 m_doc = doc;
143 m_importedColors = importedColors;
144 currColorText = "Black";
145 currColorFill = CommonStrings::None;
146 currColorStroke = CommonStrings::None;
147 }
148
eoFill(GfxState * state)149 void AnoOutputDev::eoFill(GfxState *state)
150 {
151 int shade = 100;
152 currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &shade);
153 }
154
fill(GfxState * state)155 void AnoOutputDev::fill(GfxState *state)
156 {
157 int shade = 100;
158 currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &shade);
159 }
160
stroke(GfxState * state)161 void AnoOutputDev::stroke(GfxState *state)
162 {
163 int shade = 100;
164 currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &shade);
165 }
166
drawString(GfxState * state,POPPLER_CONST GooString * s)167 void AnoOutputDev::drawString(GfxState *state, POPPLER_CONST GooString *s)
168 {
169 int shade = 100;
170 currColorText = getColor(state->getFillColorSpace(), state->getFillColor(), &shade);
171 fontSize = state->getFontSize();
172 if (state->getFont())
173 fontName = state->getFont()->getName()->copy();
174 itemText = s->copy();
175 }
176
getColor(GfxColorSpace * color_space,POPPLER_CONST_070 GfxColor * color,int * shade)177 QString AnoOutputDev::getColor(GfxColorSpace *color_space, POPPLER_CONST_070 GfxColor *color, int *shade)
178 {
179 QString fNam;
180 QString namPrefix = "FromPDF";
181 ScColor tmp;
182 tmp.setSpotColor(false);
183 tmp.setRegistrationColor(false);
184 *shade = 100;
185 if ((color_space->getMode() == csDeviceRGB) || (color_space->getMode() == csCalRGB))
186 {
187 GfxRGB rgb;
188 color_space->getRGB(color, &rgb);
189 double Rc = colToDbl(rgb.r);
190 double Gc = colToDbl(rgb.g);
191 double Bc = colToDbl(rgb.b);
192 tmp.setRgbColorF(Rc, Gc, Bc);
193 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
194 }
195 else if (color_space->getMode() == csDeviceCMYK)
196 {
197 GfxCMYK cmyk;
198 color_space->getCMYK(color, &cmyk);
199 double Cc = colToDbl(cmyk.c);
200 double Mc = colToDbl(cmyk.m);
201 double Yc = colToDbl(cmyk.y);
202 double Kc = colToDbl(cmyk.k);
203 tmp.setCmykColorF(Cc, Mc, Yc, Kc);
204 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
205 }
206 else if ((color_space->getMode() == csCalGray) || (color_space->getMode() == csDeviceGray))
207 {
208 GfxGray gray;
209 color_space->getGray(color, &gray);
210 double Kc = 1.0 - colToDbl(gray);
211 tmp.setCmykColorF(0, 0, 0, Kc);
212 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
213 }
214 else if (color_space->getMode() == csSeparation)
215 {
216 GfxSeparationColorSpace* sepColorSpace = (GfxSeparationColorSpace*)color_space;
217 GfxColorSpace* altColorSpace = sepColorSpace->getAlt();
218 QString name = QString(sepColorSpace->getName()->getCString());
219 bool isRegistrationColor = (name == "All");
220 if (isRegistrationColor)
221 {
222 tmp.setCmykColorF(1.0, 1.0, 1.0, 1.0);
223 tmp.setRegistrationColor(true);
224 name = "Registration";
225 }
226 else if ((altColorSpace->getMode() == csDeviceRGB) || (altColorSpace->getMode() == csCalRGB))
227 {
228 double x = 1.0;
229 double comps[gfxColorMaxComps];
230 sepColorSpace->getFunc()->transform(&x, comps);
231 tmp.setRgbColorF(comps[0], comps[1], comps[2]);
232 }
233 else if ((altColorSpace->getMode() == csCalGray) || (altColorSpace->getMode() == csDeviceGray))
234 {
235 double x = 1.0;
236 double comps[gfxColorMaxComps];
237 sepColorSpace->getFunc()->transform(&x, comps);
238 tmp.setCmykColorF(0.0, 0.0, 0.0, 1.0 - comps[0]);
239 }
240 else if (altColorSpace->getMode() == csLab)
241 {
242 double x = 1.0;
243 double comps[gfxColorMaxComps];
244 sepColorSpace->getFunc()->transform(&x, comps);
245 tmp.setLabColor(comps[0], comps[1], comps[2]);
246 }
247 else
248 {
249 GfxCMYK cmyk;
250 color_space->getCMYK(color, &cmyk);
251 double Cc = colToDbl(cmyk.c);
252 double Mc = colToDbl(cmyk.m);
253 double Yc = colToDbl(cmyk.y);
254 double Kc = colToDbl(cmyk.k);
255 tmp.setCmykColorF(Cc, Mc, Yc, Kc);
256 }
257 tmp.setSpotColor(true);
258
259 fNam = m_doc->PageColors.tryAddColor(name, tmp);
260 *shade = qRound(colToDbl(color->c[0]) * 100);
261 }
262 else
263 {
264 GfxRGB rgb;
265 color_space->getRGB(color, &rgb);
266 double Rc = colToDbl(rgb.r);
267 double Gc = colToDbl(rgb.g);
268 double Bc = colToDbl(rgb.b);
269 tmp.setRgbColorF(Rc, Gc, Bc);
270 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
271 // qDebug() << "update fill color other colorspace" << color_space->getMode() << "treating as rgb" << Rc << Gc << Bc;
272 }
273 if (fNam == namPrefix+tmp.name())
274 m_importedColors->append(fNam);
275 return fNam;
276 }
277
SlaOutputDev(ScribusDoc * doc,QList<PageItem * > * Elements,QStringList * importedColors,int flags)278 SlaOutputDev::SlaOutputDev(ScribusDoc* doc, QList<PageItem*> *Elements, QStringList *importedColors, int flags)
279 {
280 m_doc = doc;
281 m_Elements = Elements;
282 pushGroup();
283 m_importedColors = importedColors;
284 m_currColorStroke = "Black";
285 m_currColorFill = "Black";
286 tmpSel = new Selection(m_doc, false);
287 importerFlags = flags;
288 currentLayer = m_doc->activeLayer();
289 layersSetByOCG = false;
290 }
291
~SlaOutputDev()292 SlaOutputDev::~SlaOutputDev()
293 {
294 m_groupStack.clear();
295 tmpSel->clear();
296 delete tmpSel;
297 delete m_fontEngine;
298 }
299
300 /* get Actions not implemented by Poppler */
SC_getAction(AnnotWidget * ano)301 LinkAction* SlaOutputDev::SC_getAction(AnnotWidget *ano)
302 {
303 LinkAction *linkAction = nullptr;
304 Object obj;
305 Ref refa = ano->getRef();
306
307 obj = xref->fetch(refa.num, refa.gen);
308 if (obj.isDict())
309 {
310 Dict* adic = obj.getDict();
311 POPPLER_CONST_075 Object POPPLER_REF additionalActions = adic->lookupNF("A");
312 Object additionalActionsObject = additionalActions.fetch(pdfDoc->getXRef());
313 if (additionalActionsObject.isDict())
314 {
315 Object actionObject = additionalActionsObject.dictLookup("S");
316 if (actionObject.isName("ImportData"))
317 {
318 linkAction = new LinkImportData(&additionalActionsObject);
319 }
320 else if (actionObject.isName("SubmitForm"))
321 {
322 linkAction = new LinkSubmitForm(&additionalActionsObject);
323 }
324 }
325 }
326 return linkAction;
327 }
328
329 /* Replacement for the crippled Poppler function LinkAction* AnnotWidget::getAdditionalAction(AdditionalActionsType type) */
330 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
SC_getAdditionalAction(const char * key,AnnotWidget * ano)331 std::unique_ptr<LinkAction> SlaOutputDev::SC_getAdditionalAction(const char *key, AnnotWidget *ano)
332 {
333 std::unique_ptr<LinkAction> linkAction;
334 #else
335 LinkAction* SlaOutputDev::SC_getAdditionalAction(const char *key, AnnotWidget *ano)
336 {
337 LinkAction *linkAction = nullptr;
338 #endif
339 Object obj;
340 Ref refa = ano->getRef();
341
342 obj = xref->fetch(refa.num, refa.gen);
343 if (obj.isDict())
344 {
345 Dict* adic = obj.getDict();
346 POPPLER_CONST_075 Object POPPLER_REF additionalActions = adic->lookupNF("AA");
347 Object additionalActionsObject = additionalActions.fetch(pdfDoc->getXRef());
348 if (additionalActionsObject.isDict())
349 {
350 Object actionObject = additionalActionsObject.dictLookup(key);
351 if (actionObject.isDict())
352 linkAction = LinkAction::parseAction(&actionObject, pdfDoc->getCatalog()->getBaseURI());
353 }
354 }
355 return linkAction;
356 }
357
358 GBool SlaOutputDev::annotations_callback(Annot *annota, void *user_data)
359 {
360 SlaOutputDev *dev = (SlaOutputDev*)user_data;
361 PDFRectangle *box = annota->getRect();
362 double xCoor = dev->m_doc->currentPage()->xOffset() + box->x1 - dev->cropOffsetX;
363 double yCoor = dev->m_doc->currentPage()->yOffset() + dev->m_doc->currentPage()->height() - box->y2 + dev->cropOffsetY;
364 double width = box->x2 - box->x1;
365 double height = box->y2 - box->y1;
366 if (dev->rotate == 90)
367 {
368 xCoor = dev->m_doc->currentPage()->xOffset() - dev->cropOffsetX + box->y2;
369 yCoor = dev->m_doc->currentPage()->yOffset() + dev->cropOffsetY + box->x1;
370 }
371 else if (dev->rotate == 180)
372 {
373 xCoor = dev->m_doc->currentPage()->xOffset() - dev->cropOffsetX + dev->m_doc->currentPage()->width() - box->x1;
374 yCoor = dev->m_doc->currentPage()->yOffset() + dev->cropOffsetY + box->y2;
375 }
376 else if (dev->rotate == 270)
377 {
378 xCoor = dev->m_doc->currentPage()->xOffset() - dev->cropOffsetX + dev->m_doc->currentPage()->width() - box->y2;
379 yCoor = dev->m_doc->currentPage()->yOffset() + dev->cropOffsetY + dev->m_doc->currentPage()->height() - box->x1;
380 }
381 bool retVal = true;
382 if (annota->getType() == Annot::typeText)
383 retVal = !dev->handleTextAnnot(annota, xCoor, yCoor, width, height);
384 else if (annota->getType() == Annot::typeLink)
385 retVal = !dev->handleLinkAnnot(annota, xCoor, yCoor, width, height);
386 else if (annota->getType() == Annot::typeWidget)
387 retVal = !dev->handleWidgetAnnot(annota, xCoor, yCoor, width, height);
388 return retVal;
389 }
390
391 bool SlaOutputDev::handleTextAnnot(Annot* annota, double xCoor, double yCoor, double width, double height)
392 {
393 AnnotText *anl = (AnnotText*)annota;
394 int z = m_doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, xCoor, yCoor, width, height, 0, CommonStrings::None, CommonStrings::None);
395 PageItem *ite = m_doc->Items->at(z);
396 int flg = annota->getFlags();
397 if (!(flg & 16))
398 ite->setRotation(rotate, true);
399 ite->ClipEdited = true;
400 ite->FrameType = 3;
401 ite->setFillEvenOdd(false);
402 ite->Clip = flattenPath(ite->PoLine, ite->Segments);
403 ite->ContourLine = ite->PoLine.copy();
404 ite->setTextFlowMode(PageItem::TextFlowDisabled);
405 m_Elements->append(ite);
406 if (m_groupStack.count() != 0)
407 {
408 m_groupStack.top().Items.append(ite);
409 applyMask(ite);
410 }
411 ite->setIsAnnotation(true);
412 ite->AutoName = false;
413 ite->annotation().setType(Annotation::Text);
414 ite->annotation().setActionType(Annotation::Action_None);
415 ite->annotation().setAnOpen(anl->getOpen());
416 QString iconName = UnicodeParsedString(anl->getIcon());
417 if (iconName == "Note")
418 ite->annotation().setIcon(Annotation::Icon_Note);
419 else if (iconName == "Comment")
420 ite->annotation().setIcon(Annotation::Icon_Comment);
421 else if (iconName == "Key")
422 ite->annotation().setIcon(Annotation::Icon_Key);
423 else if (iconName == "Help")
424 ite->annotation().setIcon(Annotation::Icon_Help);
425 else if (iconName == "NewParagraph")
426 ite->annotation().setIcon(Annotation::Icon_NewParagraph);
427 else if (iconName == "Paragraph")
428 ite->annotation().setIcon(Annotation::Icon_Paragraph);
429 else if (iconName == "Insert")
430 ite->annotation().setIcon(Annotation::Icon_Insert);
431 else if (iconName == "Cross")
432 ite->annotation().setIcon(Annotation::Icon_Cross);
433 else if (iconName == "Circle")
434 ite->annotation().setIcon(Annotation::Icon_Circle);
435 else
436 ite->annotation().setIcon(Annotation::Icon_Note);
437 ite->setItemName( CommonStrings::itemName_TextAnnotation + QString("%1").arg(m_doc->TotalItems));
438 ite->itemText.insertChars(UnicodeParsedString(annota->getContents()));
439 ite->itemText.trim();
440 return true;
441 }
442
443 bool SlaOutputDev::handleLinkAnnot(Annot* annota, double xCoor, double yCoor, double width, double height)
444 {
445 AnnotLink *anl = (AnnotLink*)annota;
446 LinkAction *act = anl->getAction();
447 if (!act)
448 return false;
449 bool validLink = false;
450 int pagNum = 0;
451 int xco = 0;
452 int yco = 0;
453 QString fileName = "";
454 if (act->getKind() == actionGoTo)
455 {
456 LinkGoTo *gto = (LinkGoTo*) act;
457 POPPLER_CONST LinkDest *dst = gto->getDest();
458 if (dst)
459 {
460 if (dst->getKind() == destXYZ)
461 {
462 if (dst->isPageRef())
463 {
464 Ref dstr = dst->getPageRef();
465 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
466 pagNum = pdfDoc->findPage(dstr);
467 #else
468 pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
469 #endif
470 }
471 else
472 pagNum = dst->getPageNum();
473 xco = dst->getLeft();
474 yco = dst->getTop();
475 validLink = true;
476 }
477 }
478 else
479 {
480 POPPLER_CONST GooString *ndst = gto->getNamedDest();
481 if (ndst)
482 {
483 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
484 std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
485 #else
486 LinkDest *dstn = pdfDoc->findDest(ndst);
487 #endif
488 if (dstn)
489 {
490 if (dstn->getKind() == destXYZ)
491 {
492 if (dstn->isPageRef())
493 {
494 Ref dstr = dstn->getPageRef();
495 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
496 pagNum = pdfDoc->findPage(dstr);
497 #else
498 pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
499 #endif
500 }
501 else
502 pagNum = dstn->getPageNum();
503 xco = dstn->getLeft();
504 yco = dstn->getTop();
505 validLink = true;
506 }
507 }
508 }
509 }
510 }
511 else if (act->getKind() == actionGoToR)
512 {
513 LinkGoToR *gto = (LinkGoToR*)act;
514 fileName = UnicodeParsedString(gto->getFileName());
515 POPPLER_CONST LinkDest *dst = gto->getDest();
516 if (dst)
517 {
518 if (dst->getKind() == destXYZ)
519 {
520 pagNum = dst->getPageNum();
521 xco = dst->getLeft();
522 yco = dst->getTop();
523 validLink = true;
524 }
525 }
526 else
527 {
528 POPPLER_CONST GooString *ndst = gto->getNamedDest();
529 if (ndst)
530 {
531 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
532 std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
533 #else
534 LinkDest *dstn = pdfDoc->findDest(ndst);
535 #endif
536 if (dstn)
537 {
538 if (dstn->getKind() == destXYZ)
539 {
540 pagNum = dstn->getPageNum();
541 xco = dstn->getLeft();
542 yco = dstn->getTop();
543 validLink = true;
544 }
545 }
546 }
547 }
548 }
549 else if (act->getKind() == actionURI)
550 {
551 LinkURI *gto = (LinkURI*)act;
552 validLink = true;
553 fileName = UnicodeParsedString(gto->getURI());
554 }
555 if (validLink)
556 {
557 int z = m_doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, xCoor, yCoor, width, height, 0, CommonStrings::None, CommonStrings::None);
558 PageItem *ite = m_doc->Items->at(z);
559 int flg = annota->getFlags();
560 if (!(flg & 16))
561 ite->setRotation(rotate, true);
562 ite->ClipEdited = true;
563 ite->FrameType = 3;
564 ite->setFillEvenOdd(false);
565 ite->Clip = flattenPath(ite->PoLine, ite->Segments);
566 ite->ContourLine = ite->PoLine.copy();
567 ite->setTextFlowMode(PageItem::TextFlowDisabled);
568 m_Elements->append(ite);
569 if (m_groupStack.count() != 0)
570 {
571 m_groupStack.top().Items.append(ite);
572 applyMask(ite);
573 }
574 ite->setIsAnnotation(true);
575 ite->AutoName = false;
576 if (act->getKind() == actionGoTo)
577 {
578 ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
579 ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
580 ite->annotation().setActionType(2);
581 }
582 else if (act->getKind() == actionGoToR)
583 {
584 ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
585 ite->annotation().setExtern(fileName);
586 ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
587 ite->annotation().setActionType(9);
588 }
589 else if (act->getKind() == actionURI)
590 {
591 ite->annotation().setAction("");
592 ite->annotation().setExtern(fileName);
593 ite->annotation().setActionType(8);
594 }
595 ite->annotation().setType(Annotation::Link);
596 ite->setItemName( CommonStrings::itemName_LinkAnnotation + QString("%1").arg(m_doc->TotalItems));
597 }
598 return validLink;
599 }
600
601 bool SlaOutputDev::handleWidgetAnnot(Annot* annota, double xCoor, double yCoor, double width, double height)
602 {
603 bool retVal = false;
604 bool found = false;
605
606 if (!m_formWidgets)
607 return false;
608
609 int formcount = m_formWidgets->getNumWidgets();
610 for (int i = 0; i < formcount; ++i)
611 {
612 FormWidget *fm = m_formWidgets->getWidget(i);
613 if (!fm)
614 continue;
615 AnnotWidget *ano = fm->getWidgetAnnotation();
616 if (!ano)
617 continue;
618 if (ano != (AnnotWidget*) annota)
619 continue;
620 found = true;
621 int wtyp = -1;
622 if (fm->getType() == formButton)
623 {
624 FormWidgetButton *btn = (FormWidgetButton*)fm;
625 if (btn)
626 {
627 if (btn->getButtonType() == formButtonCheck)
628 {
629 wtyp = Annotation::Checkbox;
630 retVal = true;
631 }
632 else if (btn->getButtonType() == formButtonPush)
633 {
634 wtyp = Annotation::Button;
635 retVal = true;
636 }
637 else if (btn->getButtonType() == formButtonRadio)
638 {
639 wtyp = Annotation::RadioButton;
640 retVal = true;
641 }
642 }
643 }
644 else if (fm->getType() == formText)
645 {
646 wtyp = Annotation::Textfield;
647 retVal = true;
648 }
649 else if (fm->getType() == formChoice)
650 {
651 FormWidgetChoice *btn = (FormWidgetChoice*)fm;
652 if (btn)
653 {
654 if (btn->isCombo())
655 {
656 wtyp = Annotation::Combobox;
657 retVal = true;
658 }
659 else if (btn->isListBox())
660 {
661 wtyp = Annotation::Listbox;
662 retVal = true;
663 }
664 }
665 }
666 if (retVal)
667 {
668 AnnotAppearanceCharacs *achar = ano->getAppearCharacs();
669 bool fgFound = false;
670 bool bgFound = false;
671 if (achar)
672 {
673 POPPLER_CONST AnnotColor *bgCol = achar->getBackColor();
674 if (bgCol)
675 {
676 bgFound = true;
677 m_currColorFill = getAnnotationColor(bgCol);
678 }
679 else
680 m_currColorFill = CommonStrings::None;
681 POPPLER_CONST AnnotColor *fgCol = achar->getBorderColor();
682 if (fgCol)
683 {
684 fgFound = true;
685 m_currColorStroke = getAnnotationColor(fgCol);
686 }
687 else
688 {
689 fgCol = achar->getBackColor();
690 if (fgCol)
691 m_currColorStroke = getAnnotationColor(fgCol);
692 else
693 m_currColorStroke = CommonStrings::None;
694 }
695 }
696 QString m_currColorText = "Black";
697 double fontSize = 12;
698 QString fontName = "";
699 QString itemText = "";
700 AnnotAppearance *apa = annota->getAppearStreams();
701 if (apa || !achar)
702 {
703 AnoOutputDev *annotOutDev = new AnoOutputDev(m_doc, m_importedColors);
704 Gfx *gfx = new Gfx(pdfDoc, annotOutDev, pdfDoc->getPage(m_actPage)->getResourceDict(), annota->getRect(), nullptr);
705 ano->draw(gfx, false);
706 if (!bgFound)
707 m_currColorFill = annotOutDev->currColorFill;
708 if (!fgFound)
709 m_currColorStroke = annotOutDev->currColorStroke;
710 m_currColorText = annotOutDev->currColorText;
711 fontSize = annotOutDev->fontSize;
712 fontName = UnicodeParsedString(annotOutDev->fontName);
713 itemText = UnicodeParsedString(annotOutDev->itemText);
714 delete gfx;
715 delete annotOutDev;
716 }
717 int z = m_doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, xCoor, yCoor, width, height, 0, m_currColorFill, CommonStrings::None);
718 PageItem *ite = m_doc->Items->at(z);
719 int flg = annota->getFlags();
720 if (!(flg & 16))
721 ite->setRotation(rotate, true);
722 ite->ClipEdited = true;
723 ite->FrameType = 3;
724 ite->setFillEvenOdd(false);
725 ite->Clip = flattenPath(ite->PoLine, ite->Segments);
726 ite->ContourLine = ite->PoLine.copy();
727 ite->setTextFlowMode(PageItem::TextFlowDisabled);
728 m_Elements->append(ite);
729 if (m_groupStack.count() != 0)
730 {
731 m_groupStack.top().Items.append(ite);
732 applyMask(ite);
733 }
734 ite->setIsAnnotation(true);
735 ite->AutoName = false;
736 AnnotBorder *brd = annota->getBorder();
737 if (brd)
738 {
739 int bsty = brd->getStyle();
740 if (bsty == AnnotBorder::borderDashed)
741 bsty = 1;
742 else if (bsty == AnnotBorder::borderBeveled)
743 bsty = 3;
744 else if (bsty == AnnotBorder::borderInset)
745 bsty = 4;
746 else if (bsty == AnnotBorder::borderUnderlined)
747 bsty = 2;
748 ite->annotation().setBorderStyle(bsty);
749 ite->annotation().setBorderColor(m_currColorStroke);
750 ite->annotation().setBorderWidth(qRound(brd->getWidth()));
751 }
752 else
753 {
754 ite->annotation().setBorderStyle(0);
755 ite->annotation().setBorderColor(CommonStrings::None);
756 ite->annotation().setBorderWidth(0);
757 }
758 QString tmTxt = "";
759 tmTxt = UnicodeParsedString(fm->getPartialName());
760 if (!tmTxt.isEmpty())
761 ite->setItemName(tmTxt);
762 tmTxt = "";
763 tmTxt = UnicodeParsedString(fm->getAlternateUiName());
764 if (!tmTxt.isEmpty())
765 ite->annotation().setToolTip(tmTxt);
766 tmTxt = "";
767 if (achar)
768 {
769 tmTxt = UnicodeParsedString(achar->getRolloverCaption());
770 if (!tmTxt.isEmpty())
771 ite->annotation().setRollOver(tmTxt);
772 tmTxt = "";
773 tmTxt = UnicodeParsedString(achar->getAlternateCaption());
774 if (!tmTxt.isEmpty())
775 ite->annotation().setDown(tmTxt);
776 }
777 ite->annotation().setType(wtyp);
778 ite->annotation().setFlag(0);
779 if (flg & 2)
780 ite->annotation().setVis(1);
781 if (flg & 32)
782 ite->annotation().setVis(3);
783 if (wtyp == Annotation::Button)
784 {
785 ite->setFillColor(m_currColorFill);
786 if (achar)
787 ite->itemText.insertChars(UnicodeParsedString(achar->getNormalCaption()));
788 else
789 ite->itemText.insertChars(itemText);
790 applyTextStyle(ite, fontName, m_currColorText, fontSize);
791 ite->annotation().addToFlag(Annotation::Flag_PushButton);
792 FormWidgetButton *btn = (FormWidgetButton*)fm;
793 if (!btn->isReadOnly())
794 ite->annotation().addToFlag(Annotation::Flag_Edit);
795 handleActions(ite, ano);
796 }
797 else if (wtyp == Annotation::Textfield)
798 {
799 FormWidgetText *btn = (FormWidgetText*)fm;
800 if (btn)
801 {
802 ite->itemText.insertChars(UnicodeParsedString(btn->getContent()));
803 applyTextStyle(ite, fontName, m_currColorText, fontSize);
804 ite->itemText.trim();
805 if (btn->isMultiline())
806 ite->annotation().addToFlag(Annotation::Flag_Multiline);
807 if (btn->isPassword())
808 ite->annotation().addToFlag(Annotation::Flag_Password);
809 if (btn->noSpellCheck())
810 ite->annotation().addToFlag(Annotation::Flag_DoNotSpellCheck);
811 if (btn->noScroll())
812 ite->annotation().addToFlag(Annotation::Flag_DoNotScroll);
813 int mxLen = btn->getMaxLen();
814 if (mxLen > 0)
815 ite->annotation().setMaxChar(mxLen);
816 else
817 ite->annotation().setMaxChar(-1);
818 if (!btn->isReadOnly())
819 ite->annotation().addToFlag(Annotation::Flag_Edit);
820 handleActions(ite, ano);
821 }
822 }
823 else if (wtyp == Annotation::Checkbox)
824 {
825 FormWidgetButton *btn = (FormWidgetButton*)fm;
826 if (btn)
827 {
828 ite->annotation().setIsChk(btn->getState());
829 ite->annotation().setCheckState(ite->annotation().IsChk());
830 handleActions(ite, ano);
831 if (itemText == "4")
832 ite->annotation().setChkStil(0);
833 else if (itemText == "5")
834 ite->annotation().setChkStil(1);
835 else if (itemText == "F")
836 ite->annotation().setChkStil(2);
837 else if (itemText == "l")
838 ite->annotation().setChkStil(3);
839 else if (itemText == "H")
840 ite->annotation().setChkStil(4);
841 else if (itemText == "n")
842 ite->annotation().setChkStil(5);
843 else
844 ite->annotation().setChkStil(0);
845 if (!btn->isReadOnly())
846 ite->annotation().addToFlag(Annotation::Flag_Edit);
847 }
848 }
849 else if ((wtyp == Annotation::Combobox) || (wtyp == Annotation::Listbox))
850 {
851 FormWidgetChoice *btn = (FormWidgetChoice*)fm;
852 if (btn)
853 {
854 if (wtyp == 5)
855 ite->annotation().addToFlag(Annotation::Flag_Combo);
856 int co = btn->getNumChoices();
857 if (co > 0)
858 {
859 QString inh = UnicodeParsedString(btn->getChoice(0));
860 for (int a = 1; a < co; a++)
861 {
862 inh += "\n" + UnicodeParsedString(btn->getChoice(a));
863 }
864 ite->itemText.insertChars(inh);
865 }
866 applyTextStyle(ite, fontName, m_currColorText, fontSize);
867 if (!btn->isReadOnly())
868 ite->annotation().addToFlag(Annotation::Flag_Edit);
869 handleActions(ite, ano);
870 }
871 }
872 else if (wtyp == Annotation::RadioButton)
873 {
874 FormWidgetButton *btn = (FormWidgetButton*)fm;
875 if (btn)
876 {
877 ite->setItemName( CommonStrings::itemName_RadioButton + QString("%1").arg(m_doc->TotalItems));
878 ite->annotation().setIsChk(btn->getState());
879 ite->annotation().setCheckState(ite->annotation().IsChk());
880 handleActions(ite, ano);
881 m_radioButtons.insert(annota->getRef().num, ite);
882 }
883 }
884 }
885 break;
886 }
887 if (!found)
888 {
889 Object obj1;
890 Ref refa = annota->getRef();
891 obj1 = xref->fetch(refa.num, refa.gen);
892 if (obj1.isDict())
893 {
894 Dict* dict = obj1.getDict();
895 Object obj2 = dict->lookup("Kids");
896 //childs
897 if (obj2.isArray())
898 {
899 // Load children
900 QList<int> radList;
901 for (int i = 0; i < obj2.arrayGetLength(); i++)
902 {
903 POPPLER_CONST_075 Object POPPLER_REF childRef = obj2.arrayGetNF(i);
904 if (!childRef.isRef())
905 continue;
906 Object childObj = obj2.arrayGet(i);
907 if (!childObj.isDict())
908 continue;
909 const Ref ref = childRef.getRef();
910 radList.append(ref.num);
911 }
912 QString tmTxt = UnicodeParsedString(annota->getName());
913 m_radioMap.insert(tmTxt, radList);
914 }
915 }
916 }
917 return retVal;
918 }
919
920 void SlaOutputDev::applyTextStyle(PageItem* ite, const QString& fontName, const QString& textColor, double fontSize)
921 {
922 CharStyle newStyle;
923 newStyle.setFillColor(textColor);
924 newStyle.setFontSize(fontSize * 10);
925 if (!fontName.isEmpty())
926 {
927 SCFontsIterator it(*m_doc->AllFonts);
928 for ( ; it.hasNext() ; it.next())
929 {
930 ScFace& face(it.current());
931 if ((face.psName() == fontName) && (face.usable()) && (face.type() == ScFace::TTF))
932 {
933 newStyle.setFont(face);
934 break;
935 }
936 if ((face.family() == fontName) && (face.usable()) && (face.type() == ScFace::TTF))
937 {
938 newStyle.setFont(face);
939 break;
940 }
941 if ((face.scName() == fontName) && (face.usable()) && (face.type() == ScFace::TTF))
942 {
943 newStyle.setFont(face);
944 break;
945 }
946 }
947 }
948 ParagraphStyle dstyle(ite->itemText.defaultStyle());
949 dstyle.charStyle().applyCharStyle(newStyle);
950 ite->itemText.setDefaultStyle(dstyle);
951 ite->itemText.applyCharStyle(0, ite->itemText.length(), newStyle);
952 ite->invalid = true;
953 }
954
955 void SlaOutputDev::handleActions(PageItem* ite, AnnotWidget *ano)
956 {
957 LinkAction *Lact = ano->getAction();
958 if (Lact)
959 {
960 if (Lact->getKind() == actionJavaScript)
961 {
962 LinkJavaScript *jsa = (LinkJavaScript*)Lact;
963 if (jsa->isOk())
964 {
965 ite->annotation().setActionType(1);
966 ite->annotation().setAction(UnicodeParsedString(jsa->getScript()));
967 }
968 }
969 else if (Lact->getKind() == actionGoTo)
970 {
971 int pagNum = 0;
972 int xco = 0;
973 int yco = 0;
974 LinkGoTo *gto = (LinkGoTo*)Lact;
975 POPPLER_CONST LinkDest *dst = gto->getDest();
976 if (dst)
977 {
978 if (dst->getKind() == destXYZ)
979 {
980 if (dst->isPageRef())
981 {
982 Ref dstr = dst->getPageRef();
983 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
984 pagNum = pdfDoc->findPage(dstr);
985 #else
986 pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
987 #endif
988 }
989 else
990 pagNum = dst->getPageNum();
991 xco = dst->getLeft();
992 yco = dst->getTop();
993 ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
994 ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
995 ite->annotation().setActionType(2);
996 }
997 }
998 else
999 {
1000 POPPLER_CONST GooString *ndst = gto->getNamedDest();
1001 if (ndst)
1002 {
1003 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1004 std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
1005 #else
1006 LinkDest *dstn = pdfDoc->findDest(ndst);
1007 #endif
1008 if (dstn)
1009 {
1010 if (dstn->getKind() == destXYZ)
1011 {
1012 if (dstn->isPageRef())
1013 {
1014 Ref dstr = dstn->getPageRef();
1015 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
1016 pagNum = pdfDoc->findPage(dstr);
1017 #else
1018 pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
1019 #endif
1020 }
1021 else
1022 pagNum = dstn->getPageNum();
1023 xco = dstn->getLeft();
1024 yco = dstn->getTop();
1025 ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
1026 ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
1027 ite->annotation().setActionType(2);
1028 }
1029 }
1030 }
1031 }
1032 }
1033 else if (Lact->getKind() == actionGoToR)
1034 {
1035 int pagNum = 0;
1036 int xco = 0;
1037 int yco = 0;
1038 LinkGoToR *gto = (LinkGoToR*)Lact;
1039 QString fileName = UnicodeParsedString(gto->getFileName());
1040 POPPLER_CONST LinkDest *dst = gto->getDest();
1041 if (dst)
1042 {
1043 if (dst->getKind() == destXYZ)
1044 {
1045 pagNum = dst->getPageNum();
1046 xco = dst->getLeft();
1047 yco = dst->getTop();
1048 ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
1049 ite->annotation().setExtern(fileName);
1050 ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
1051 ite->annotation().setActionType(9);
1052 }
1053 }
1054 else
1055 {
1056 POPPLER_CONST GooString *ndst = gto->getNamedDest();
1057 if (ndst)
1058 {
1059 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1060 std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
1061 #else
1062 LinkDest *dstn = pdfDoc->findDest(ndst);
1063 #endif
1064 if (dstn)
1065 {
1066 if (dstn->getKind() == destXYZ)
1067 {
1068 pagNum = dstn->getPageNum();
1069 xco = dstn->getLeft();
1070 yco = dstn->getTop();
1071 ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
1072 ite->annotation().setExtern(fileName);
1073 ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
1074 ite->annotation().setActionType(9);
1075 }
1076 }
1077 }
1078 }
1079 }
1080 else if (Lact->getKind() == actionUnknown)
1081 {
1082 LinkUnknown *uno = (LinkUnknown*)Lact;
1083 QString actString = UnicodeParsedString(uno->getAction());
1084 if (actString == "ResetForm")
1085 {
1086 ite->annotation().setActionType(4);
1087 }
1088 else
1089 {
1090 LinkAction* scact = SC_getAction(ano);
1091 if (scact)
1092 {
1093 if (actString == "ImportData")
1094 {
1095 LinkImportData *impo = (LinkImportData*)scact;
1096 if (impo->isOk())
1097 {
1098 ite->annotation().setActionType(5);
1099 ite->annotation().setAction(UnicodeParsedString(impo->getFileName()));
1100 }
1101 }
1102 else if (actString == "SubmitForm")
1103 {
1104 LinkSubmitForm *impo = (LinkSubmitForm*)scact;
1105 if (impo->isOk())
1106 {
1107 ite->annotation().setActionType(3);
1108 ite->annotation().setAction(UnicodeParsedString(impo->getFileName()));
1109 int fl = impo->getFlags();
1110 if (fl == 0)
1111 ite->annotation().setHTML(0);
1112 else if (fl == 4)
1113 ite->annotation().setHTML(1);
1114 else if (fl == 64)
1115 ite->annotation().setHTML(2);
1116 else if (fl == 512)
1117 ite->annotation().setHTML(3);
1118 }
1119 }
1120 }
1121 }
1122 }
1123 else if (Lact->getKind() == actionNamed)
1124 {
1125 LinkNamed *uno = (LinkNamed*)Lact;
1126 ite->annotation().setActionType(10);
1127 ite->annotation().setAction(UnicodeParsedString(uno->getName()));
1128 }
1129 else
1130 qDebug() << "Found unsupported Action of type" << Lact->getKind();
1131 }
1132 auto Aact = SC_getAdditionalAction("D", ano);
1133 if (Aact)
1134 {
1135 if (Aact->getKind() == actionJavaScript)
1136 {
1137 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1138 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1139 #else
1140 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1141 #endif
1142 if (jsa->isOk())
1143 {
1144 ite->annotation().setD_act(UnicodeParsedString(jsa->getScript()));
1145 ite->annotation().setAAact(true);
1146 }
1147 }
1148 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1149 Aact.reset();
1150 #else
1151 Aact = nullptr;
1152 #endif
1153 }
1154 Aact = SC_getAdditionalAction("E", ano);
1155 if (Aact)
1156 {
1157 if (Aact->getKind() == actionJavaScript)
1158 {
1159 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1160 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1161 #else
1162 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1163 #endif
1164 if (jsa->isOk())
1165 {
1166 ite->annotation().setE_act(UnicodeParsedString(jsa->getScript()));
1167 ite->annotation().setAAact(true);
1168 }
1169 }
1170 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1171 Aact.reset();
1172 #else
1173 Aact = nullptr;
1174 #endif
1175 }
1176 Aact = SC_getAdditionalAction("X", ano);
1177 if (Aact)
1178 {
1179 if (Aact->getKind() == actionJavaScript)
1180 {
1181 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1182 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1183 #else
1184 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1185 #endif
1186 if (jsa->isOk())
1187 {
1188 ite->annotation().setX_act(UnicodeParsedString(jsa->getScript()));
1189 ite->annotation().setAAact(true);
1190 }
1191 }
1192 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1193 Aact.reset();
1194 #else
1195 Aact = nullptr;
1196 #endif
1197 }
1198 Aact = SC_getAdditionalAction("Fo", ano);
1199 if (Aact)
1200 {
1201 if (Aact->getKind() == actionJavaScript)
1202 {
1203 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1204 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1205 #else
1206 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1207 #endif
1208 if (jsa->isOk())
1209 {
1210 ite->annotation().setFo_act(UnicodeParsedString(jsa->getScript()));
1211 ite->annotation().setAAact(true);
1212 }
1213 }
1214 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1215 Aact.reset();
1216 #else
1217 Aact = nullptr;
1218 #endif
1219 }
1220 Aact = SC_getAdditionalAction("Bl", ano);
1221 if (Aact)
1222 {
1223 if (Aact->getKind() == actionJavaScript)
1224 {
1225 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1226 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1227 #else
1228 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1229 #endif
1230 if (jsa->isOk())
1231 {
1232 ite->annotation().setBl_act(UnicodeParsedString(jsa->getScript()));
1233 ite->annotation().setAAact(true);
1234 }
1235 }
1236 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1237 Aact.reset();
1238 #else
1239 Aact = nullptr;
1240 #endif
1241 }
1242 Aact = SC_getAdditionalAction("C", ano);
1243 if (Aact)
1244 {
1245 if (Aact->getKind() == actionJavaScript)
1246 {
1247 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1248 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1249 #else
1250 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1251 #endif
1252 if (jsa->isOk())
1253 {
1254 ite->annotation().setC_act(UnicodeParsedString(jsa->getScript()));
1255 ite->annotation().setAAact(true);
1256 }
1257 }
1258 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1259 Aact.reset();
1260 #else
1261 Aact = nullptr;
1262 #endif
1263 }
1264 Aact = SC_getAdditionalAction("F", ano);
1265 if (Aact)
1266 {
1267 if (Aact->getKind() == actionJavaScript)
1268 {
1269 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1270 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1271 #else
1272 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1273 #endif
1274 if (jsa->isOk())
1275 {
1276 ite->annotation().setF_act(UnicodeParsedString(jsa->getScript()));
1277 ite->annotation().setAAact(true);
1278 ite->annotation().setFormat(5);
1279 }
1280 }
1281 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1282 Aact.reset();
1283 #else
1284 Aact = nullptr;
1285 #endif
1286 }
1287 Aact = SC_getAdditionalAction("K", ano);
1288 if (Aact)
1289 {
1290 if (Aact->getKind() == actionJavaScript)
1291 {
1292 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1293 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1294 #else
1295 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1296 #endif
1297 if (jsa->isOk())
1298 {
1299 ite->annotation().setK_act(UnicodeParsedString(jsa->getScript()));
1300 ite->annotation().setAAact(true);
1301 ite->annotation().setFormat(5);
1302 }
1303 }
1304 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1305 Aact.reset();
1306 #else
1307 Aact = nullptr;
1308 #endif
1309 }
1310 Aact = SC_getAdditionalAction("V", ano);
1311 if (Aact)
1312 {
1313 if (Aact->getKind() == actionJavaScript)
1314 {
1315 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1316 LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
1317 #else
1318 LinkJavaScript *jsa = (LinkJavaScript*) Aact;
1319 #endif
1320 if (jsa->isOk())
1321 {
1322 ite->annotation().setV_act(UnicodeParsedString(jsa->getScript()));
1323 ite->annotation().setAAact(true);
1324 }
1325 }
1326 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
1327 Aact.reset();
1328 #else
1329 Aact = nullptr;
1330 #endif
1331 }
1332 }
1333
1334 void SlaOutputDev::startDoc(PDFDoc *doc, XRef *xrefA, Catalog *catA)
1335 {
1336 xref = xrefA;
1337 catalog = catA;
1338 pdfDoc = doc;
1339 updateGUICounter = 0;
1340 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 84, 0)
1341 m_fontEngine = new SplashFontEngine(true, false, false, true);
1342 #else
1343 m_fontEngine = new SplashFontEngine(globalParams->getEnableFreeType(), false, false, true);
1344 #endif
1345 }
1346
1347 void SlaOutputDev::startPage(int pageNum, GfxState *, XRef *)
1348 {
1349 m_formWidgets = pdfDoc->getPage(pageNum)->getFormWidgets();
1350 m_radioMap.clear();
1351 m_radioButtons.clear();
1352 m_actPage = pageNum;
1353 m_groupStack.clear();
1354 pushGroup();
1355 m_currentClipPath = QPainterPath();
1356 m_clipPaths.clear();
1357 }
1358
1359 void SlaOutputDev::endPage()
1360 {
1361 if (!m_radioMap.isEmpty())
1362 {
1363 for (auto it = m_radioMap.begin(); it != m_radioMap.end(); ++it)
1364 {
1365 tmpSel->clear();
1366 QList<int> refList = it.value();
1367 for (int a = 0; a < refList.count(); a++)
1368 {
1369 if (m_radioButtons.contains(refList[a]))
1370 {
1371 tmpSel->addItem(m_radioButtons[refList[a]], true);
1372 m_Elements->removeAll(m_radioButtons[refList[a]]);
1373 }
1374 }
1375 if (!tmpSel->isEmpty())
1376 {
1377 PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
1378 ite->setItemName(it.key());
1379 m_Elements->append(ite);
1380 if (m_groupStack.count() != 0)
1381 m_groupStack.top().Items.append(ite);
1382 }
1383 }
1384 }
1385 m_radioMap.clear();
1386 m_radioButtons.clear();
1387 // qDebug() << "ending page";
1388 }
1389
1390 void SlaOutputDev::saveState(GfxState *state)
1391 {
1392 m_clipPaths.push(m_currentClipPath);
1393 pushGroup();
1394 }
1395
1396 void SlaOutputDev::restoreState(GfxState *state)
1397 {
1398 if (m_groupStack.count() != 0)
1399 {
1400 groupEntry gElements = m_groupStack.pop();
1401 if (gElements.Items.count() > 0)
1402 {
1403 if ((gElements.Items.count() > 1) && (checkClip()))
1404 {
1405 tmpSel->clear();
1406 for (int dre = 0; dre < gElements.Items.count(); ++dre)
1407 {
1408 tmpSel->addItem(gElements.Items.at(dre), true);
1409 m_Elements->removeAll(gElements.Items.at(dre));
1410 }
1411 PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
1412 if (ite)
1413 {
1414 QPainterPath clippath = m_currentClipPath;
1415 clippath.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
1416 clippath.translate(-ite->xPos(), -ite->yPos());
1417 ite->PoLine.fromQPainterPath(clippath, true);
1418 ite->ClipEdited = true;
1419 ite->FrameType = 3;
1420 ite->setTextFlowMode(PageItem::TextFlowDisabled);
1421 // Comment out temporarily, there are some bad interactions between adjustItemSize() and
1422 // resizeGroupToContents() since fixing resizing of multiple selections
1423 //m_doc->adjustItemSize(ite, true);
1424 m_doc->resizeGroupToContents(ite);
1425 ite->OldB2 = ite->width();
1426 ite->OldH2 = ite->height();
1427 m_Elements->append(ite);
1428 if (m_groupStack.count() != 0)
1429 {
1430 applyMask(ite);
1431 m_groupStack.top().Items.append(ite);
1432 }
1433 }
1434 else
1435 {
1436 if (m_groupStack.count() != 0)
1437 {
1438 for (int dre = 0; dre < gElements.Items.count(); ++dre)
1439 {
1440 PageItem *ite = gElements.Items.at(dre);
1441 applyMask(ite);
1442 m_groupStack.top().Items.append(ite);
1443 }
1444 }
1445 }
1446 tmpSel->clear();
1447 }
1448 else
1449 {
1450 if (m_groupStack.count() != 0)
1451 {
1452 for (int dre = 0; dre < gElements.Items.count(); ++dre)
1453 {
1454 PageItem *ite = gElements.Items.at(dre);
1455 applyMask(ite);
1456 m_groupStack.top().Items.append(ite);
1457 }
1458 }
1459 }
1460 }
1461 }
1462 if (m_clipPaths.count() != 0)
1463 m_currentClipPath = m_clipPaths.pop();
1464 }
1465
1466 void SlaOutputDev::beginTransparencyGroup(GfxState *state, POPPLER_CONST_070 double *bbox, GfxColorSpace * /*blendingColorSpace*/, GBool isolated, GBool knockout, GBool forSoftMask)
1467 {
1468 // qDebug() << "SlaOutputDev::beginTransparencyGroup isolated:" << isolated << "knockout:" << knockout << "forSoftMask:" << forSoftMask;
1469 pushGroup("", forSoftMask);
1470 m_groupStack.top().isolated = isolated;
1471 }
1472
1473 void SlaOutputDev::paintTransparencyGroup(GfxState *state, POPPLER_CONST_070 double *bbox)
1474 {
1475 // qDebug() << "SlaOutputDev::paintTransparencyGroup";
1476 if (m_groupStack.count() != 0)
1477 {
1478 if ((m_groupStack.top().Items.count() != 0) && (!m_groupStack.top().forSoftMask))
1479 {
1480 PageItem *ite = m_groupStack.top().Items.last();
1481 ite->setFillTransparency(1.0 - state->getFillOpacity());
1482 ite->setFillBlendmode(getBlendMode(state));
1483 }
1484 }
1485 }
1486
1487 void SlaOutputDev::endTransparencyGroup(GfxState *state)
1488 {
1489 // qDebug() << "SlaOutputDev::endTransparencyGroup";
1490 if (m_groupStack.count() <= 0)
1491 return;
1492
1493 tmpSel->clear();
1494
1495 groupEntry gElements = m_groupStack.pop();
1496 if (gElements.Items.count() <= 0)
1497 return;
1498
1499 if (gElements.forSoftMask)
1500 {
1501 for (int dre = 0; dre < gElements.Items.count(); ++dre)
1502 {
1503 tmpSel->addItem(gElements.Items.at(dre), true);
1504 m_Elements->removeAll(gElements.Items.at(dre));
1505 }
1506 PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
1507 ite->setFillTransparency(1.0 - state->getFillOpacity());
1508 ite->setFillBlendmode(getBlendMode(state));
1509 ScPattern pat = ScPattern();
1510 pat.setDoc(m_doc);
1511 m_doc->DoDrawing = true;
1512 pat.pattern = ite->DrawObj_toImage(qMin(qMax(ite->width(), ite->height()), 500.0));
1513 pat.xoffset = 0;
1514 pat.yoffset = 0;
1515 m_doc->DoDrawing = false;
1516 pat.width = ite->width();
1517 pat.height = ite->height();
1518 m_currentMaskPosition = QPointF(ite->xPos(), ite->yPos());
1519 ite->gXpos = 0;
1520 ite->gYpos = 0;
1521 ite->setXYPos(ite->gXpos, ite->gYpos, true);
1522 pat.items.append(ite);
1523 m_doc->Items->removeAll(ite);
1524 QString id = QString("Pattern_from_PDF_%1S").arg(m_doc->docPatterns.count() + 1);
1525 m_doc->addPattern(id, pat);
1526 m_currentMask = id;
1527 tmpSel->clear();
1528 return;
1529 }
1530 PageItem *ite;
1531 for (int dre = 0; dre < gElements.Items.count(); ++dre)
1532 {
1533 tmpSel->addItem(gElements.Items.at(dre), true);
1534 m_Elements->removeAll(gElements.Items.at(dre));
1535 }
1536 if ((gElements.Items.count() != 1) || (gElements.isolated))
1537 ite = m_doc->groupObjectsSelection(tmpSel);
1538 else
1539 ite = gElements.Items.first();
1540 if (ite->isGroup())
1541 {
1542 ite->ClipEdited = true;
1543 ite->FrameType = 3;
1544 if (checkClip())
1545 {
1546 QPainterPath clippath = m_currentClipPath;
1547 clippath.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
1548 clippath.translate(-ite->xPos(), -ite->yPos());
1549 ite->PoLine.fromQPainterPath(clippath, true);
1550 ite->ClipEdited = true;
1551 ite->FrameType = 3;
1552 ite->setTextFlowMode(PageItem::TextFlowDisabled);
1553 // Comment out temporarily, there are some bad interactions between adjustItemSize() and
1554 // resizeGroupToContents() since fixing resizing of multiple selections
1555 //m_doc->adjustItemSize(ite, true);
1556 m_doc->resizeGroupToContents(ite);
1557 ite->OldB2 = ite->width();
1558 ite->OldH2 = ite->height();
1559 }
1560 }
1561 ite->setFillTransparency(1.0 - state->getFillOpacity());
1562 ite->setFillBlendmode(getBlendMode(state));
1563 m_Elements->append(ite);
1564 if (m_groupStack.count() != 0)
1565 {
1566 applyMask(ite);
1567 m_groupStack.top().Items.append(ite);
1568 }
1569
1570 tmpSel->clear();
1571 }
1572
1573 void SlaOutputDev::setSoftMask(GfxState * /*state*/, POPPLER_CONST_070 double * bbox, GBool alpha, Function *transferFunc, GfxColor * /*backdropColor*/)
1574 {
1575 if (m_groupStack.count() <= 0)
1576 return;
1577
1578 double lum = 0;
1579 double lum2 = 0;
1580 if (transferFunc)
1581 transferFunc->transform(&lum, &lum2);
1582 else
1583 lum2 = lum;
1584 m_groupStack.top().inverted = (lum != lum2);
1585 m_groupStack.top().maskName = m_currentMask;
1586 // Remember the mask's position as it might not align with the image to which the mask is later assigned.
1587 m_groupStack.top().maskPos = m_currentMaskPosition;
1588 m_groupStack.top().alpha = alpha;
1589 if (m_groupStack.top().Items.count() != 0)
1590 applyMask(m_groupStack.top().Items.last());
1591 }
1592
1593 void SlaOutputDev::clearSoftMask(GfxState * /*state*/)
1594 {
1595 if (m_groupStack.count() != 0)
1596 m_groupStack.top().maskName = "";
1597 }
1598
1599 void SlaOutputDev::updateFillColor(GfxState *state)
1600 {
1601 m_currFillShade = 100;
1602 m_currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &m_currFillShade);
1603 }
1604
1605 void SlaOutputDev::updateStrokeColor(GfxState *state)
1606 {
1607 m_currStrokeShade = 100;
1608 m_currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &m_currStrokeShade);
1609 }
1610
1611 void SlaOutputDev::clip(GfxState *state)
1612 {
1613 // qDebug() << "Clip";
1614 adjustClip(state, Qt::WindingFill);
1615 }
1616
1617 void SlaOutputDev::eoClip(GfxState *state)
1618 {
1619 // qDebug() << "EoClip";
1620 adjustClip(state, Qt::OddEvenFill);
1621 }
1622
1623 void SlaOutputDev::adjustClip(GfxState *state, Qt::FillRule fillRule)
1624 {
1625 const double *ctm = state->getCTM();
1626 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
1627 QString output = convertPath(state->getPath());
1628 if (output.isEmpty())
1629 return;
1630 FPointArray out;
1631 out.parseSVG(output);
1632 out.svgClosePath();
1633 out.map(m_ctm);
1634 if (checkClip())
1635 {
1636 // "clip" (WindingFill) and "eoClip" (OddEvenFill) only the determine
1637 // the fill rule of the new clipping path. The new clip should be the
1638 // intersection of the old and new area. QPainterPath determines on
1639 // its own which fill rule to use for the result. We should not loose
1640 // this information.
1641 QPainterPath pathN = out.toQPainterPath(false);
1642 pathN.setFillRule(fillRule);
1643 m_currentClipPath = intersection(pathN, m_currentClipPath);
1644 }
1645 else
1646 m_currentClipPath = out.toQPainterPath(false);
1647 }
1648
1649 void SlaOutputDev::stroke(GfxState *state)
1650 {
1651 // qDebug() << "Stroke";
1652 const double *ctm;
1653 ctm = state->getCTM();
1654 double xCoor = m_doc->currentPage()->xOffset();
1655 double yCoor = m_doc->currentPage()->yOffset();
1656 QString output = convertPath(state->getPath());
1657 getPenState(state);
1658 if ((m_Elements->count() != 0) && (output == Coords)) // Path is the same as in last fill
1659 {
1660 PageItem* ite = m_Elements->last();
1661 ite->setLineColor(m_currColorStroke);
1662 ite->setLineShade(m_currStrokeShade);
1663 ite->setLineEnd(m_lineEnd);
1664 ite->setLineJoin(m_lineJoin);
1665 ite->setLineWidth(state->getTransformedLineWidth());
1666 ite->setDashes(DashValues);
1667 ite->setDashOffset(DashOffset);
1668 ite->setLineTransparency(1.0 - state->getStrokeOpacity());
1669 }
1670 else
1671 {
1672 FPointArray out;
1673 out.parseSVG(output);
1674 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
1675 out.map(m_ctm);
1676 FPoint wh = out.widthHeight();
1677 if ((out.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)))
1678 {
1679 m_currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &m_currStrokeShade);
1680 int z;
1681 if (pathIsClosed)
1682 z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, state->getTransformedLineWidth(), CommonStrings::None, m_currColorStroke);
1683 else
1684 z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, xCoor, yCoor, 10, 10, state->getTransformedLineWidth(), CommonStrings::None, m_currColorStroke);
1685 PageItem* ite = m_doc->Items->at(z);
1686 ite->PoLine = out.copy();
1687 ite->ClipEdited = true;
1688 ite->FrameType = 3;
1689 ite->setWidthHeight(wh.x(), wh.y());
1690 m_doc->adjustItemSize(ite);
1691 if (m_Elements->count() != 0)
1692 {
1693 PageItem* lItem = m_Elements->last();
1694 if ((lItem->lineColor() == CommonStrings::None) && (lItem->PoLine == ite->PoLine))
1695 {
1696 lItem->setLineColor(m_currColorStroke);
1697 lItem->setLineWidth(state->getTransformedLineWidth());
1698 lItem->setLineShade(m_currStrokeShade);
1699 lItem->setLineTransparency(1.0 - state->getStrokeOpacity());
1700 lItem->setLineBlendmode(getBlendMode(state));
1701 lItem->setLineEnd(m_lineEnd);
1702 lItem->setLineJoin(m_lineJoin);
1703 lItem->setDashes(DashValues);
1704 lItem->setDashOffset(DashOffset);
1705 lItem->setTextFlowMode(PageItem::TextFlowDisabled);
1706 m_doc->Items->removeAll(ite);
1707 }
1708 else
1709 {
1710 ite->setLineShade(m_currStrokeShade);
1711 ite->setLineTransparency(1.0 - state->getStrokeOpacity());
1712 ite->setLineBlendmode(getBlendMode(state));
1713 ite->setLineEnd(m_lineEnd);
1714 ite->setLineJoin(m_lineJoin);
1715 ite->setDashes(DashValues);
1716 ite->setDashOffset(DashOffset);
1717 ite->setTextFlowMode(PageItem::TextFlowDisabled);
1718 m_Elements->append(ite);
1719 if (m_groupStack.count() != 0)
1720 m_groupStack.top().Items.append(ite);
1721 }
1722 }
1723 else
1724 {
1725 ite->setLineShade(m_currStrokeShade);
1726 ite->setLineTransparency(1.0 - state->getStrokeOpacity());
1727 ite->setLineBlendmode(getBlendMode(state));
1728 ite->setLineEnd(m_lineEnd);
1729 ite->setLineJoin(m_lineJoin);
1730 ite->setDashes(DashValues);
1731 ite->setDashOffset(DashOffset);
1732 ite->setTextFlowMode(PageItem::TextFlowDisabled);
1733 m_Elements->append(ite);
1734 if (m_groupStack.count() != 0)
1735 m_groupStack.top().Items.append(ite);
1736 }
1737 }
1738 }
1739 }
1740
1741 void SlaOutputDev::fill(GfxState *state)
1742 {
1743 // qDebug() << "Fill";
1744 createFillItem(state, Qt::WindingFill);
1745 }
1746
1747 void SlaOutputDev::eoFill(GfxState *state)
1748 {
1749 // qDebug() << "EoFill";
1750 createFillItem(state, Qt::OddEvenFill);
1751 }
1752
1753 void SlaOutputDev::createFillItem(GfxState *state, Qt::FillRule fillRule)
1754 {
1755 const double *ctm;
1756 ctm = state->getCTM();
1757 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
1758 double xCoor = m_doc->currentPage()->xOffset();
1759 double yCoor = m_doc->currentPage()->yOffset();
1760 FPointArray out;
1761 QString output = convertPath(state->getPath());
1762 out.parseSVG(output);
1763 out.map(m_ctm);
1764
1765 // Clip the new path first and only add it if it is not empty.
1766 QPainterPath path = out.toQPainterPath(false);
1767 path.setFillRule(fillRule);
1768 QPainterPath clippedPath = intersection(m_currentClipPath, path);
1769
1770 // Undo the rotation of the clipping path as it is rotated together with the item.
1771 double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
1772 QTransform mm;
1773 mm.rotate(angle);
1774 clippedPath = mm.map(clippedPath);
1775
1776 Coords = output;
1777 QRectF bbox = clippedPath.boundingRect();
1778 if (!clippedPath.isEmpty() && !bbox.isNull())
1779 {
1780 m_currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &m_currFillShade);
1781 int z;
1782 if (pathIsClosed)
1783 z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, m_currColorFill, CommonStrings::None);
1784 else
1785 z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, m_currColorFill, CommonStrings::None);
1786 PageItem* ite = m_doc->Items->at(z);
1787 ite->PoLine.fromQPainterPath(clippedPath, true);
1788 ite->ClipEdited = true;
1789 ite->FrameType = 3;
1790 ite->setFillShade(m_currFillShade);
1791 ite->setLineShade(100);
1792 ite->setRotation(-angle);
1793 // Only the new path has to be interpreted according to fillRule. QPainterPath
1794 // could decide to create a final path according to the other rule. Thus
1795 // we have to set this from the final path.
1796 ite->setFillEvenOdd(clippedPath.fillRule() == Qt::OddEvenFill);
1797 ite->setFillTransparency(1.0 - state->getFillOpacity());
1798 ite->setFillBlendmode(getBlendMode(state));
1799 ite->setLineEnd(m_lineEnd);
1800 ite->setLineJoin(m_lineJoin);
1801 ite->setWidthHeight(bbox.width(),bbox.height());
1802 ite->setTextFlowMode(PageItem::TextFlowDisabled);
1803 m_doc->adjustItemSize(ite);
1804 m_Elements->append(ite);
1805 if (m_groupStack.count() != 0)
1806 {
1807 m_groupStack.top().Items.append(ite);
1808 applyMask(ite);
1809 }
1810 }
1811 }
1812
1813 GBool SlaOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax)
1814 {
1815 // qDebug() << "SlaOutputDev::axialShadedFill";
1816 double GrStartX;
1817 double GrStartY;
1818 double GrEndX;
1819 double GrEndY;
1820 int shade = 100;
1821 POPPLER_CONST_070 Function *func = shading->getFunc(0);
1822 VGradient FillGradient = VGradient(VGradient::linear);
1823 FillGradient.clearStops();
1824 GfxColorSpace *color_space = shading->getColorSpace();
1825 if (func->getType() == 3)
1826 {
1827 StitchingFunction *stitchingFunc = (StitchingFunction*)func;
1828 const double *bounds = stitchingFunc->getBounds();
1829 int num_funcs = stitchingFunc->getNumFuncs();
1830 double domain_min = stitchingFunc->getDomainMin(0);
1831 double domain_max = stitchingFunc->getDomainMax(0);
1832 if (fabs(domain_max - domain_min) < 1e-6)
1833 {
1834 domain_min = 0.0;
1835 domain_max = 1.0;
1836 }
1837 // Add stops from all the stitched functions
1838 for (int i = 0 ; i <= num_funcs ; i++)
1839 {
1840 GfxColor temp;
1841 shading->getColor(bounds[i], &temp);
1842 QString stopColor = getColor(color_space, &temp, &shade);
1843 double stopPoint = (bounds[i] - domain_min) / (domain_max - domain_min);
1844 FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor], m_doc, shade), stopPoint, 0.5, 1.0, stopColor, shade );
1845 }
1846 }
1847 else if ((func->getType() == 2) || (func->getType() == 0))
1848 {
1849 GfxColor stop1;
1850 shading->getColor(0.0, &stop1);
1851 QString stopColor1 = getColor(color_space, &stop1, &shade);
1852 FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor1], m_doc, shade), 0.0, 0.5, 1.0, stopColor1, shade );
1853 GfxColor stop2;
1854 shading->getColor(1.0, &stop2);
1855 QString stopColor2 = getColor(color_space, &stop2, &shade);
1856 FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor2], m_doc, shade), 1.0, 0.5, 1.0, stopColor2, shade );
1857 }
1858 shading->getCoords(&GrStartX, &GrStartY, &GrEndX, &GrEndY);
1859 double xmin, ymin, xmax, ymax;
1860 // get the clip region bbox
1861 state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
1862 QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
1863 crect = crect.normalized();
1864 QPainterPath out;
1865 out.addRect(crect);
1866 if (checkClip())
1867 {
1868 // Apply the clip path early to adjust the gradient vector to the
1869 // smaller boundign box.
1870 out = intersection(m_currentClipPath, out);
1871 crect = out.boundingRect();
1872 }
1873 const double *ctm = state->getCTM();
1874 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
1875 FPointArray gr;
1876 gr.addPoint(GrStartX, GrStartY);
1877 gr.addPoint(GrEndX, GrEndY);
1878 gr.map(m_ctm);
1879 gr.translate(-crect.x(), -crect.y());
1880
1881 // Undo the rotation and translation of the gradient vector.
1882 double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
1883 QTransform mm;
1884 mm.rotate(angle);
1885 out.translate(-crect.x(), -crect.y());
1886 out = mm.map(out);
1887 QRectF bb = out.boundingRect();
1888 gr.map(mm);
1889 gr.translate(-bb.left(), -bb.top());
1890 GrStartX = gr.point(0).x();
1891 GrStartY = gr.point(0).y();
1892 GrEndX = gr.point(1).x();
1893 GrEndY = gr.point(1).y();
1894
1895 double xCoor = m_doc->currentPage()->xOffset();
1896 double yCoor = m_doc->currentPage()->yOffset();
1897 QString output = QString("M %1 %2").arg(0.0).arg(0.0);
1898 output += QString("L %1 %2").arg(crect.width()).arg(0.0);
1899 output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
1900 output += QString("L %1 %2").arg(0.0).arg(crect.height());
1901 output += QString("L %1 %2").arg(0.0).arg(0.0);
1902 output += QString("Z");
1903 pathIsClosed = true;
1904 Coords = output;
1905 int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), bb.width(), bb.height(), 0, m_currColorFill, CommonStrings::None);
1906 PageItem* ite = m_doc->Items->at(z);
1907 if (checkClip())
1908 {
1909 ite->PoLine.fromQPainterPath(out, true);
1910 ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
1911 }
1912 ite->setRotation(-angle);
1913 ite->ClipEdited = true;
1914 ite->FrameType = 3;
1915 ite->setFillShade(m_currFillShade);
1916 ite->setLineShade(100);
1917 ite->setFillTransparency(1.0 - state->getFillOpacity());
1918 ite->setFillBlendmode(getBlendMode(state));
1919 ite->setLineEnd(m_lineEnd);
1920 ite->setLineJoin(m_lineJoin);
1921 ite->setTextFlowMode(PageItem::TextFlowDisabled);
1922 ite->GrType = 6;
1923 if (!shading->getExtend0() || !shading->getExtend1())
1924 {
1925 FillGradient.setRepeatMethod(VGradient::none);
1926 ite->setGradientExtend(VGradient::none);
1927 }
1928 else
1929 {
1930 FillGradient.setRepeatMethod(VGradient::pad);
1931 ite->setGradientExtend(VGradient::pad);
1932 }
1933 ite->fill_gradient = FillGradient;
1934 ite->setGradientVector(GrStartX, GrStartY, GrEndX, GrEndY, 0, 0, 1, 0);
1935 m_doc->adjustItemSize(ite);
1936 m_Elements->append(ite);
1937 if (m_groupStack.count() != 0)
1938 {
1939 m_groupStack.top().Items.append(ite);
1940 applyMask(ite);
1941 }
1942 return gTrue;
1943 }
1944
1945 GBool SlaOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax)
1946 {
1947 // qDebug() << "SlaOutputDev::radialShadedFill";
1948 double GrStartX;
1949 double GrStartY;
1950 double GrEndX;
1951 double GrEndY;
1952 int shade = 100;
1953 POPPLER_CONST_070 Function *func = shading->getFunc(0);
1954 VGradient FillGradient = VGradient(VGradient::linear);
1955 FillGradient.clearStops();
1956 GfxColorSpace *color_space = shading->getColorSpace();
1957 if (func->getType() == 3)
1958 {
1959 StitchingFunction *stitchingFunc = (StitchingFunction*)func;
1960 const double *bounds = stitchingFunc->getBounds();
1961 int num_funcs = stitchingFunc->getNumFuncs();
1962 double domain_min = stitchingFunc->getDomainMin(0);
1963 double domain_max = stitchingFunc->getDomainMax(0);
1964 if (fabs(domain_max - domain_min) < 1e-6)
1965 {
1966 domain_min = 0.0;
1967 domain_max = 1.0;
1968 }
1969 // Add stops from all the stitched functions
1970 for (int i = 0 ; i <= num_funcs ; i++)
1971 {
1972 GfxColor temp;
1973 shading->getColor(bounds[i], &temp);
1974 QString stopColor = getColor(color_space, &temp, &shade);
1975 double stopPoint = (bounds[i] - domain_min) / (domain_max - domain_min);
1976 FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor], m_doc, shade), stopPoint, 0.5, 1.0, stopColor, shade );
1977 }
1978 }
1979 else if ((func->getType() == 2) || (func->getType() == 0))
1980 {
1981 GfxColor stop1;
1982 shading->getColor(0.0, &stop1);
1983 QString stopColor1 = getColor(color_space, &stop1, &shade);
1984 FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor1], m_doc, shade), 0.0, 0.5, 1.0, stopColor1, shade );
1985 GfxColor stop2;
1986 shading->getColor(1.0, &stop2);
1987 QString stopColor2 = getColor(color_space, &stop2, &shade);
1988 FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor2], m_doc, shade), 1.0, 0.5, 1.0, stopColor2, shade );
1989 }
1990 double r0, x1, y1, r1;
1991 shading->getCoords(&GrStartX, &GrStartY, &r0, &x1, &y1, &r1);
1992 double xmin, ymin, xmax, ymax;
1993 // get the clip region bbox
1994 state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
1995 QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
1996 crect = crect.normalized();
1997 double GrFocalX = x1;
1998 double GrFocalY = y1;
1999 GrEndX = GrFocalX + r1;
2000 GrEndY = GrFocalY;
2001 const double *ctm = state->getCTM();
2002 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
2003 FPointArray gr;
2004 gr.addPoint(GrStartX, GrStartY);
2005 gr.addPoint(GrEndX, GrEndY);
2006 gr.addPoint(GrFocalX, GrFocalY);
2007 gr.map(m_ctm);
2008 GrStartX = gr.point(0).x() - crect.x();
2009 GrStartY = gr.point(0).y() - crect.y();
2010 GrEndX = gr.point(1).x() - crect.x();
2011 GrEndY = gr.point(1).y() - crect.y();
2012 GrFocalX = gr.point(2).x() - crect.x();
2013 GrFocalY = gr.point(2).y() - crect.y();
2014 double xCoor = m_doc->currentPage()->xOffset();
2015 double yCoor = m_doc->currentPage()->yOffset();
2016 QString output = QString("M %1 %2").arg(0.0).arg(0.0);
2017 output += QString("L %1 %2").arg(crect.width()).arg(0.0);
2018 output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
2019 output += QString("L %1 %2").arg(0.0).arg(crect.height());
2020 output += QString("L %1 %2").arg(0.0).arg(0.0);
2021 output += QString("Z");
2022 pathIsClosed = true;
2023 Coords = output;
2024 int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
2025 PageItem* ite = m_doc->Items->at(z);
2026 if (checkClip())
2027 {
2028 QPainterPath out = m_currentClipPath;
2029 out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
2030 out.translate(-ite->xPos(), -ite->yPos());
2031 ite->PoLine.fromQPainterPath(out, true);
2032 ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
2033 }
2034 ite->ClipEdited = true;
2035 ite->FrameType = 3;
2036 ite->setFillShade(m_currFillShade);
2037 ite->setLineShade(100);
2038 ite->setFillTransparency(1.0 - state->getFillOpacity());
2039 ite->setFillBlendmode(getBlendMode(state));
2040 ite->setLineEnd(m_lineEnd);
2041 ite->setLineJoin(m_lineJoin);
2042 ite->setTextFlowMode(PageItem::TextFlowDisabled);
2043 ite->GrType = 7;
2044 if (!shading->getExtend0() || !shading->getExtend1())
2045 {
2046 FillGradient.setRepeatMethod(VGradient::none);
2047 ite->setGradientExtend(VGradient::none);
2048 }
2049 else
2050 {
2051 FillGradient.setRepeatMethod(VGradient::pad);
2052 ite->setGradientExtend(VGradient::pad);
2053 }
2054 ite->fill_gradient = FillGradient;
2055 ite->setGradientVector(GrStartX, GrStartY, GrEndX, GrEndY, GrFocalX, GrFocalY, 1, 0);
2056 m_doc->adjustItemSize(ite);
2057 m_Elements->append(ite);
2058 if (m_groupStack.count() != 0)
2059 {
2060 m_groupStack.top().Items.append(ite);
2061 applyMask(ite);
2062 }
2063 return gTrue;
2064 }
2065
2066 GBool SlaOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
2067 {
2068 // qDebug() << "SlaOutputDev::gouraudTriangleShadedFill";
2069 double xCoor = m_doc->currentPage()->xOffset();
2070 double yCoor = m_doc->currentPage()->yOffset();
2071 double xmin, ymin, xmax, ymax;
2072 // get the clip region bbox
2073 state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
2074 QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
2075 crect = crect.normalized();
2076 QString output = QString("M %1 %2").arg(0.0).arg(0.0);
2077 output += QString("L %1 %2").arg(crect.width()).arg(0.0);
2078 output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
2079 output += QString("L %1 %2").arg(0.0).arg(crect.height());
2080 output += QString("L %1 %2").arg(0.0).arg(0.0);
2081 output += QString("Z");
2082 pathIsClosed = true;
2083 Coords = output;
2084 const double *ctm = state->getCTM();
2085 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
2086 int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
2087 PageItem* ite = m_doc->Items->at(z);
2088 ite->ClipEdited = true;
2089 ite->FrameType = 3;
2090 ite->setFillShade(m_currFillShade);
2091 ite->setLineShade(100);
2092 ite->setFillEvenOdd(false);
2093 ite->setFillTransparency(1.0 - state->getFillOpacity());
2094 ite->setFillBlendmode(getBlendMode(state));
2095 ite->setLineEnd(m_lineEnd);
2096 ite->setLineJoin(m_lineJoin);
2097 ite->setTextFlowMode(PageItem::TextFlowDisabled);
2098 m_doc->adjustItemSize(ite);
2099 m_Elements->append(ite);
2100 if (m_groupStack.count() != 0)
2101 {
2102 m_groupStack.top().Items.append(ite);
2103 applyMask(ite);
2104 }
2105 GfxColor color[3];
2106 double x0, y0, x1, y1, x2, y2;
2107 for (int i = 0; i < shading->getNTriangles(); i++)
2108 {
2109 int shade = 100;
2110 meshGradientPatch patchM;
2111 shading->getTriangle(i, &x0, &y0, &color[0], &x1, &y1, &color[1], &x2, &y2, &color[2]);
2112 patchM.BL.resetTo(FPoint(x0, y0));
2113 patchM.BL.shade = 100;
2114 patchM.BL.transparency = 1.0;
2115 patchM.BL.colorName = getColor(shading->getColorSpace(), &color[0], &shade);
2116 patchM.BL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BL.colorName], m_doc, shade);
2117 patchM.TL.resetTo(FPoint(x1, y1));
2118 patchM.TL.shade = 100;
2119 patchM.TL.transparency = 1.0;
2120 patchM.TL.colorName = getColor(shading->getColorSpace(), &color[1], &shade);
2121 patchM.TL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TL.colorName], m_doc, shade);
2122 patchM.TR.resetTo(FPoint(x2, y2));
2123 patchM.TR.shade = 100;
2124 patchM.TR.transparency = 1.0;
2125 patchM.TR.colorName = getColor(shading->getColorSpace(), &color[2], &shade);
2126 patchM.TR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TR.colorName], m_doc, shade);
2127 patchM.BR.resetTo(FPoint(x0, y0));
2128 patchM.BR.shade = 100;
2129 patchM.BR.transparency = 1.0;
2130 patchM.BR.colorName = getColor(shading->getColorSpace(), &color[0], &shade);
2131 patchM.BR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BR.colorName], m_doc, shade);
2132 patchM.TL.transform(m_ctm);
2133 patchM.TL.moveRel(-crect.x(), -crect.y());
2134 patchM.TR.transform(m_ctm);
2135 patchM.TR.moveRel(-crect.x(), -crect.y());
2136 patchM.BR.transform(m_ctm);
2137 patchM.BR.moveRel(-crect.x(), -crect.y());
2138 patchM.BL.transform(m_ctm);
2139 patchM.BL.moveRel(-crect.x(), -crect.y());
2140 ite->meshGradientPatches.append(patchM);
2141 }
2142 ite->GrType = 12;
2143 return gTrue;
2144 }
2145
2146 GBool SlaOutputDev::patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
2147 {
2148 // qDebug() << "SlaOutputDev::patchMeshShadedFill";
2149 double xCoor = m_doc->currentPage()->xOffset();
2150 double yCoor = m_doc->currentPage()->yOffset();
2151 double xmin, ymin, xmax, ymax;
2152 // get the clip region bbox
2153 state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
2154 QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
2155 crect = crect.normalized();
2156 QString output = QString("M %1 %2").arg(0.0).arg(0.0);
2157 output += QString("L %1 %2").arg(crect.width()).arg(0.0);
2158 output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
2159 output += QString("L %1 %2").arg(0.0).arg(crect.height());
2160 output += QString("L %1 %2").arg(0.0).arg(0.0);
2161 output += QString("Z");
2162 pathIsClosed = true;
2163 Coords = output;
2164 const double *ctm = state->getCTM();
2165 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
2166 int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
2167 PageItem* ite = m_doc->Items->at(z);
2168 ite->ClipEdited = true;
2169 ite->FrameType = 3;
2170 ite->setFillShade(m_currFillShade);
2171 ite->setLineShade(100);
2172 ite->setFillEvenOdd(false);
2173 ite->setFillTransparency(1.0 - state->getFillOpacity());
2174 ite->setFillBlendmode(getBlendMode(state));
2175 ite->setLineEnd(m_lineEnd);
2176 ite->setLineJoin(m_lineJoin);
2177 ite->setTextFlowMode(PageItem::TextFlowDisabled);
2178 m_doc->adjustItemSize(ite);
2179 m_Elements->append(ite);
2180 if (m_groupStack.count() != 0)
2181 {
2182 m_groupStack.top().Items.append(ite);
2183 applyMask(ite);
2184 }
2185 ite->meshGradientPatches.clear();
2186 for (int i = 0; i < shading->getNPatches(); i++)
2187 {
2188 int shade = 100;
2189 const GfxPatch *patch = shading->getPatch(i);
2190 GfxColor color;
2191 meshGradientPatch patchM;
2192 int u, v;
2193 patchM.BL.resetTo(FPoint(patch->x[0][0], patch->y[0][0]));
2194 patchM.BL.controlTop = FPoint(patch->x[0][1], patch->y[0][1]);
2195 patchM.BL.controlRight = FPoint(patch->x[1][0], patch->y[1][0]);
2196 patchM.BL.controlColor = FPoint(patch->x[1][1], patch->y[1][1]);
2197 u = 0;
2198 v = 0;
2199 if (shading->isParameterized())
2200 {
2201 shading->getParameterizedColor (patch->color[u][v].c[0], &color);
2202 }
2203 else
2204 {
2205 for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
2206 {
2207 color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
2208 }
2209 }
2210 patchM.BL.colorName = getColor(shading->getColorSpace(), &color, &shade);
2211 patchM.BL.shade = 100;
2212 patchM.BL.transparency = 1.0;
2213 patchM.BL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BL.colorName], m_doc, shade);
2214
2215 u = 0;
2216 v = 1;
2217 patchM.TL.resetTo(FPoint(patch->x[0][3], patch->y[0][3]));
2218 patchM.TL.controlRight = FPoint(patch->x[1][3], patch->y[1][3]);
2219 patchM.TL.controlBottom = FPoint(patch->x[0][2], patch->y[0][2]);
2220 patchM.TL.controlColor = FPoint(patch->x[1][2], patch->y[1][2]);
2221 if (shading->isParameterized())
2222 {
2223 shading->getParameterizedColor (patch->color[u][v].c[0], &color);
2224 }
2225 else
2226 {
2227 for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
2228 {
2229 color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
2230 }
2231 }
2232 patchM.TL.colorName = getColor(shading->getColorSpace(), &color, &shade);
2233 patchM.TL.shade = 100;
2234 patchM.TL.transparency = 1.0;
2235 patchM.TL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TL.colorName], m_doc, shade);
2236
2237 u = 1;
2238 v = 1;
2239 patchM.TR.resetTo(FPoint(patch->x[3][3], patch->y[3][3]));
2240 patchM.TR.controlBottom = FPoint(patch->x[3][2], patch->y[3][2]);
2241 patchM.TR.controlLeft = FPoint(patch->x[2][3], patch->y[2][3]);
2242 patchM.TR.controlColor = FPoint(patch->x[2][2], patch->y[2][2]);
2243 if (shading->isParameterized())
2244 {
2245 shading->getParameterizedColor (patch->color[u][v].c[0], &color);
2246 }
2247 else
2248 {
2249 for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
2250 {
2251 color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
2252 }
2253 }
2254 patchM.TR.colorName = getColor(shading->getColorSpace(), &color, &shade);
2255 patchM.TR.shade = 100;
2256 patchM.TR.transparency = 1.0;
2257 patchM.TR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TR.colorName], m_doc, shade);
2258
2259 u = 1;
2260 v = 0;
2261 patchM.BR.resetTo(FPoint(patch->x[3][0], patch->y[3][0]));
2262 patchM.BR.controlLeft = FPoint(patch->x[2][0], patch->y[2][0]);
2263 patchM.BR.controlTop = FPoint(patch->x[3][1], patch->y[3][1]);
2264 patchM.BR.controlColor = FPoint(patch->x[2][1], patch->y[2][1]);
2265 if (shading->isParameterized())
2266 {
2267 shading->getParameterizedColor (patch->color[u][v].c[0], &color);
2268 }
2269 else
2270 {
2271 for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
2272 {
2273 color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
2274 }
2275 }
2276 patchM.BR.colorName = getColor(shading->getColorSpace(), &color, &shade);
2277 patchM.BR.shade = 100;
2278 patchM.BR.transparency = 1.0;
2279 patchM.BR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BR.colorName], m_doc, shade);
2280
2281 patchM.TL.transform(m_ctm);
2282 patchM.TL.moveRel(-crect.x(), -crect.y());
2283 patchM.TR.transform(m_ctm);
2284 patchM.TR.moveRel(-crect.x(), -crect.y());
2285 patchM.BR.transform(m_ctm);
2286 patchM.BR.moveRel(-crect.x(), -crect.y());
2287 patchM.BL.transform(m_ctm);
2288 patchM.BL.moveRel(-crect.x(), -crect.y());
2289 ite->meshGradientPatches.append(patchM);
2290 }
2291 ite->GrType = 12;
2292 return gTrue;
2293 }
2294
2295 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 3, 0)
2296 bool SlaOutputDev::tilingPatternFill(GfxState *state, Gfx * /*gfx*/, Catalog *cat, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep)
2297 #else
2298 GBool SlaOutputDev::tilingPatternFill(GfxState *state, Gfx * /*gfx*/, Catalog *cat, Object *str, POPPLER_CONST_070 double *pmat, int /*paintType*/, int /*tilingType*/, Dict *resDict, POPPLER_CONST_070 double *mat, POPPLER_CONST_070 double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep)
2299 #endif
2300 {
2301 // qDebug() << "SlaOutputDev::tilingPatternFill";
2302 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 3, 0)
2303 const double *bbox = tPat->getBBox();
2304 const double *pmat = tPat->getMatrix();
2305 Dict *resDict = tPat->getResDict();
2306 #endif
2307
2308 PDFRectangle box;
2309 Gfx *gfx;
2310 QString id;
2311 PageItem *ite;
2312 groupEntry gElements;
2313 m_groupStack.push(gElements);
2314 double width, height;
2315 width = bbox[2] - bbox[0];
2316 height = bbox[3] - bbox[1];
2317 if (xStep != width || yStep != height)
2318 return gFalse;
2319 box.x1 = bbox[0];
2320 box.y1 = bbox[1];
2321 box.x2 = bbox[2];
2322 box.y2 = bbox[3];
2323
2324 const double *ctm = state->getCTM();
2325 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
2326 QTransform mm = QTransform(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
2327 QTransform mmx = mm * m_ctm;
2328
2329 gfx = new Gfx(pdfDoc, this, resDict, &box, nullptr);
2330 inPattern++;
2331 // Unset the clip path as it is unrelated to the pattern's coordinate space.
2332 QPainterPath savedClip = m_currentClipPath;
2333 m_currentClipPath = QPainterPath();
2334 #if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 3, 0)
2335 gfx->display(tPat->getContentStream());
2336 #else
2337 gfx->display(str);
2338 #endif
2339 m_currentClipPath = savedClip;
2340 inPattern--;
2341 gElements = m_groupStack.pop();
2342 m_doc->m_Selection->clear();
2343 // double pwidth = 0;
2344 // double pheight = 0;
2345 if (gElements.Items.count() > 0)
2346 {
2347 for (int dre = 0; dre < gElements.Items.count(); ++dre)
2348 {
2349 m_doc->m_Selection->addItem(gElements.Items.at(dre), true);
2350 m_Elements->removeAll(gElements.Items.at(dre));
2351 }
2352 m_doc->itemSelection_FlipV();
2353 PageItem *ite;
2354 if (m_doc->m_Selection->count() > 1)
2355 ite = m_doc->groupObjectsSelection();
2356 else
2357 ite = m_doc->m_Selection->itemAt(0);
2358 ite->setFillTransparency(1.0 - state->getFillOpacity());
2359 ite->setFillBlendmode(getBlendMode(state));
2360 m_doc->m_Selection->clear();
2361 ScPattern pat = ScPattern();
2362 pat.setDoc(m_doc);
2363 m_doc->DoDrawing = true;
2364 pat.pattern = ite->DrawObj_toImage(qMin(qMax(ite->width(), ite->height()), 500.0));
2365 pat.xoffset = 0;
2366 pat.yoffset = 0;
2367 m_doc->DoDrawing = false;
2368 pat.width = ite->width();
2369 pat.height = ite->height();
2370 // pwidth = ite->width();
2371 // pheight = ite->height();
2372 ite->gXpos = 0;
2373 ite->gYpos = 0;
2374 ite->setXYPos(ite->gXpos, ite->gYpos, true);
2375 pat.items.append(ite);
2376 m_doc->Items->removeAll(ite);
2377 id = QString("Pattern_from_PDF_%1").arg(m_doc->docPatterns.count() + 1);
2378 m_doc->addPattern(id, pat);
2379 }
2380 double xCoor = m_doc->currentPage()->xOffset();
2381 double yCoor = m_doc->currentPage()->yOffset();
2382 double xmin, ymin, xmax, ymax;
2383 // get the clip region bbox
2384 state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
2385 QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
2386 crect = crect.normalized();
2387 QString output = QString("M %1 %2").arg(0.0).arg(0.0);
2388 output += QString("L %1 %2").arg(crect.width()).arg(0.0);
2389 output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
2390 output += QString("L %1 %2").arg(0.0).arg(crect.height());
2391 output += QString("L %1 %2").arg(0.0).arg(0.0);
2392 output += QString("Z");
2393 pathIsClosed = true;
2394 Coords = output;
2395 int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
2396 ite = m_doc->Items->at(z);
2397
2398 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
2399 double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
2400 ite->setRotation(-angle);
2401 if (checkClip())
2402 {
2403 QPainterPath outline = m_currentClipPath;
2404 outline.translate(xCoor - ite->xPos(), yCoor - ite->yPos());
2405 // Undo the rotation of the clipping path as it is rotated together with the item.
2406 QTransform mm;
2407 mm.rotate(angle);
2408 outline = mm.map(outline);
2409 ite->PoLine.fromQPainterPath(outline, true);
2410 ite->setFillEvenOdd(outline.fillRule() == Qt::OddEvenFill);
2411 }
2412 ite->ClipEdited = true;
2413 ite->FrameType = 3;
2414 ite->setFillShade(m_currFillShade);
2415 ite->setLineShade(100);
2416 ite->setFillTransparency(1.0 - state->getFillOpacity());
2417 ite->setFillBlendmode(getBlendMode(state));
2418 ite->setLineEnd(m_lineEnd);
2419 ite->setLineJoin(m_lineJoin);
2420 ite->setTextFlowMode(PageItem::TextFlowDisabled);
2421 ite->GrType = 8;
2422 ite->setPattern(id);
2423 ite->setPatternTransform(fabs(pmat[0]) * 100, fabs(pmat[3]) * 100, mmx.dx() - ctm[4], mmx.dy() - ctm[5], 0, -1 * pmat[1], pmat[2]);
2424 m_doc->adjustItemSize(ite);
2425 m_Elements->append(ite);
2426 if (m_groupStack.count() != 0)
2427 {
2428 m_groupStack.top().Items.append(ite);
2429 applyMask(ite);
2430 }
2431 delete gfx;
2432 return gTrue;
2433 }
2434
2435 void SlaOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool interpolate, GBool inlineImg)
2436 {
2437 // qDebug() << "Draw Image Mask";
2438 QImage * image = nullptr;
2439 int invert_bit;
2440 int row_stride;
2441 int x, y, i, bit;
2442 unsigned char *dest = nullptr;
2443 unsigned char *buffer;
2444 Guchar *pix;
2445 ImageStream * imgStr = new ImageStream(str, width, 1, 1);
2446 imgStr->reset();
2447 #ifdef WORDS_BIGENDIAN
2448 image = new QImage(width, height, QImage::Format_Mono);
2449 #else
2450 image = new QImage(width, height, QImage::Format_MonoLSB);
2451 #endif
2452 if (image == nullptr || image->isNull())
2453 {
2454 delete imgStr;
2455 delete image;
2456 return;
2457 }
2458 invert_bit = invert ? 1 : 0;
2459 buffer = image->bits();
2460 row_stride = image->bytesPerLine();
2461 for (y = 0; y < height; y++)
2462 {
2463 pix = imgStr->getLine();
2464 dest = buffer + y * row_stride;
2465 i = 0;
2466 bit = 0;
2467 for (x = 0; x < width; x++)
2468 {
2469 if (bit == 0)
2470 dest[i] = 0;
2471 if (!(pix[x] ^ invert_bit))
2472 {
2473 #ifdef WORDS_BIGENDIAN
2474 dest[i] |= (1 << (7 - bit));
2475 #else
2476 dest[i] |= (1 << bit);
2477 #endif
2478 }
2479 bit++;
2480 if (bit > 7)
2481 {
2482 bit = 0;
2483 i++;
2484 }
2485 }
2486 }
2487 QColor backColor = ScColorEngine::getShadeColorProof(m_doc->PageColors[m_currColorFill], m_doc, m_currFillShade);
2488 QImage res = QImage(width, height, QImage::Format_ARGB32);
2489 res.fill(backColor.rgb());
2490 unsigned char cc, cm, cy, ck;
2491 for (int yi = 0; yi < res.height(); ++yi)
2492 {
2493 QRgb *t = (QRgb*)(res.scanLine( yi ));
2494 for (int xi = 0; xi < res.width(); ++xi)
2495 {
2496 cc = qRed(*t);
2497 cm = qGreen(*t);
2498 cy = qBlue(*t);
2499 ck = image->pixel(xi, yi);
2500 if (ck == 0)
2501 (*t) = qRgba(cc, cm, cy, 0);
2502 else
2503 (*t) = qRgba(cc, cm, cy, 255);
2504 t++;
2505 }
2506 }
2507
2508 createImageFrame(res, state, 3);
2509
2510 imgStr->close();
2511 delete imgStr;
2512 delete image;
2513 }
2514
2515 void SlaOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool interpolate, Stream *maskStr, int maskWidth, int maskHeight,
2516 GfxImageColorMap *maskColorMap, GBool maskInterpolate)
2517 {
2518 // qDebug() << "SlaOutputDev::drawSoftMaskedImage Masked Image Components" << colorMap->getNumPixelComps();
2519 ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
2520 imgStr->reset();
2521 unsigned int *dest = nullptr;
2522 unsigned char * buffer = new unsigned char[width * height * 4];
2523 QImage * image = nullptr;
2524 for (int y = 0; y < height; y++)
2525 {
2526 dest = (unsigned int *)(buffer + y * 4 * width);
2527 Guchar * pix = imgStr->getLine();
2528 colorMap->getRGBLine(pix, dest, width);
2529 }
2530 image = new QImage(buffer, width, height, QImage::Format_RGB32);
2531 if (image == nullptr || image->isNull())
2532 {
2533 delete imgStr;
2534 delete[] buffer;
2535 delete image;
2536 return;
2537 }
2538 ImageStream *mskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2539 mskStr->reset();
2540 Guchar *mdest = nullptr;
2541 unsigned char * mbuffer = new unsigned char[maskWidth * maskHeight];
2542 memset(mbuffer, 0, maskWidth * maskHeight);
2543 for (int y = 0; y < maskHeight; y++)
2544 {
2545 mdest = (Guchar *)(mbuffer + y * maskWidth);
2546 Guchar * pix = mskStr->getLine();
2547 maskColorMap->getGrayLine(pix, mdest, maskWidth);
2548 }
2549 if ((maskWidth != width) || (maskHeight != height))
2550 *image = image->scaled(maskWidth, maskHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2551 QImage res = image->convertToFormat(QImage::Format_ARGB32);
2552
2553 int matteRc, matteGc, matteBc;
2554 POPPLER_CONST_070 GfxColor *matteColor = maskColorMap->getMatteColor();
2555 if (matteColor != nullptr)
2556 {
2557 GfxRGB matteRgb;
2558 colorMap->getColorSpace()->getRGB(matteColor, &matteRgb);
2559 matteRc = qRound(colToDbl(matteRgb.r) * 255);
2560 matteGc = qRound(colToDbl(matteRgb.g) * 255);
2561 matteBc = qRound(colToDbl(matteRgb.b) * 255);
2562 }
2563
2564 unsigned char cr, cg, cb, ca;
2565 int s = 0;
2566 for (int yi=0; yi < res.height(); ++yi)
2567 {
2568 QRgb *t = (QRgb*)(res.scanLine( yi ));
2569 for (int xi=0; xi < res.width(); ++xi)
2570 {
2571 cr = qRed(*t);
2572 cg = qGreen(*t);
2573 cb = qBlue(*t);
2574 ca = mbuffer[s];
2575 if (matteColor != nullptr)
2576 {
2577 cr = unblendMatte(cr, ca, matteRc);
2578 cg = unblendMatte(cg, ca, matteGc);
2579 cb = unblendMatte(cb, ca, matteBc);
2580 }
2581 (*t) = qRgba(cr, cg, cb, ca);
2582 s++;
2583 t++;
2584 }
2585 }
2586
2587 createImageFrame(res, state, 3);
2588
2589 delete imgStr;
2590 delete[] buffer;
2591 delete image;
2592 delete mskStr;
2593 delete[] mbuffer;
2594 }
2595
2596 void SlaOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GBool maskInterpolate)
2597 {
2598 // qDebug() << "SlaOutputDev::drawMaskedImage";
2599 ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
2600 imgStr->reset();
2601 unsigned int *dest = nullptr;
2602 unsigned char * buffer = new unsigned char[width * height * 4];
2603 QImage * image = nullptr;
2604 for (int y = 0; y < height; y++)
2605 {
2606 dest = (unsigned int *)(buffer + y * 4 * width);
2607 Guchar * pix = imgStr->getLine();
2608 colorMap->getRGBLine(pix, dest, width);
2609 }
2610 image = new QImage(buffer, width, height, QImage::Format_RGB32);
2611 if (image == nullptr || image->isNull())
2612 {
2613 delete imgStr;
2614 delete[] buffer;
2615 delete image;
2616 return;
2617 }
2618 ImageStream *mskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2619 mskStr->reset();
2620 Guchar *mdest = nullptr;
2621 int invert_bit = maskInvert ? 1 : 0;
2622 unsigned char * mbuffer = new unsigned char[maskWidth * maskHeight];
2623 memset(mbuffer, 0, maskWidth * maskHeight);
2624 for (int y = 0; y < maskHeight; y++)
2625 {
2626 mdest = (Guchar *)(mbuffer + y * maskWidth);
2627 Guchar * pix = mskStr->getLine();
2628 for (int x = 0; x < maskWidth; x++)
2629 {
2630 if (pix[x] ^ invert_bit)
2631 *mdest++ = 0;
2632 else
2633 *mdest++ = 255;
2634 }
2635 }
2636 if ((maskWidth != width) || (maskHeight != height))
2637 *image = image->scaled(maskWidth, maskHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
2638 QImage res = image->convertToFormat(QImage::Format_ARGB32);
2639 unsigned char cc, cm, cy, ck;
2640 int s = 0;
2641 for (int yi=0; yi < res.height(); ++yi)
2642 {
2643 QRgb *t = (QRgb*)(res.scanLine( yi ));
2644 for (int xi=0; xi < res.width(); ++xi)
2645 {
2646 cc = qRed(*t);
2647 cm = qGreen(*t);
2648 cy = qBlue(*t);
2649 ck = mbuffer[s];
2650 (*t) = qRgba(cc, cm, cy, ck);
2651 s++;
2652 t++;
2653 }
2654 }
2655
2656 createImageFrame(res, state, colorMap->getNumPixelComps());
2657
2658 delete imgStr;
2659 delete[] buffer;
2660 delete image;
2661 delete mskStr;
2662 delete[] mbuffer;
2663 }
2664
2665 void SlaOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool interpolate, POPPLER_CONST_082 int* maskColors, GBool inlineImg)
2666 {
2667 ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
2668 // qDebug() << "SlaOutputDev::drawImage Image Components" << colorMap->getNumPixelComps() << "Mask" << maskColors;
2669 imgStr->reset();
2670 QImage* image = nullptr;
2671 if (maskColors)
2672 {
2673 image = new QImage(width, height, QImage::Format_ARGB32);
2674 for (int y = 0; y < height; y++)
2675 {
2676 QRgb *s = (QRgb*)(image->scanLine(y));
2677 Guchar *pix = imgStr->getLine();
2678 for (int x = 0; x < width; x++)
2679 {
2680 GfxRGB rgb;
2681 colorMap->getRGB(pix, &rgb);
2682 int Rc = qRound(colToDbl(rgb.r) * 255);
2683 int Gc = qRound(colToDbl(rgb.g) * 255);
2684 int Bc = qRound(colToDbl(rgb.b) * 255);
2685 *s = qRgba(Rc, Gc, Bc, 255);
2686 for (int i = 0; i < colorMap->getNumPixelComps(); ++i)
2687 {
2688 if (pix[i] < maskColors[2*i] * 255 || pix[i] > maskColors[2*i+1] * 255)
2689 {
2690 *s = *s | 0xff000000;
2691 break;
2692 }
2693 }
2694 s++;
2695 pix += colorMap->getNumPixelComps();
2696 }
2697 }
2698 }
2699 else
2700 {
2701 image = new QImage(width, height, QImage::Format_ARGB32);
2702 for (int y = 0; y < height; y++)
2703 {
2704 QRgb *s = (QRgb*)(image->scanLine(y));
2705 Guchar *pix = imgStr->getLine();
2706 for (int x = 0; x < width; x++)
2707 {
2708 if (colorMap->getNumPixelComps() == 4)
2709 {
2710 GfxCMYK cmyk;
2711 colorMap->getCMYK(pix, &cmyk);
2712 int Cc = qRound(colToDbl(cmyk.c) * 255);
2713 int Mc = qRound(colToDbl(cmyk.m) * 255);
2714 int Yc = qRound(colToDbl(cmyk.y) * 255);
2715 int Kc = qRound(colToDbl(cmyk.k) * 255);
2716 *s = qRgba(Yc, Mc, Cc, Kc);
2717 }
2718 else
2719 {
2720 GfxRGB rgb;
2721 colorMap->getRGB(pix, &rgb);
2722 int Rc = qRound(colToDbl(rgb.r) * 255);
2723 int Gc = qRound(colToDbl(rgb.g) * 255);
2724 int Bc = qRound(colToDbl(rgb.b) * 255);
2725 *s = qRgba(Rc, Gc, Bc, 255);
2726 }
2727 s++;
2728 pix += colorMap->getNumPixelComps();
2729 }
2730 }
2731 }
2732
2733 if (image != nullptr && !image->isNull()) {
2734 createImageFrame(*image, state, colorMap->getNumPixelComps());
2735 }
2736
2737 delete imgStr;
2738 delete image;
2739 }
2740
2741 void SlaOutputDev::createImageFrame(QImage& image, GfxState *state, int numColorComponents)
2742 {
2743 // qDebug() << "SlaOutputDev::createImageFrame";
2744 const double *ctm = state->getCTM();
2745 double xCoor = m_doc->currentPage()->xOffset();
2746 double yCoor = m_doc->currentPage()->yOffset();
2747
2748 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
2749 double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
2750 QPointF torigin;
2751 // In PDF all images considered squares with unit length that are transformed into the proper
2752 // dimensions by ctm.
2753 // A positive determinant retains orientation. Thus orientation is the same as in the PDF
2754 // coordinate system (y-axis increases upwards). As Scribus uses the inverse orientation the
2755 // image needs to be flipped (a horizontal flip is applied later). For a flipped image the
2756 // corner that will be origin in Scribus is the upper right corner (1, 1) of the image.
2757 // A negative determinant changes the orientation such that the image is already in the Scribus
2758 // coordinate orientation and no flip is necessary. The origin will be the upper left corner (0, 1).
2759 if (m_ctm.determinant() > 0) {
2760 torigin = m_ctm.map(QPointF(1, 1));
2761 } else {
2762 torigin = m_ctm.map(QPointF(0, 1));
2763 }
2764
2765 // Determine the visible area of the picture after clipping it. If it is empty, no item
2766 // needs to be created.
2767 QPainterPath outline;
2768 outline.addRect(0, 0, 1, 1);
2769 outline = m_ctm.map(outline);
2770 outline = intersection(outline, m_currentClipPath);
2771
2772 if ((inPattern == 0) && (outline.isEmpty() || outline.boundingRect().isNull()))
2773 return;
2774
2775 // Determine the width and height of the image by undoing the rotation part
2776 // of the CTM and applying the result to the unit square.
2777 QTransform without_rotation;
2778 without_rotation = m_ctm * without_rotation.rotate(angle);
2779 QRectF trect_wr = without_rotation.mapRect(QRectF(0, 0, 1, 1));
2780
2781 int z = m_doc->itemAdd(PageItem::ImageFrame, PageItem::Rectangle, xCoor + torigin.x(), yCoor + torigin.y(), trect_wr.width(), trect_wr.height(), 0, CommonStrings::None, CommonStrings::None);
2782 PageItem* ite = m_doc->Items->at(z);
2783 ite->ClipEdited = true;
2784 ite->FrameType = 3;
2785 m_doc->setRedrawBounding(ite);
2786 ite->Clip = flattenPath(ite->PoLine, ite->Segments);
2787 ite->setTextFlowMode(PageItem::TextFlowDisabled);
2788 ite->setFillShade(100);
2789 ite->setLineShade(100);
2790 ite->setFillEvenOdd(false);
2791 ite->setFillTransparency(1.0 - state->getFillOpacity());
2792 ite->setFillBlendmode(getBlendMode(state));
2793 if (m_ctm.determinant() > 0)
2794 {
2795 ite->setRotation(-(angle - 180));
2796 ite->setImageFlippedH(true);
2797 }
2798 else
2799 ite->setRotation(-angle);
2800 m_doc->adjustItemSize(ite);
2801
2802 if (numColorComponents == 4)
2803 {
2804 QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_pdf_XXXXXX.tif");
2805 tempFile->setAutoRemove(false);
2806 if (tempFile->open())
2807 {
2808 QString fileName = getLongPathName(tempFile->fileName());
2809 if (!fileName.isEmpty())
2810 {
2811 tempFile->close();
2812 ite->isInlineImage = true;
2813 ite->isTempFile = true;
2814 ite->AspectRatio = false;
2815 ite->ScaleType = false;
2816 TIFF* tif = TIFFOpen(fileName.toLocal8Bit().data(), "w");
2817 if (tif)
2818 {
2819 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, image.width());
2820 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, image.height());
2821 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
2822 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
2823 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
2824 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
2825 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
2826 for (int y = 0; y < image.height(); ++y)
2827 {
2828 TIFFWriteScanline(tif, image.scanLine(y), y);
2829 }
2830 TIFFClose(tif);
2831 m_doc->loadPict(fileName, ite);
2832 }
2833 m_Elements->append(ite);
2834 if (m_groupStack.count() != 0)
2835 {
2836 m_groupStack.top().Items.append(ite);
2837 applyMask(ite);
2838 }
2839 }
2840 else
2841 m_doc->Items->removeAll(ite);
2842 }
2843 delete tempFile;
2844 }
2845 else
2846 {
2847 QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_pdf_XXXXXX.png");
2848 tempFile->setAutoRemove(false);
2849 if (tempFile->open())
2850 {
2851 QString fileName = getLongPathName(tempFile->fileName());
2852 if (!fileName.isEmpty())
2853 {
2854 tempFile->close();
2855 ite->isInlineImage = true;
2856 ite->isTempFile = true;
2857 ite->AspectRatio = false;
2858 ite->ScaleType = false;
2859 image.save(fileName, "PNG");
2860 m_doc->loadPict(fileName, ite);
2861 m_Elements->append(ite);
2862 if (m_groupStack.count() != 0)
2863 {
2864 m_groupStack.top().Items.append(ite);
2865 applyMask(ite);
2866 }
2867 }
2868 else
2869 m_doc->Items->removeAll(ite);
2870 }
2871 delete tempFile;
2872 }
2873 if (inPattern == 0)
2874 {
2875 outline.translate(xCoor - ite->xPos(), yCoor - ite->yPos());
2876 // Undo the rotation of the clipping path as it is rotated together with the iamge.
2877 QTransform mm;
2878 mm.rotate(-ite->rotation());
2879 outline = mm.map(outline);
2880 ite->PoLine.fromQPainterPath(outline, true);
2881 ite->setFillEvenOdd(outline.fillRule() == Qt::OddEvenFill);
2882 ite->ClipEdited = true;
2883 ite->FrameType = 3;
2884 ite->setTextFlowMode(PageItem::TextFlowDisabled);
2885 ite->ScaleType = true;
2886 m_doc->adjustItemSize(ite);
2887 ite->OldB2 = ite->width();
2888 ite->OldH2 = ite->height();
2889 ite->updateClip();
2890 }
2891 }
2892
2893 void SlaOutputDev::beginMarkedContent(POPPLER_CONST char *name, Object *dictRef)
2894 {
2895 mContent mSte;
2896 mSte.name = QString(name);
2897 mSte.ocgName = "";
2898 if (importerFlags & LoadSavePlugin::lfCreateDoc)
2899 {
2900 if (dictRef->isNull())
2901 return;
2902 Object dictObj;
2903 Dict *dict;
2904 Object dictType;
2905 OCGs *contentConfig = catalog->getOptContentConfig();
2906 OptionalContentGroup *oc;
2907 if (dictRef->isRef())
2908 {
2909 oc = contentConfig->findOcgByRef(dictRef->getRef());
2910 if (oc)
2911 {
2912 // qDebug() << "Begin OCG Content (Ref) with Name " << QString(name) << "Layer" << UnicodeParsedString(oc->getName());
2913 m_doc->setActiveLayer(UnicodeParsedString(oc->getName()));
2914 mSte.ocgName = UnicodeParsedString(oc->getName());
2915 }
2916 }
2917 else
2918 {
2919 dictObj = dictRef->fetch(xref);
2920 if (!dictObj.isDict())
2921 return;
2922 dict = dictObj.getDict();
2923 dictType = dict->lookup("Type");
2924 if (dictType.isName("OCG"))
2925 {
2926 oc = contentConfig->findOcgByRef(dictRef->getRef());
2927 if (oc)
2928 {
2929 // qDebug() << "Begin OCG Content with Name " << UnicodeParsedString(oc->getName());
2930 m_doc->setActiveLayer(UnicodeParsedString(oc->getName()));
2931 mSte.ocgName = UnicodeParsedString(oc->getName());
2932 }
2933 }
2934 }
2935 }
2936 m_mcStack.push(mSte);
2937 }
2938
2939 void SlaOutputDev::beginMarkedContent(POPPLER_CONST char *name, Dict *properties)
2940 {
2941 // qDebug() << "Begin Marked Content with Name " << QString(name);
2942 QString nam = QString(name);
2943 mContent mSte;
2944 mSte.name = nam;
2945 mSte.ocgName = "";
2946 m_mcStack.push(mSte);
2947 if (importerFlags & LoadSavePlugin::lfCreateDoc)
2948 {
2949 if (nam == "Layer") // Handle Adobe Illustrator Layer command
2950 {
2951 if (layersSetByOCG)
2952 return;
2953 QString lName = QString("Layer_%1").arg(layerNum + 1);
2954 Object obj = properties->lookup((char*) "Title");
2955 if (obj.isString())
2956 lName = QString(obj.getString()->getCString());
2957 for (ScLayers::iterator it = m_doc->Layers.begin(); it != m_doc->Layers.end(); ++it)
2958 {
2959 if (it->Name == lName)
2960 {
2961 m_doc->setActiveLayer(lName);
2962 return;
2963 }
2964 }
2965 layerNum++;
2966 if (!firstLayer)
2967 currentLayer = m_doc->addLayer(lName, true);
2968 firstLayer = false;
2969
2970 obj = properties->lookup((char*) "Visible");
2971 if (obj.isBool())
2972 m_doc->setLayerVisible(currentLayer, obj.getBool());
2973 obj = properties->lookup((char*) "Editable");
2974 if (obj.isBool())
2975 m_doc->setLayerLocked(currentLayer, !obj.getBool());
2976 obj = properties->lookup((char*) "Printed");
2977 if (obj.isBool())
2978 m_doc->setLayerPrintable(currentLayer, obj.getBool());
2979 obj = properties->lookup((char*)"Color");
2980 if (obj.isArray())
2981 {
2982 Object obj1;
2983 obj1 = obj.arrayGet(0);
2984 int r = obj1.getNum() / 256;
2985 obj1 = obj.arrayGet(1);
2986 int g = obj1.getNum() / 256;
2987 obj1 = obj.arrayGet(2);
2988 int b = obj1.getNum() / 256;
2989 m_doc->setLayerMarker(currentLayer, QColor(r, g, b));
2990 }
2991 }
2992 }
2993 }
2994
2995 void SlaOutputDev::endMarkedContent(GfxState *state)
2996 {
2997 // qDebug() << "End Marked Content";
2998 if (m_mcStack.count() > 0)
2999 {
3000 mContent mSte = m_mcStack.pop();
3001 if (importerFlags & LoadSavePlugin::lfCreateDoc)
3002 {
3003 if (mSte.name == "OC")
3004 {
3005 for (ScLayers::iterator it = m_doc->Layers.begin(); it != m_doc->Layers.end(); ++it)
3006 {
3007 if (it->Name == mSte.ocgName)
3008 {
3009 m_doc->setActiveLayer(mSte.ocgName);
3010 return;
3011 }
3012 }
3013 }
3014 }
3015 }
3016 }
3017
3018 void SlaOutputDev::markPoint(POPPLER_CONST char *name)
3019 {
3020 // qDebug() << "Begin Marked Point with Name " << QString(name);
3021 }
3022
3023 void SlaOutputDev::markPoint(POPPLER_CONST char *name, Dict *properties)
3024 {
3025 // qDebug() << "Begin Marked Point with Name " << QString(name) << "and Properties";
3026 beginMarkedContent(name, properties);
3027 }
3028
3029 void SlaOutputDev::updateFont(GfxState *state)
3030 {
3031 GfxFont *gfxFont;
3032 GfxFontLoc *fontLoc;
3033 GfxFontType fontType;
3034 SlaOutFontFileID *id;
3035 SplashFontFile *fontFile;
3036 SplashFontSrc *fontsrc = nullptr;
3037 FoFiTrueType *ff;
3038 Object refObj, strObj;
3039 GooString *fileName;
3040 char *tmpBuf;
3041 int tmpBufLen = 0;
3042 int *codeToGID;
3043 const double *textMat;
3044 double m11, m12, m21, m22, fontSize;
3045 SplashCoord mat[4];
3046 int n = 0;
3047 int faceIndex = 0;
3048 SplashCoord matrix[6];
3049
3050 m_font = nullptr;
3051 fileName = nullptr;
3052 tmpBuf = nullptr;
3053 fontLoc = nullptr;
3054
3055 gfxFont = state->getFont();
3056 if (!gfxFont)
3057 goto err1;
3058
3059 fontType = gfxFont->getType();
3060 if (fontType == fontType3)
3061 goto err1;
3062
3063 // check the font file cache
3064 id = new SlaOutFontFileID(gfxFont->getID());
3065 if ((fontFile = m_fontEngine->getFontFile(id)))
3066 delete id;
3067 else
3068 {
3069 if (!(fontLoc = gfxFont->locateFont(xref, nullptr)))
3070 {
3071 error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
3072 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3073 goto err2;
3074 }
3075
3076 // embedded font
3077 if (fontLoc->locType == gfxFontLocEmbedded)
3078 {
3079 // if there is an embedded font, read it to memory
3080 tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
3081 if (! tmpBuf)
3082 goto err2;
3083
3084 // external font
3085 }
3086 else
3087 { // gfxFontLocExternal
3088 fileName = fontLoc->path;
3089 fontType = fontLoc->fontType;
3090 }
3091
3092 fontsrc = new SplashFontSrc;
3093 if (fileName)
3094 fontsrc->setFile(fileName, gFalse);
3095 else
3096 fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
3097
3098 // load the font file
3099 switch (fontType) {
3100 case fontType1:
3101 if (!(fontFile = m_fontEngine->loadType1Font(
3102 id,
3103 fontsrc,
3104 (const char **)((Gfx8BitFont *) gfxFont)->getEncoding())))
3105 {
3106 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3107 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3108 goto err2;
3109 }
3110 break;
3111 case fontType1C:
3112 if (!(fontFile = m_fontEngine->loadType1CFont(
3113 id,
3114 fontsrc,
3115 (const char **)((Gfx8BitFont *) gfxFont)->getEncoding())))
3116 {
3117 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3118 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3119 goto err2;
3120 }
3121 break;
3122 case fontType1COT:
3123 if (!(fontFile = m_fontEngine->loadOpenTypeT1CFont(
3124 id,
3125 fontsrc,
3126 (const char **)((Gfx8BitFont *) gfxFont)->getEncoding())))
3127 {
3128 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3129 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3130 goto err2;
3131 }
3132 break;
3133 case fontTrueType:
3134 case fontTrueTypeOT:
3135 if (fileName)
3136 ff = FoFiTrueType::load(fileName->getCString());
3137 else
3138 ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
3139 if (ff)
3140 {
3141 codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
3142 n = 256;
3143 delete ff;
3144 }
3145 else
3146 {
3147 codeToGID = nullptr;
3148 n = 0;
3149 }
3150 if (!(fontFile = m_fontEngine->loadTrueTypeFont(
3151 id,
3152 fontsrc,
3153 codeToGID, n)))
3154 {
3155 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3156 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3157 goto err2;
3158 }
3159 break;
3160 case fontCIDType0:
3161 case fontCIDType0C:
3162 if (!(fontFile = m_fontEngine->loadCIDFont(
3163 id,
3164 fontsrc)))
3165 {
3166 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3167 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3168 goto err2;
3169 }
3170 break;
3171 case fontCIDType0COT:
3172 if (((GfxCIDFont *) gfxFont)->getCIDToGID())
3173 {
3174 n = ((GfxCIDFont *) gfxFont)->getCIDToGIDLen();
3175 codeToGID = (int *) gmallocn(n, sizeof(*codeToGID));
3176 memcpy(codeToGID, ((GfxCIDFont *) gfxFont)->getCIDToGID(), n * sizeof(*codeToGID));
3177 }
3178 else
3179 {
3180 codeToGID = nullptr;
3181 n = 0;
3182 }
3183 if (!(fontFile = m_fontEngine->loadOpenTypeCFFFont(
3184 id,
3185 fontsrc,
3186 codeToGID, n)))
3187 {
3188 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3189 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3190 goto err2;
3191 }
3192 break;
3193 case fontCIDType2:
3194 case fontCIDType2OT:
3195 codeToGID = nullptr;
3196 n = 0;
3197 if (((GfxCIDFont *) gfxFont)->getCIDToGID())
3198 {
3199 n = ((GfxCIDFont *) gfxFont)->getCIDToGIDLen();
3200 if (n)
3201 {
3202 codeToGID = (int *)gmallocn(n, sizeof(*codeToGID));
3203 memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(*codeToGID));
3204 }
3205 }
3206 else
3207 {
3208 if (fileName)
3209 ff = FoFiTrueType::load(fileName->getCString());
3210 else
3211 ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
3212 if (! ff)
3213 goto err2;
3214 codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
3215 delete ff;
3216 }
3217 if (!(fontFile = m_fontEngine->loadTrueTypeFont(
3218 id,
3219 fontsrc,
3220 codeToGID, n, faceIndex)))
3221 {
3222 error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
3223 gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
3224 goto err2;
3225 }
3226 break;
3227 default:
3228 // this shouldn't happen
3229 goto err2;
3230 }
3231 }
3232 // get the font matrix
3233 textMat = state->getTextMat();
3234 fontSize = state->getFontSize();
3235 m11 = textMat[0] * fontSize * state->getHorizScaling();
3236 m12 = textMat[1] * fontSize * state->getHorizScaling();
3237 m21 = textMat[2] * fontSize;
3238 m22 = textMat[3] * fontSize;
3239 matrix[0] = 1;
3240 matrix[1] = 0;
3241 matrix[2] = 0;
3242 matrix[3] = 1;
3243 matrix[4] = 0;
3244 matrix[5] = 0;
3245 // create the scaled font
3246 mat[0] = m11;
3247 mat[1] = -m12;
3248 mat[2] = m21;
3249 mat[3] = -m22;
3250 m_font = m_fontEngine->getFont(fontFile, mat, matrix);
3251
3252 delete fontLoc;
3253 if (fontsrc && !fontsrc->isFile)
3254 fontsrc->unref();
3255 return;
3256
3257 err2:
3258 delete id;
3259 delete fontLoc;
3260 err1:
3261 if (fontsrc && !fontsrc->isFile)
3262 fontsrc->unref();
3263 }
3264
3265 void SlaOutputDev::drawChar(GfxState* state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, POPPLER_CONST_082 Unicode* u, int uLen)
3266 {
3267 // qDebug() << "SlaOutputDev::drawChar code:" << code << "bytes:" << nBytes << "Unicode:" << u << "ulen:" << uLen << "render:" << state->getRender();
3268 double x1, y1, x2, y2;
3269 updateFont(state);
3270 if (!m_font)
3271 return;
3272
3273 // PDF 1.7 Section 9.3.6 defines eight text rendering modes.
3274 // 0 - Fill
3275 // 1 - Stroke
3276 // 2 - First fill and then stroke
3277 // 3 - Invisible
3278 // 4 - Fill and use as a clipping path
3279 // 5 - Stroke and use as a clipping path
3280 // 6 - First fill, then stroke and add as a clipping path
3281 // 7 - Only use as a clipping path.
3282 // TODO Implement the clipping operations. At least the characters are shown.
3283 int textRenderingMode = state->getRender();
3284 // Invisible or only used for clipping
3285 if (textRenderingMode == 3)
3286 return;
3287 if (textRenderingMode < 8)
3288 {
3289 SplashPath * fontPath;
3290 fontPath = m_font->getGlyphPath(code);
3291 if (fontPath)
3292 {
3293 QPainterPath qPath;
3294 qPath.setFillRule(Qt::WindingFill);
3295 for (int i = 0; i < fontPath->getLength(); ++i)
3296 {
3297 Guchar f;
3298 fontPath->getPoint(i, &x1, &y1, &f);
3299 if (f & splashPathFirst)
3300 qPath.moveTo(x1,y1);
3301 else if (f & splashPathCurve)
3302 {
3303 double x3, y3;
3304 ++i;
3305 fontPath->getPoint(i, &x2, &y2, &f);
3306 ++i;
3307 fontPath->getPoint(i, &x3, &y3, &f);
3308 qPath.cubicTo(x1,y1,x2,y2,x3,y3);
3309 }
3310 else
3311 qPath.lineTo(x1, y1);
3312 if (f & splashPathLast)
3313 qPath.closeSubpath();
3314 }
3315 const double * ctm = state->getCTM();
3316 m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
3317 double xCoor = m_doc->currentPage()->xOffset();
3318 double yCoor = m_doc->currentPage()->yOffset();
3319 FPointArray textPath;
3320 textPath.fromQPainterPath(qPath);
3321 FPoint wh = textPath.widthHeight();
3322 if (textRenderingMode > 3)
3323 {
3324 QTransform mm;
3325 mm.scale(1, -1);
3326 mm.translate(x, -y);
3327 // Remember the glyph for later clipping
3328 m_clipTextPath.addPath(m_ctm.map(mm.map(qPath)));
3329 }
3330 if ((textPath.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)) && (textRenderingMode != 7))
3331 {
3332 int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CommonStrings::None, CommonStrings::None);
3333 PageItem* ite = m_doc->Items->at(z);
3334
3335 // todo: merge this between vector and text implementations.
3336 QTransform mm;
3337 mm.scale(1, -1);
3338 mm.translate(x, -y);
3339 textPath.map(mm);
3340 textPath.map(m_ctm);
3341 ite->PoLine = textPath.copy();
3342 setItemFillAndStroke(state, ite);
3343 // Fill text rendering modes. See above
3344 m_doc->adjustItemSize(ite);
3345 m_Elements->append(ite);
3346 if (m_groupStack.count() != 0)
3347 {
3348 m_groupStack.top().Items.append(ite);
3349 applyMask(ite);
3350 }
3351 }
3352 delete fontPath;
3353
3354 }
3355 }
3356 }
3357
3358
3359 GBool SlaOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, POPPLER_CONST_082 Unicode *u, int uLen)
3360 {
3361 // qDebug() << "beginType3Char";
3362 GfxFont *gfxFont;
3363 if (!(gfxFont = state->getFont()))
3364 return gTrue;
3365 if (gfxFont->getType() != fontType3)
3366 return gTrue;
3367 F3Entry f3e;
3368 f3e.colored = false;
3369 m_F3Stack.push(f3e);
3370 pushGroup();
3371 return gFalse;
3372 }
3373
3374 void SlaOutputDev::endType3Char(GfxState *state)
3375 {
3376 // qDebug() << "endType3Char";
3377 F3Entry f3e = m_F3Stack.pop();
3378 groupEntry gElements = m_groupStack.pop();
3379 m_doc->m_Selection->clear();
3380 if (gElements.Items.count() > 0)
3381 {
3382 m_doc->m_Selection->delaySignalsOn();
3383 for (int dre = 0; dre < gElements.Items.count(); ++dre)
3384 {
3385 m_doc->m_Selection->addItem(gElements.Items.at(dre), true);
3386 m_Elements->removeAll(gElements.Items.at(dre));
3387 }
3388 PageItem *ite;
3389 if (m_doc->m_Selection->count() > 1)
3390 ite = m_doc->groupObjectsSelection();
3391 else
3392 ite = m_doc->m_Selection->itemAt(0);
3393 if (!f3e.colored)
3394 {
3395 m_doc->itemSelection_SetItemBrush(m_currColorFill);
3396 m_doc->itemSelection_SetItemBrushShade(m_currFillShade);
3397 m_doc->itemSelection_SetItemFillTransparency(1.0 - state->getFillOpacity());
3398 m_doc->itemSelection_SetItemFillBlend(getBlendMode(state));
3399 }
3400 m_Elements->append(ite);
3401 m_doc->m_Selection->clear();
3402 m_doc->m_Selection->delaySignalsOff();
3403 }
3404 }
3405
3406 void SlaOutputDev::type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/)
3407 {
3408 // qDebug() << "type3D0";
3409 if (m_F3Stack.count() > 0)
3410 m_F3Stack.top().colored = true;
3411 }
3412
3413 void SlaOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
3414 {
3415 // qDebug() << "type3D1";
3416 if (m_F3Stack.count() > 0)
3417 m_F3Stack.top().colored = false;
3418 }
3419
3420 void SlaOutputDev::beginTextObject(GfxState *state)
3421 {
3422 pushGroup();
3423 }
3424
3425 void SlaOutputDev::endTextObject(GfxState *state)
3426 {
3427 // qDebug() << "SlaOutputDev::endTextObject";
3428 if (!m_clipTextPath.isEmpty())
3429 {
3430 m_currentClipPath = intersection(m_currentClipPath, m_clipTextPath);
3431 m_clipTextPath = QPainterPath();
3432 }
3433 if (m_groupStack.count() != 0)
3434 {
3435 groupEntry gElements = m_groupStack.pop();
3436 tmpSel->clear();
3437 if (gElements.Items.count() > 0)
3438 {
3439 for (int dre = 0; dre < gElements.Items.count(); ++dre)
3440 {
3441 tmpSel->addItem(gElements.Items.at(dre), true);
3442 m_Elements->removeAll(gElements.Items.at(dre));
3443 }
3444 PageItem *ite;
3445 if (gElements.Items.count() != 1)
3446 ite = m_doc->groupObjectsSelection(tmpSel);
3447 else
3448 ite = gElements.Items.first();
3449 ite->setGroupClipping(false);
3450 ite->setFillTransparency(1.0 - state->getFillOpacity());
3451 ite->setFillBlendmode(getBlendMode(state));
3452 for (int as = 0; as < tmpSel->count(); ++as)
3453 {
3454 m_Elements->append(tmpSel->itemAt(as));
3455 }
3456 if (m_groupStack.count() != 0)
3457 applyMask(ite);
3458 }
3459 if (m_groupStack.count() != 0)
3460 {
3461 for (int as = 0; as < tmpSel->count(); ++as)
3462 {
3463 m_groupStack.top().Items.append(tmpSel->itemAt(as));
3464 }
3465 }
3466 tmpSel->clear();
3467 }
3468 }
3469
3470 QString SlaOutputDev::getColor(GfxColorSpace *color_space, POPPLER_CONST_070 GfxColor *color, int *shade)
3471 {
3472 QString fNam;
3473 QString namPrefix = "FromPDF";
3474 ScColor tmp;
3475 tmp.setSpotColor(false);
3476 tmp.setRegistrationColor(false);
3477 *shade = 100;
3478 /*if (m_F3Stack.count() > 0)
3479 {
3480 if (!m_F3Stack.top().colored)
3481 return "Black";
3482 }*/
3483
3484 if ((color_space->getMode() == csDeviceRGB) || (color_space->getMode() == csCalRGB))
3485 {
3486 GfxRGB rgb;
3487 color_space->getRGB(color, &rgb);
3488 double Rc = colToDbl(rgb.r);
3489 double Gc = colToDbl(rgb.g);
3490 double Bc = colToDbl(rgb.b);
3491 tmp.setRgbColorF(Rc, Gc, Bc);
3492 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3493 }
3494 else if (color_space->getMode() == csDeviceCMYK)
3495 {
3496 GfxCMYK cmyk;
3497 color_space->getCMYK(color, &cmyk);
3498 double Cc = colToDbl(cmyk.c);
3499 double Mc = colToDbl(cmyk.m);
3500 double Yc = colToDbl(cmyk.y);
3501 double Kc = colToDbl(cmyk.k);
3502 tmp.setCmykColorF(Cc, Mc, Yc, Kc);
3503 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3504 }
3505 else if ((color_space->getMode() == csCalGray) || (color_space->getMode() == csDeviceGray))
3506 {
3507 GfxGray gray;
3508 color_space->getGray(color, &gray);
3509 double Kc = 1.0 - colToDbl(gray);
3510 tmp.setCmykColorF(0, 0, 0, Kc);
3511 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3512 }
3513 else if (color_space->getMode() == csSeparation)
3514 {
3515 GfxSeparationColorSpace* sepColorSpace = (GfxSeparationColorSpace*) color_space;
3516 GfxColorSpace* altColorSpace = sepColorSpace->getAlt();
3517 QString name = QString(sepColorSpace->getName()->getCString());
3518 bool isRegistrationColor = (name == "All");
3519 if (isRegistrationColor)
3520 {
3521 tmp.setCmykColorF(1.0, 1.0, 1.0, 1.0);
3522 tmp.setRegistrationColor(true);
3523 name = "Registration";
3524 }
3525 else if ((altColorSpace->getMode() == csDeviceRGB) || (altColorSpace->getMode() == csCalRGB))
3526 {
3527 double x = 1.0;
3528 double comps[gfxColorMaxComps];
3529 sepColorSpace->getFunc()->transform(&x, comps);
3530 tmp.setRgbColorF(comps[0], comps[1], comps[2]);
3531 }
3532 else if ((altColorSpace->getMode() == csCalGray) || (altColorSpace->getMode() == csDeviceGray))
3533 {
3534 double x = 1.0;
3535 double comps[gfxColorMaxComps];
3536 sepColorSpace->getFunc()->transform(&x, comps);
3537 tmp.setCmykColorF(0.0, 0.0, 0.0, 1.0 - comps[0]);
3538 }
3539 else if (altColorSpace->getMode() == csLab)
3540 {
3541 double x = 1.0;
3542 double comps[gfxColorMaxComps];
3543 sepColorSpace->getFunc()->transform(&x, comps);
3544 tmp.setLabColor(comps[0], comps[1], comps[2]);
3545 }
3546 else
3547 {
3548 GfxCMYK cmyk;
3549 color_space->getCMYK(color, &cmyk);
3550 double Cc = colToDbl(cmyk.c);
3551 double Mc = colToDbl(cmyk.m);
3552 double Yc = colToDbl(cmyk.y);
3553 double Kc = colToDbl(cmyk.k);
3554 tmp.setCmykColorF(Cc, Mc, Yc, Kc);
3555 }
3556 tmp.setSpotColor(true);
3557
3558 fNam = m_doc->PageColors.tryAddColor(name, tmp);
3559 *shade = qRound(colToDbl(color->c[0]) * 100);
3560 }
3561 else
3562 {
3563 GfxRGB rgb;
3564 color_space->getRGB(color, &rgb);
3565 double Rc = colToDbl(rgb.r);
3566 double Gc = colToDbl(rgb.g);
3567 double Bc = colToDbl(rgb.b);
3568 tmp.setRgbColorF(Rc, Gc, Bc);
3569 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3570 // qDebug() << "update fill color other colorspace" << color_space->getMode() << "treating as rgb" << Rc << Gc << Bc;
3571 }
3572 if (fNam == namPrefix+tmp.name())
3573 m_importedColors->append(fNam);
3574 return fNam;
3575 }
3576
3577 QString SlaOutputDev::getAnnotationColor(const AnnotColor *color)
3578 {
3579 QString fNam;
3580 QString namPrefix = "FromPDF";
3581 ScColor tmp;
3582 tmp.setSpotColor(false);
3583 tmp.setRegistrationColor(false);
3584 if (color->getSpace() == AnnotColor::colorTransparent)
3585 return CommonStrings::None;
3586 if (color->getSpace() == AnnotColor::colorRGB)
3587 {
3588 const double *color_data = color->getValues();
3589 double Rc = color_data[0];
3590 double Gc = color_data[1];
3591 double Bc = color_data[2];
3592 tmp.setRgbColorF(Rc, Gc, Bc);
3593 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3594 }
3595 else if (color->getSpace() == AnnotColor::colorCMYK)
3596 {
3597 const double *color_data = color->getValues();
3598 double Cc = color_data[0];
3599 double Mc = color_data[1];
3600 double Yc = color_data[2];
3601 double Kc = color_data[3];
3602 tmp.setCmykColorF(Cc, Mc, Yc, Kc);
3603 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3604 }
3605 else if (color->getSpace() == AnnotColor::colorGray)
3606 {
3607 const double *color_data = color->getValues();
3608 double Kc = 1.0 - color_data[0];
3609 tmp.setCmykColorF(0, 0, 0, Kc);
3610 fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
3611 }
3612 if (fNam == namPrefix+tmp.name())
3613 m_importedColors->append(fNam);
3614 return fNam;
3615 }
3616
3617 QString SlaOutputDev::convertPath(POPPLER_CONST_083 GfxPath *path)
3618 {
3619 // qDebug() << "SlaOutputDev::convertPath";
3620 if (! path)
3621 return QString();
3622
3623 QString output;
3624 pathIsClosed = false;
3625
3626 for (int i = 0; i < path->getNumSubpaths(); ++i)
3627 {
3628 POPPLER_CONST_083 GfxSubpath * subpath = path->getSubpath(i);
3629 if (subpath->getNumPoints() > 0)
3630 {
3631 output += QString("M %1 %2").arg(subpath->getX(0)).arg(subpath->getY(0));
3632 int j = 1;
3633 while (j < subpath->getNumPoints())
3634 {
3635 if (subpath->getCurve(j))
3636 {
3637 output += QString("C %1 %2 %3 %4 %5 %6")
3638 .arg(subpath->getX(j)).arg(subpath->getY(j))
3639 .arg(subpath->getX(j + 1)).arg(subpath->getY(j + 1))
3640 .arg(subpath->getX(j + 2)).arg(subpath->getY(j + 2));
3641 j += 3;
3642 }
3643 else
3644 {
3645 output += QString("L %1 %2").arg(subpath->getX(j)).arg(subpath->getY(j));
3646 ++j;
3647 }
3648 }
3649 if (subpath->isClosed())
3650 {
3651 output += QString("Z");
3652 pathIsClosed = true;
3653 }
3654 }
3655 }
3656 return output;
3657 }
3658
3659 void SlaOutputDev::getPenState(GfxState *state)
3660 {
3661 switch (state->getLineCap())
3662 {
3663 case 0:
3664 m_lineEnd = Qt::FlatCap;
3665 break;
3666 case 1:
3667 m_lineEnd = Qt::RoundCap;
3668 break;
3669 case 2:
3670 m_lineEnd = Qt::SquareCap;
3671 break;
3672 }
3673 switch (state->getLineJoin())
3674 {
3675 case 0:
3676 m_lineJoin = Qt::MiterJoin;
3677 break;
3678 case 1:
3679 m_lineJoin = Qt::RoundJoin;
3680 break;
3681 case 2:
3682 m_lineJoin = Qt::BevelJoin;
3683 break;
3684 }
3685 double lw = state->getLineWidth();
3686 double *dashPattern;
3687 int dashLength;
3688 state->getLineDash(&dashPattern, &dashLength, &DashOffset);
3689 QVector<double> pattern(dashLength);
3690 for (int i = 0; i < dashLength; ++i)
3691 {
3692 pattern[i] = dashPattern[i] / lw;
3693 }
3694 DashValues = pattern;
3695 }
3696
3697 int SlaOutputDev::getBlendMode(GfxState *state)
3698 {
3699 int mode = 0;
3700 switch (state->getBlendMode())
3701 {
3702 default:
3703 case gfxBlendNormal:
3704 mode = 0;
3705 break;
3706 case gfxBlendDarken:
3707 mode = 1;
3708 break;
3709 case gfxBlendLighten:
3710 mode = 2;
3711 break;
3712 case gfxBlendMultiply:
3713 mode = 3;
3714 break;
3715 case gfxBlendScreen:
3716 mode = 4;
3717 break;
3718 case gfxBlendOverlay:
3719 mode = 5;
3720 break;
3721 case gfxBlendHardLight:
3722 mode = 6;
3723 break;
3724 case gfxBlendSoftLight:
3725 mode = 7;
3726 break;
3727 case gfxBlendDifference:
3728 mode = 8;
3729 break;
3730 case gfxBlendExclusion:
3731 mode = 9;
3732 break;
3733 case gfxBlendColorDodge:
3734 mode = 10;
3735 break;
3736 case gfxBlendColorBurn:
3737 mode = 11;
3738 break;
3739 case gfxBlendHue:
3740 mode = 12;
3741 break;
3742 case gfxBlendSaturation:
3743 mode = 13;
3744 break;
3745 case gfxBlendColor:
3746 mode = 14;
3747 break;
3748 case gfxBlendLuminosity:
3749 mode = 15;
3750 break;
3751 }
3752 return mode;
3753 }
3754
3755 void SlaOutputDev::applyMask(PageItem *ite)
3756 {
3757 if (m_groupStack.count() != 0)
3758 {
3759 if (!m_groupStack.top().maskName.isEmpty())
3760 {
3761 ite->setPatternMask(m_groupStack.top().maskName);
3762 QPointF maskPos = m_groupStack.top().maskPos;
3763 double sx, sy, px, py, r, shx, shy;
3764 ite->maskTransform(sx, sy, px, py, r, shx, shy);
3765 ite->setMaskTransform(sx, sy, maskPos.x() - ite->xPos(), maskPos.y() - ite->yPos(), r, shx, shy);
3766 if (m_groupStack.top().alpha)
3767 {
3768 if (m_groupStack.top().inverted)
3769 ite->setMaskType(8);
3770 else
3771 ite->setMaskType(3);
3772 }
3773 else
3774 {
3775 if (m_groupStack.top().inverted)
3776 ite->setMaskType(7);
3777 else
3778 ite->setMaskType(6);
3779 }
3780 }
3781 }
3782 // Code for updating our Progressbar, needs to be called this way, as we have no
3783 // possibility to get the current fileposition.
3784 updateGUICounter++;
3785 if (updateGUICounter > 20)
3786 {
3787 qApp->processEvents();
3788 updateGUICounter = 0;
3789 }
3790 }
3791
3792 void SlaOutputDev::pushGroup(const QString& maskName, GBool forSoftMask, GBool alpha, bool inverted)
3793 {
3794 groupEntry gElements;
3795 gElements.forSoftMask = forSoftMask;
3796 gElements.alpha = alpha;
3797 gElements.inverted = inverted;
3798 gElements.maskName = maskName;
3799 m_groupStack.push(gElements);
3800 }
3801
3802 QString SlaOutputDev::UnicodeParsedString(POPPLER_CONST GooString *s1)
3803 {
3804 if ( !s1 || s1->getLength() == 0 )
3805 return QString();
3806 GBool isUnicode;
3807 int i;
3808 Unicode u;
3809 QString result;
3810 if ((s1->getChar(0) & 0xff) == 0xfe && (s1->getLength() > 1 && (s1->getChar(1) & 0xff) == 0xff))
3811 {
3812 isUnicode = gTrue;
3813 i = 2;
3814 result.reserve((s1->getLength() - 2) / 2);
3815 }
3816 else
3817 {
3818 isUnicode = gFalse;
3819 i = 0;
3820 result.reserve(s1->getLength());
3821 }
3822 while (i < s1->getLength())
3823 {
3824 if (isUnicode)
3825 {
3826 u = ((s1->getChar(i) & 0xff) << 8) | (s1->getChar(i+1) & 0xff);
3827 i += 2;
3828 }
3829 else
3830 {
3831 u = s1->getChar(i) & 0xff;
3832 ++i;
3833 }
3834 result += QChar( u );
3835 }
3836 return result;
3837 }
3838
3839 QString SlaOutputDev::UnicodeParsedString(const std::string& s1)
3840 {
3841 if (s1.length() == 0)
3842 return QString();
3843 GBool isUnicode;
3844 size_t i;
3845 Unicode u;
3846 QString result;
3847 if ((s1.at(0) & 0xff) == 0xfe && (s1.length() > 1 && (s1.at(1) & 0xff) == 0xff))
3848 {
3849 isUnicode = gTrue;
3850 i = 2;
3851 result.reserve((s1.length() - 2) / 2);
3852 }
3853 else
3854 {
3855 isUnicode = gFalse;
3856 i = 0;
3857 result.reserve(s1.length());
3858 }
3859 while (i < s1.length())
3860 {
3861 if (isUnicode)
3862 {
3863 u = ((s1.at(i) & 0xff) << 8) | (s1.at(i+1) & 0xff);
3864 i += 2;
3865 }
3866 else
3867 {
3868 u = s1.at(i) & 0xff;
3869 ++i;
3870 }
3871 // #15616: imagemagick may write unicode strings incorrectly in PDF
3872 if (u == 0)
3873 continue;
3874 result += QChar(u);
3875 }
3876 return result;
3877 }
3878
3879 bool SlaOutputDev::checkClip()
3880 {
3881 bool ret = false;
3882 if (!m_currentClipPath.isEmpty())
3883 {
3884 QRectF bbox = m_currentClipPath.boundingRect();
3885 if ((bbox.width() > 0) && (bbox.height() > 0))
3886 ret = true;
3887 }
3888 return ret;
3889 }
3890
3891 void SlaOutputDev::setItemFillAndStroke(GfxState* state, PageItem* textNode)
3892 {
3893
3894 textNode->ClipEdited = true;
3895 textNode->FrameType = 3;
3896 textNode->setLineEnd(m_lineEnd);
3897 textNode->setLineJoin(m_lineJoin);
3898 textNode->setTextFlowMode(PageItem::TextFlowDisabled);
3899
3900 int textRenderingMode = state->getRender();
3901 // Invisible or only used for clipping
3902 if (textRenderingMode == 3)
3903 return;
3904
3905 // Fill text rendering modes. See above
3906 if (textRenderingMode == 0 || textRenderingMode == 2 || textRenderingMode == 4 || textRenderingMode == 6)
3907 {
3908 m_currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &m_currFillShade);
3909 if (textNode->isTextFrame())
3910 {
3911 textNode->setFillTransparency(1.0 - (state->getFillOpacity() > state->getStrokeOpacity() ? state->getFillOpacity() : state->getStrokeOpacity())); //fill colour sets the background colour for the frame not the fill colour fore the text
3912 textNode->setLineTransparency(1.0); // this sets the transparency of the textbox border and we don't want to see it
3913 textNode->setFillColor(CommonStrings::None);
3914 textNode->setLineColor(CommonStrings::None);
3915 textNode->setLineWidth(0);//line width doesn't effect drawing text, it creates a bounding box state->getTransformedLineWidth());
3916 textNode->setFillShade(m_currFillShade);
3917 }
3918 else
3919 {
3920 textNode->setFillColor(m_currColorFill);
3921 textNode->setFillShade(m_currFillShade);
3922 textNode->setFillEvenOdd(false);
3923 textNode->setFillTransparency(1.0 - state->getFillOpacity());
3924 textNode->setFillBlendmode(getBlendMode(state));
3925 }
3926 }
3927 // Stroke text rendering modes. See above
3928 if (textRenderingMode == 1 || textRenderingMode == 2 || textRenderingMode == 5 || textRenderingMode == 6)
3929 {
3930 m_currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &m_currStrokeShade);
3931 if (textNode->isTextFrame())
3932 {
3933 //fill color sets the background color for the frame not the fill color fore the text
3934 textNode->setFillTransparency(1.0 - (state->getFillOpacity() > state->getStrokeOpacity() ? state->getFillOpacity() : state->getStrokeOpacity()));
3935 textNode->setLineTransparency(1.0); // this sets the transparency of the textbox border and we don't want to see it
3936 textNode->setFillColor(CommonStrings::None); //TODO: Check if we override the stroke color with the fill color when there is a choice
3937 textNode->setLineColor(CommonStrings::None);
3938 textNode->setLineWidth(0);//line width doesn't effect drawing text, it creates a bounding box state->getTransformedLineWidth());
3939 textNode->setFillBlendmode(getBlendMode(state));
3940 textNode->setFillShade(m_currFillShade);
3941 }
3942 else
3943 {
3944 textNode->setLineColor(m_currColorStroke);
3945 textNode->setLineWidth(0);//line width doesn't effect drawing text, it creates a bounding box state->getTransformedLineWidth());
3946 textNode->setFillTransparency(1.0 - state->getFillOpacity() > state->getStrokeOpacity() ? state->getFillOpacity() : state->getStrokeOpacity());
3947 textNode->setLineTransparency(1.0); // this sets the transparency of the textbox border and we don't want to see it
3948 textNode->setLineBlendmode(getBlendMode(state));
3949 textNode->setLineShade(m_currStrokeShade);
3950 }
3951 }
3952 }
3953