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 begin : 2005
9 copyright : (C) 2005 by Franz Schmid
10 email : Franz.Schmid@altmuehlnet.de
11 copyright : (C) 2005 by Craig Bradney
12 email : cbradney@zip.com.au
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * Scribus program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24 #include "commonstrings.h"
25 #include "documentchecker.h"
26 #include "pageitem.h"
27 #include "pdf_analyzer.h"
28 #include "sccolor.h"
29 #include "sclayer.h"
30 #include "scpage.h"
31 #include "scribusdoc.h"
32 #include "scribusstructs.h"
33 #include "text/textlayoutpainter.h"
34 #include "util.h"
35 #include "util_formats.h"
36
37 #include <QList>
38
39
40 class MissingGlyphsPainter: public TextLayoutPainter
41 {
42 errorCodes& m_itemError;
43 // const TextLayout& m_textLayout;
44
45 public:
MissingGlyphsPainter(errorCodes & itemError,const TextLayout &)46 MissingGlyphsPainter(errorCodes& itemError, const TextLayout& /*textLayout*/)
47 : m_itemError(itemError)
48 // , m_textLayout(textLayout)
49 { }
50
drawGlyph(const GlyphCluster & gc)51 void drawGlyph(const GlyphCluster& gc) override
52 {
53 if (gc.isEmpty())
54 {
55 int pos = gc.firstChar();
56 m_itemError.insert(MissingGlyph, pos);
57 }
58 }
drawGlyphOutline(const GlyphCluster & gc,bool)59 void drawGlyphOutline(const GlyphCluster& gc, bool) override
60 {
61 drawGlyph(gc);
62 }
drawLine(QPointF,QPointF)63 void drawLine(QPointF, QPointF) override { }
drawRect(QRectF)64 void drawRect(QRectF) override { }
drawObject(PageItem *)65 void drawObject(PageItem*) override { }
66 };
67
isPartFilledImageFrame(PageItem * currItem)68 bool isPartFilledImageFrame(PageItem * currItem)
69 {
70 double imageRealWidth = currItem->imageXScale() * currItem->pixm.imgInfo.lowResScale * currItem->pixm.width();
71 double imageRealHeight = currItem->imageYScale() * currItem->pixm.imgInfo.lowResScale * currItem->pixm.height();
72 // qDebug() << "X" << currItem->width() << imageRealWidth;
73 // qDebug() << "Y" << currItem->height() << imageRealHeight;
74 return ((currItem->width() - imageRealWidth) > 0.05 || (currItem->height() - imageRealHeight) > 0.05);
75 }
76
77
checkDocument(ScribusDoc * currDoc)78 bool DocumentChecker::checkDocument(ScribusDoc *currDoc)
79 {
80 const auto& checkerProfiles = currDoc->checkerProfiles();
81 if (!checkerProfiles.contains(currDoc->curCheckProfile()))
82 return false;
83 return checkDocument(currDoc, currDoc->curCheckProfile());
84 }
85
checkDocument(ScribusDoc * currDoc,const QString & checkerProfile)86 bool DocumentChecker::checkDocument(ScribusDoc *currDoc, const QString& checkerProfile)
87 {
88 const auto& checkerProfiles = currDoc->checkerProfiles();
89 if (!checkerProfiles.contains(checkerProfile))
90 return false;
91
92 struct CheckerPrefs checkerSettings;
93 checkerSettings = checkerProfiles[checkerProfile];
94 currDoc->pageErrors.clear();
95 currDoc->docItemErrors.clear();
96 currDoc->masterItemErrors.clear();
97 currDoc->docLayerErrors.clear();
98
99 checkPages(currDoc, checkerSettings);
100 checkLayers(currDoc, checkerSettings);
101 //update all marks references and check if that changes anything in doc
102 currDoc->setNotesChanged(currDoc->updateMarks(true));
103
104 checkItems(currDoc, checkerSettings);
105
106 return (currDoc->hasPreflightErrors());
107 }
108
checkPages(ScribusDoc * currDoc,struct CheckerPrefs checkerSettings)109 void DocumentChecker::checkPages(ScribusDoc *currDoc, struct CheckerPrefs checkerSettings)
110 {
111 errorCodes pageError;
112 for (int i=0; i < currDoc->DocPages.count(); ++i )
113 {
114 pageError.clear();
115 if (checkerSettings.checkAppliedMasterDifferentSide)
116 {
117 bool error = false;
118 int masterPageNumber = -1, masterPageLocation = -1;
119 PageLocation pageLoc = currDoc->locationOfPage(i);
120 masterPageNumber = currDoc->MasterNames.value(currDoc->DocPages[i]->masterPageName(), -1);
121 if (masterPageNumber >= 0)
122 masterPageLocation = currDoc->MasterPages[masterPageNumber]->LeftPg;
123 if (currDoc->pagePositioning() == singlePage)
124 {
125 if ((pageLoc != LeftPage) || (masterPageLocation != 0))
126 error = true;
127 }
128 else
129 {
130 if (pageLoc==LeftPage && masterPageLocation==1)
131 error = false;
132 else if (pageLoc==RightPage && masterPageLocation==0)
133 error = false;
134 else if (pageLoc==MiddlePage && masterPageLocation==2)
135 error = false;
136 else
137 error = true;
138 }
139 if (error)
140 pageError.insert(AppliedMasterDifferentSide, 0);
141 }
142 if (pageError.count() != 0)
143 currDoc->pageErrors.insert(i, pageError);
144 }
145 }
146
checkLayers(ScribusDoc * currDoc,struct CheckerPrefs checkerSettings)147 void DocumentChecker::checkLayers(ScribusDoc *currDoc, struct CheckerPrefs checkerSettings)
148 {
149 errorCodes layerError;
150 int Lnr;
151 ScLayer ll;
152 ll.ID = 0;
153 Lnr = 0;
154 uint layerCount= currDoc->layerCount();
155 for (uint la = 0; la < layerCount; ++la)
156 {
157 layerError.clear();
158 currDoc->Layers.levelToLayer(ll, Lnr);
159 if ((ll.isViewable != ll.isPrintable) && (checkerSettings.checkOffConflictLayers))
160 layerError.insert(OffConflictLayers, 0);
161 if ((!ll.isViewable) && (checkerSettings.ignoreOffLayers))
162 continue;
163 if ((!ll.isPrintable) && (checkerSettings.ignoreOffLayers))
164 continue;
165 if ((ll.transparency != 1.0) && (checkerSettings.checkTransparency))
166 layerError.insert(Transparency, 0);
167 if ((ll.blendMode != 0) && (checkerSettings.checkTransparency))
168 layerError.insert(BlendMode, 1);
169 Lnr++;
170 if (layerError.count() != 0)
171 currDoc->docLayerErrors.insert(ll.ID, layerError);
172 }
173 }
174
checkItems(ScribusDoc * currDoc,struct CheckerPrefs checkerSettings)175 void DocumentChecker::checkItems(ScribusDoc *currDoc, struct CheckerPrefs checkerSettings)
176 {
177 errorCodes itemError;
178
179 QList<PageItem*> allItems;
180 uint masterItemsCount = currDoc->MasterItems.count();
181 for (uint i = 0; i < masterItemsCount; ++i)
182 {
183 PageItem* currItem = currDoc->MasterItems.at(i);
184 if (currItem->isGroup())
185 allItems = currItem->getAllChildren();
186 else
187 allItems.append(currItem);
188 for (int ii = 0; ii < allItems.count(); ii++)
189 {
190 currItem = allItems.at(ii);
191 if (!currItem->printEnabled())
192 continue;
193 if (!(currDoc->layerPrintable(currItem->m_layerID)) && (checkerSettings.ignoreOffLayers))
194 continue;
195 itemError.clear();
196 if (((currItem->isAnnotation()) || (currItem->isBookmark)) && (checkerSettings.checkAnnotations))
197 itemError.insert(PDFAnnotField, 0);
198 if (currItem->hasSoftShadow() && checkerSettings.checkTransparency)
199 itemError.insert(Transparency, 0);
200 if ((currItem->GrType == 0) && (checkerSettings.checkTransparency))
201 {
202 if (currItem->fillColor() != CommonStrings::None)
203 {
204 if ((currItem->fillTransparency() != 0.0) || (currItem->fillBlendmode() != 0))
205 itemError.insert(Transparency, 0);
206 }
207 }
208 if ((currItem->GrType != 0) && (checkerSettings.checkTransparency))
209 {
210 if (currItem->GrType == Gradient_4Colors)
211 {
212 if (currItem->GrCol1transp != 1.0)
213 itemError.insert(Transparency, 0);
214 else if (currItem->GrCol2transp != 1.0)
215 itemError.insert(Transparency, 0);
216 else if (currItem->GrCol3transp != 1.0)
217 itemError.insert(Transparency, 0);
218 else if (currItem->GrCol4transp != 1.0)
219 itemError.insert(Transparency, 0);
220 }
221 else if (currItem->GrType == Gradient_Mesh)
222 {
223 for (int grow = 0; grow < currItem->meshGradientArray.count(); grow++)
224 {
225 for (int gcol = 0; gcol < currItem->meshGradientArray[grow].count(); gcol++)
226 {
227 if (currItem->meshGradientArray[grow][gcol].transparency != 1.0)
228 itemError.insert(Transparency, 0);
229 }
230 }
231 }
232 else if (currItem->GrType == Gradient_PatchMesh)
233 {
234 for (int grow = 0; grow < currItem->meshGradientPatches.count(); grow++)
235 {
236 meshGradientPatch patch = currItem->meshGradientPatches[grow];
237 if (currItem->meshGradientPatches[grow].TL.transparency != 1.0)
238 itemError.insert(Transparency, 0);
239 if (currItem->meshGradientPatches[grow].TR.transparency != 1.0)
240 itemError.insert(Transparency, 0);
241 if (currItem->meshGradientPatches[grow].BR.transparency != 1.0)
242 itemError.insert(Transparency, 0);
243 if (currItem->meshGradientPatches[grow].BL.transparency != 1.0)
244 itemError.insert(Transparency, 0);
245 }
246 }
247 else
248 {
249 QList<VColorStop*> colorStops = currItem->fill_gradient.colorStops();
250 for (int offset = 0 ; offset < colorStops.count() ; offset++)
251 {
252 if (colorStops[offset]->opacity != 1.0)
253 {
254 itemError.insert(Transparency, 0);
255 break;
256 }
257 }
258 }
259 }
260 if ((currItem->GrTypeStroke == 0) && (checkerSettings.checkTransparency))
261 {
262 if ((currItem->lineColor() != CommonStrings::None) || !currItem->NamedLStyle.isEmpty())
263 {
264 if ((currItem->lineTransparency() != 0.0) || (currItem->lineBlendmode() != 0))
265 itemError.insert(Transparency, 0);
266 }
267 }
268 if ((currItem->GrTypeStroke != 0) && (checkerSettings.checkTransparency))
269 {
270 QList<VColorStop*> colorStops = currItem->stroke_gradient.colorStops();
271 for (int offset = 0 ; offset < colorStops.count() ; offset++)
272 {
273 if (colorStops[offset]->opacity != 1.0)
274 {
275 itemError.insert(Transparency, 0);
276 break;
277 }
278 }
279 }
280 if ((currItem->GrMask > 0) && (checkerSettings.checkTransparency))
281 itemError.insert(Transparency, 0);
282 if ((currItem->OwnPage == -1) && (checkerSettings.checkOrphans))
283 itemError.insert(ObjectNotOnPage, 0);
284 if (currItem->isImageFrame() && !currItem->isOSGFrame())
285 {
286
287 // check image vs. frame sizes
288 if (checkerSettings.checkPartFilledImageFrames && isPartFilledImageFrame(currItem))
289 {
290 itemError.insert(PartFilledImageFrame, 0);
291 }
292
293 if ((!currItem->imageIsAvailable) && (checkerSettings.checkPictures))
294 itemError.insert(MissingImage, 0);
295 else
296 {
297 if (currItem->imageIsAvailable)
298 {
299 if (checkerSettings.checkTransparency && currItem->pixm.hasSmoothAlpha())
300 itemError.insert(Transparency, 0);
301 }
302 if (((qRound(72.0 / currItem->imageXScale()) < checkerSettings.minResolution) || (qRound(72.0 / currItem->imageYScale()) < checkerSettings.minResolution))
303 && (currItem->isRaster) && (checkerSettings.checkResolution))
304 itemError.insert(ImageDPITooLow, 0);
305 if (((qRound(72.0 / currItem->imageXScale()) > checkerSettings.maxResolution) || (qRound(72.0 / currItem->imageYScale()) > checkerSettings.maxResolution))
306 && (currItem->isRaster) && (checkerSettings.checkResolution))
307 itemError.insert(ImageDPITooHigh, 0);
308 QFileInfo fi = QFileInfo(currItem->Pfile);
309 QString ext = fi.suffix().toLower();
310 if (extensionIndicatesPDF(ext) && (checkerSettings.checkRasterPDF))
311 itemError.insert(PlacedPDF, 0);
312 if ((ext == "gif") && (checkerSettings.checkForGIF))
313 itemError.insert(ImageIsGIF, 0);
314
315 if (extensionIndicatesPDF(ext))
316 {
317 PDFAnalyzer analyst(currItem->Pfile);
318 QList<PDFColorSpace> usedColorSpaces;
319 bool hasTransparency = false;
320 QList<PDFFont> usedFonts;
321 int pageNum = qMin(qMax(1, currItem->pixm.imgInfo.actualPageNumber), currItem->pixm.imgInfo.numberOfPages) - 1;
322 QList<PDFImage> imgs;
323 bool succeeded = analyst.inspectPDF(pageNum, usedColorSpaces, hasTransparency, usedFonts, imgs);
324 if (succeeded)
325 {
326 if (checkerSettings.checkNotCMYKOrSpot || checkerSettings.checkDeviceColorsAndOutputIntent)
327 {
328 eColorSpaceType currPrintProfCS = ColorSpace_Unknown;
329 if (currDoc->HasCMS)
330 {
331 ScColorProfile printerProf = currDoc->DocPrinterProf;
332 currPrintProfCS = printerProf.colorSpace();
333 }
334 if (checkerSettings.checkNotCMYKOrSpot)
335 {
336 for (int i=0; i<usedColorSpaces.size(); ++i)
337 {
338 if (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_ICCBased || usedColorSpaces[i] == CS_CalGray
339 || usedColorSpaces[i] == CS_CalRGB || usedColorSpaces[i] == CS_Lab)
340 {
341 itemError.insert(NotCMYKOrSpot, 0);
342 break;
343 }
344 }
345 }
346 if (checkerSettings.checkDeviceColorsAndOutputIntent && currDoc->HasCMS)
347 {
348 for (int i=0; i<usedColorSpaces.size(); ++i)
349 {
350 if (currPrintProfCS == ColorSpace_Cmyk && (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_DeviceGray))
351 {
352 itemError.insert(DeviceColorsAndOutputIntent, 0);
353 break;
354 }
355 if (currPrintProfCS == ColorSpace_Rgb && (usedColorSpaces[i] == CS_DeviceCMYK || usedColorSpaces[i] == CS_DeviceGray))
356 {
357 itemError.insert(DeviceColorsAndOutputIntent, 0);
358 break;
359 }
360 }
361 }
362 }
363 if (checkerSettings.checkTransparency && hasTransparency)
364 itemError.insert(Transparency, 0);
365 if (checkerSettings.checkFontNotEmbedded || checkerSettings.checkFontIsOpenType)
366 {
367 for (int i=0; i<usedFonts.size(); ++i)
368 {
369 PDFFont currentFont = usedFonts[i];
370 if (!currentFont.isEmbedded && checkerSettings.checkFontNotEmbedded)
371 itemError.insert(FontNotEmbedded, 0);
372 if (currentFont.isEmbedded && currentFont.isOpenType && checkerSettings.checkFontIsOpenType)
373 itemError.insert(EmbeddedFontIsOpenType, 0);
374 }
375 }
376 if (checkerSettings.checkResolution)
377 {
378 for (int i=0; i<imgs.size(); ++i)
379 {
380 if ((imgs[i].dpiX < checkerSettings.minResolution) || (imgs[i].dpiY < checkerSettings.minResolution))
381 itemError.insert(ImageDPITooLow, 0);
382 if ((imgs[i].dpiX > checkerSettings.maxResolution) || (imgs[i].dpiY > checkerSettings.maxResolution))
383 itemError.insert(ImageDPITooHigh, 0);
384 }
385 }
386 }
387 }
388 }
389 }
390 if ((currItem->isTextFrame()) || (currItem->isPathText()))
391 {
392 if ( currItem->frameOverflows() && (checkerSettings.checkOverflow) && (!((currItem->isAnnotation()) && ((currItem->annotation().Type() == Annotation::Combobox) || (currItem->annotation().Type() == Annotation::Listbox)))))
393 itemError.insert(TextOverflow, 0);
394
395 if (checkerSettings.checkEmptyTextFrames && (currItem->itemText.length() == 0 || currItem->frameUnderflows()))
396 {
397 bool isEmptyAnnotation = (currItem->isAnnotation() &&
398 ((currItem->annotation().Type() == Annotation::Link) ||
399 (currItem->annotation().Type() == Annotation::Checkbox) ||
400 (currItem->annotation().Type() == Annotation::RadioButton)));
401 if (!isEmptyAnnotation)
402 itemError.insert(EmptyTextFrame, 0);
403 }
404
405 if (currItem->isAnnotation())
406 {
407 ScFace::FontFormat fformat = currItem->itemText.defaultStyle().charStyle().font().format();
408 if (!(fformat == ScFace::SFNT || fformat == ScFace::TTCF))
409 itemError.insert(WrongFontInAnnotation, 0);
410 }
411
412 if (checkerSettings.checkGlyphs)
413 {
414 if (currItem->invalid)
415 currItem->layout();
416 MissingGlyphsPainter p(itemError, currItem->textLayout);
417 currItem->textLayout.render(&p);
418 }
419 }
420 if (((currItem->fillColor() != CommonStrings::None) || (currItem->lineColor() != CommonStrings::None)) && (checkerSettings.checkNotCMYKOrSpot))
421 {
422 bool rgbUsed = false;
423 if ((currItem->fillColor() != CommonStrings::None))
424 {
425 ScColor tmpC = currDoc->PageColors[currItem->fillColor()];
426 if (tmpC.getColorModel() == colorModelRGB)
427 rgbUsed = true;
428 }
429 if ((currItem->lineColor() != CommonStrings::None))
430 {
431 ScColor tmpC = currDoc->PageColors[currItem->lineColor()];
432 if (tmpC.getColorModel() == colorModelRGB)
433 rgbUsed = true;
434 }
435 if (rgbUsed)
436 itemError.insert(NotCMYKOrSpot, 0);
437 }
438 if (itemError.count() != 0)
439 currDoc->masterItemErrors.insert(currItem, itemError);
440 }
441 allItems.clear();
442 }
443 allItems.clear();
444 uint docItemsCount = currDoc->DocItems.count();
445 for (uint i = 0; i < docItemsCount; ++i)
446 {
447 PageItem* currItem = currDoc->DocItems.at(i);
448 if (currItem->isGroup())
449 allItems = currItem->getAllChildren();
450 else
451 allItems.append(currItem);
452 for (int ii = 0; ii < allItems.count(); ii++)
453 {
454 currItem = allItems.at(ii);
455 if (!currItem->printEnabled())
456 continue;
457 if (!(currDoc->layerPrintable(currItem->m_layerID)) && (checkerSettings.ignoreOffLayers))
458 continue;
459 itemError.clear();
460 if (currItem->hasSoftShadow() && checkerSettings.checkTransparency)
461 itemError.insert(Transparency, 0);
462 if ((currItem->GrType == 0) && (checkerSettings.checkTransparency))
463 {
464 if (currItem->fillColor() != CommonStrings::None)
465 {
466 if ((currItem->fillTransparency() != 0.0) || (currItem->fillBlendmode() != 0))
467 itemError.insert(Transparency, 0);
468 }
469 }
470 if ((currItem->GrType != 0) && (checkerSettings.checkTransparency))
471 {
472 if (currItem->GrType == Gradient_4Colors)
473 {
474 if (currItem->GrCol1transp != 1.0)
475 itemError.insert(Transparency, 0);
476 else if (currItem->GrCol2transp != 1.0)
477 itemError.insert(Transparency, 0);
478 else if (currItem->GrCol3transp != 1.0)
479 itemError.insert(Transparency, 0);
480 else if (currItem->GrCol4transp != 1.0)
481 itemError.insert(Transparency, 0);
482 }
483 else if (currItem->GrType == Gradient_Mesh)
484 {
485 for (int grow = 0; grow < currItem->meshGradientArray.count(); grow++)
486 {
487 for (int gcol = 0; gcol < currItem->meshGradientArray[grow].count(); gcol++)
488 {
489 if (currItem->meshGradientArray[grow][gcol].transparency != 1.0)
490 itemError.insert(Transparency, 0);
491 }
492 }
493 }
494 else if (currItem->GrType == Gradient_PatchMesh)
495 {
496 for (int grow = 0; grow < currItem->meshGradientPatches.count(); grow++)
497 {
498 meshGradientPatch patch = currItem->meshGradientPatches[grow];
499 if (currItem->meshGradientPatches[grow].TL.transparency != 1.0)
500 itemError.insert(Transparency, 0);
501 if (currItem->meshGradientPatches[grow].TR.transparency != 1.0)
502 itemError.insert(Transparency, 0);
503 if (currItem->meshGradientPatches[grow].BR.transparency != 1.0)
504 itemError.insert(Transparency, 0);
505 if (currItem->meshGradientPatches[grow].BL.transparency != 1.0)
506 itemError.insert(Transparency, 0);
507 }
508 }
509 else
510 {
511 QList<VColorStop*> colorStops = currItem->fill_gradient.colorStops();
512 for (int offset = 0 ; offset < colorStops.count() ; offset++)
513 {
514 if (colorStops[offset]->opacity != 1.0)
515 {
516 itemError.insert(Transparency, 0);
517 break;
518 }
519 }
520 }
521 }
522 if ((currItem->GrTypeStroke == 0) && (checkerSettings.checkTransparency))
523 {
524 if ((currItem->lineColor() != CommonStrings::None) || !currItem->NamedLStyle.isEmpty())
525 {
526 if ((currItem->lineTransparency() != 0.0) || (currItem->lineBlendmode() != 0))
527 itemError.insert(Transparency, 0);
528 }
529 }
530 if ((currItem->GrTypeStroke != 0) && (checkerSettings.checkTransparency))
531 {
532 QList<VColorStop*> colorStops = currItem->stroke_gradient.colorStops();
533 for (int offset = 0 ; offset < colorStops.count() ; offset++)
534 {
535 if (colorStops[offset]->opacity != 1.0)
536 {
537 itemError.insert(Transparency, 0);
538 break;
539 }
540 }
541 }
542 if ((currItem->GrMask > 0) && (checkerSettings.checkTransparency))
543 itemError.insert(Transparency, 0);
544 if (((currItem->isAnnotation()) || (currItem->isBookmark)) && (checkerSettings.checkAnnotations))
545 itemError.insert(PDFAnnotField, 0);
546 if ((currItem->OwnPage == -1) && (checkerSettings.checkOrphans))
547 itemError.insert(ObjectNotOnPage, 0);
548 if (currItem->isImageFrame() && !currItem->isOSGFrame())
549 {
550
551 // check image vs. frame sizes
552 if (checkerSettings.checkPartFilledImageFrames && isPartFilledImageFrame(currItem))
553 {
554 itemError.insert(PartFilledImageFrame, 0);
555 }
556
557 if ((!currItem->imageIsAvailable) && (checkerSettings.checkPictures))
558 itemError.insert(MissingImage, 0);
559 else
560 {
561 if (currItem->imageIsAvailable)
562 {
563 if (checkerSettings.checkTransparency && currItem->pixm.hasSmoothAlpha())
564 itemError.insert(Transparency, 0);
565 }
566 if (((qRound(72.0 / currItem->imageXScale()) < checkerSettings.minResolution) || (qRound(72.0 / currItem->imageYScale()) < checkerSettings.minResolution))
567 && (currItem->isRaster) && (checkerSettings.checkResolution))
568 itemError.insert(ImageDPITooLow, 0);
569 if (((qRound(72.0 / currItem->imageXScale()) > checkerSettings.maxResolution) || (qRound(72.0 / currItem->imageYScale()) > checkerSettings.maxResolution))
570 && (currItem->isRaster) && (checkerSettings.checkResolution))
571 itemError.insert(ImageDPITooHigh, 0);
572 QFileInfo fi = QFileInfo(currItem->Pfile);
573 QString ext = fi.suffix().toLower();
574 if (extensionIndicatesPDF(ext) && (checkerSettings.checkRasterPDF))
575 itemError.insert(PlacedPDF, 0);
576 if ((ext == "gif") && (checkerSettings.checkForGIF))
577 itemError.insert(ImageIsGIF, 0);
578
579 if (extensionIndicatesPDF(ext))
580 {
581 PDFAnalyzer analyst(currItem->Pfile);
582 QList<PDFColorSpace> usedColorSpaces;
583 bool hasTransparency = false;
584 QList<PDFFont> usedFonts;
585 int pageNum = qMin(qMax(1, currItem->pixm.imgInfo.actualPageNumber), currItem->pixm.imgInfo.numberOfPages) - 1;
586 QList<PDFImage> imgs;
587 bool succeeded = analyst.inspectPDF(pageNum, usedColorSpaces, hasTransparency, usedFonts, imgs);
588 if (succeeded)
589 {
590 if (checkerSettings.checkNotCMYKOrSpot || checkerSettings.checkDeviceColorsAndOutputIntent)
591 {
592 int currPrintProfCS = -1;
593 if (currDoc->HasCMS)
594 {
595 ScColorProfile printerProf = currDoc->DocPrinterProf;
596 currPrintProfCS = static_cast<int>(printerProf.colorSpace());
597 }
598 if (checkerSettings.checkNotCMYKOrSpot)
599 {
600 for (int i=0; i<usedColorSpaces.size(); ++i)
601 {
602 if (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_ICCBased || usedColorSpaces[i] == CS_CalGray
603 || usedColorSpaces[i] == CS_CalRGB || usedColorSpaces[i] == CS_Lab)
604 {
605 itemError.insert(NotCMYKOrSpot, 0);
606 break;
607 }
608 }
609 }
610 if (checkerSettings.checkDeviceColorsAndOutputIntent && currDoc->HasCMS)
611 {
612 for (int i=0; i<usedColorSpaces.size(); ++i)
613 {
614 if (currPrintProfCS == ColorSpace_Cmyk && (usedColorSpaces[i] == CS_DeviceRGB || usedColorSpaces[i] == CS_DeviceGray))
615 {
616 itemError.insert(DeviceColorsAndOutputIntent, 0);
617 break;
618 }
619 if (currPrintProfCS == ColorSpace_Rgb && (usedColorSpaces[i] == CS_DeviceCMYK || usedColorSpaces[i] == CS_DeviceGray))
620 {
621 itemError.insert(DeviceColorsAndOutputIntent, 0);
622 break;
623 }
624 }
625 }
626 }
627 if (checkerSettings.checkTransparency && hasTransparency)
628 itemError.insert(Transparency, 0);
629 if (checkerSettings.checkFontNotEmbedded || checkerSettings.checkFontIsOpenType)
630 {
631 for (int i=0; i<usedFonts.size(); ++i)
632 {
633 PDFFont currentFont = usedFonts[i];
634 if (!currentFont.isEmbedded && checkerSettings.checkFontNotEmbedded)
635 itemError.insert(FontNotEmbedded, 0);
636 if (currentFont.isEmbedded && currentFont.isOpenType && checkerSettings.checkFontIsOpenType)
637 itemError.insert(EmbeddedFontIsOpenType, 0);
638 }
639 }
640 if (checkerSettings.checkResolution)
641 {
642 for (int i=0; i<imgs.size(); ++i)
643 {
644 if ((imgs[i].dpiX < checkerSettings.minResolution) || (imgs[i].dpiY < checkerSettings.minResolution))
645 itemError.insert(ImageDPITooLow, 0);
646 if ((imgs[i].dpiX > checkerSettings.maxResolution) || (imgs[i].dpiY > checkerSettings.maxResolution))
647 itemError.insert(ImageDPITooHigh, 0);
648 }
649 }
650 }
651 }
652 }
653 }
654 if ((currItem->isTextFrame()) || (currItem->isPathText()))
655 {
656 if ( currItem->frameOverflows() && (checkerSettings.checkOverflow) && (!((currItem->isAnnotation()) && ((currItem->annotation().Type() == Annotation::Combobox) || (currItem->annotation().Type() == Annotation::Listbox)))))
657 itemError.insert(TextOverflow, 0);
658
659 if (checkerSettings.checkEmptyTextFrames && (currItem->itemText.length()==0 || currItem->frameUnderflows()))
660 {
661 bool isEmptyAnnotation = (currItem->isAnnotation() &&
662 ((currItem->annotation().Type() == Annotation::Link) ||
663 (currItem->annotation().Type() == Annotation::Checkbox) ||
664 (currItem->annotation().Type() == Annotation::RadioButton)));
665 if (!isEmptyAnnotation)
666 itemError.insert(EmptyTextFrame, 0);
667 }
668
669 if (currItem->isAnnotation())
670 {
671 ScFace::FontFormat fformat = currItem->itemText.defaultStyle().charStyle().font().format();
672 if (!(fformat == ScFace::SFNT || fformat == ScFace::TTCF))
673 itemError.insert(WrongFontInAnnotation, 0);
674 }
675 if (checkerSettings.checkGlyphs)
676 {
677 if (currItem->invalid)
678 currItem->layout();
679 MissingGlyphsPainter p(itemError, currItem->textLayout);
680 currItem->textLayout.render(&p);
681 }
682 }
683 if (((currItem->fillColor() != CommonStrings::None) || (currItem->lineColor() != CommonStrings::None)) && (checkerSettings.checkNotCMYKOrSpot))
684 {
685 bool rgbUsed = false;
686 if ((currItem->fillColor() != CommonStrings::None))
687 {
688 ScColor tmpC = currDoc->PageColors[currItem->fillColor()];
689 if (tmpC.getColorModel() == colorModelRGB)
690 rgbUsed = true;
691 }
692 if ((currItem->lineColor() != CommonStrings::None))
693 {
694 ScColor tmpC = currDoc->PageColors[currItem->lineColor()];
695 if (tmpC.getColorModel() == colorModelRGB)
696 rgbUsed = true;
697 }
698 if (rgbUsed)
699 itemError.insert(NotCMYKOrSpot, 0);
700 }
701 if (itemError.count() != 0)
702 currDoc->docItemErrors.insert(currItem, itemError);
703 }
704 allItems.clear();
705 }
706 }
707