View Issue Details

IDProjectCategoryView StatusLast Update
0014597ScribusScripterpublic2026-02-15 19:51
ReporterJLuc Assigned Toale  
PrioritynormalSeverityfeatureReproducibilityN/A
Status acknowledgedResolutionopen 
PlatformLinuxOSUbuntuOS Version14.04
Summary0014597: [PATCH] Script command to get preflight errors or warnings
DescriptionProvide scripter a command
to get preflight errors or warnings
or to export them to a file
so as to manage them in some not interactive way
Additional InformationEither get them all according to the document preferences for preflight check
or enable the scripter function to receive a parameter being a specific preflight check option as : check image resolution / or / check text overflow ...
TagsNo tags attached.
PatchYes

Activities

ale

2025-11-26 21:55

manager   ~0053308

I'm working on a way to get the scripter to export the information from the preflight verifier to json.

JLuc

2025-12-23 11:19

developer   ~0053402

That'd be great @ale !

ale

2026-02-15 19:51

manager   ~0053496

Here is my proposal...
scripter-export-preflight.diff (9,860 bytes)   
From 3f96675c8faa0738fa41ab0bbc0e3ff73b6f5288 Mon Sep 17 00:00:00 2001
From: ale rimoldi <ale@graphicslab.org>
Date: Sun, 15 Feb 2026 20:42:00 +0100
Subject: scripter command to export preflight information


diff --git a/scribus/plugins/scriptplugin/cmddoc.cpp b/scribus/plugins/scriptplugin/cmddoc.cpp
index 00b63cd7e..ef858d963 100644
--- a/scribus/plugins/scriptplugin/cmddoc.cpp
+++ b/scribus/plugins/scriptplugin/cmddoc.cpp
@@ -6,6 +6,7 @@ for which a new license (GPL+exception) is in place.
 */
 #include "cmddoc.h"
 #include "cmdutil.h"
+#include "documentchecker.h"
 #include "documentinformation.h"
 #include "pyesstring.h"
 #include "scribuscore.h"
@@ -14,6 +15,11 @@ for which a new license (GPL+exception) is in place.
 #include "units.h"
 
 #include <QApplication>
+#include <qdebug.h>
+#include <qjsonarray.h>
+#include <qjsondocument.h>
+#include <qjsonobject.h>
+#include <qobject.h>
 
 /*
 newDocument(size, margins, orientation, firstPageNumber,
@@ -562,6 +568,172 @@ PyObject* scribus_applymasterpage(PyObject* /* self */, PyObject* args)
 	Py_RETURN_NONE;
 }
 
+PyObject* scribus_exportdocumentcheck(PyObject* /* self */, PyObject* args, PyObject* kw)
+{
+	PyESString targetFilenameArg;
+	PyESString checkProfileNameArg;
+	bool showNonPrintingLayerErrors = false;
+	char *kwargs[] = {const_cast<char*>("jsonFilename"), const_cast<char*>("checkProfile"),
+		const_cast<char*>("nonPrintingLayers"), nullptr};
+	if (!PyArg_ParseTupleAndKeywords(args, kw, "|es$esp", kwargs,
+			"utf-8", targetFilenameArg.ptr(), "utf-8", checkProfileNameArg.ptr(),
+			&showNonPrintingLayerErrors))
+		return nullptr;
+
+	if (!checkHaveDocument())
+		return nullptr;
+	const QString targetFileName(targetFilenameArg.c_str());
+	const QString checkProfileName(checkProfileNameArg.c_str());
+
+	ScribusDoc* currentDoc = ScCore->primaryMainWindow()->doc;
+
+	if (checkProfileName.isEmpty())
+		DocumentChecker::checkDocument(currentDoc);
+	else
+		DocumentChecker::checkDocument(currentDoc, checkProfileName);
+
+	// "Standard" Errors
+	// (Taken from PreflightError in scribusstruct.h)
+	QMap<PreflightError, QString> errorsList = {
+		{PreflightError::MissingGlyph, "MissingGlyph"},
+		{PreflightError::TextOverflow, "TextOverflow"},
+		{PreflightError::ObjectNotOnPage, "ObjectNotOnPage"},
+		{PreflightError::MissingImage, "MissingImage"},
+		{PreflightError::ImageDPITooLow, "ImageDPITooLow"},
+		{PreflightError::Transparency, "Transparency"},
+		{PreflightError::PDFAnnotField, "PDFAnnotField"},
+		{PreflightError::PlacedPDF, "PlacedPDF"},
+		{PreflightError::ImageDPITooHigh, "ImageDPITooHigh"},
+		{PreflightError::ImageIsGIF, "ImageIsGIF"},
+		{PreflightError::BlendMode, "BlendMode"},
+		{PreflightError::WrongFontInAnnotation, "WrongFontInAnnotation"},
+		{PreflightError::NotCMYKOrSpot, "NotCMYKOrSpot"},
+		{PreflightError::DeviceColorsAndOutputIntent, "DeviceColorsAndOutputIntent"},
+		{PreflightError::FontNotEmbedded, "FontNotEmbedded"},
+		{PreflightError::EmbeddedFontIsOpenType, "EmbeddedFontIsOpenType"},
+		{PreflightError::OffConflictLayers, "OffConflictLayers"},
+		{PreflightError::PartFilledImageFrame, "PartFilledImageFrame"},
+		{PreflightError::MarksChanged, "MarksChanged"},
+		{PreflightError::AppliedMasterDifferentSide, "AppliedMasterDifferentSide"},
+		{PreflightError::EmptyTextFrame, "EmptyTextFrame"},
+		{PreflightError::ImageHasProgressiveEncoding, "ImageHasProgressiveEncoding"},
+	};
+	// Custom Errors
+	// "DocumentModifiedAfterMarksUpdate"
+
+	QJsonObject json;
+
+	if (currentDoc->notesChanged())
+	{
+		json["marks"] = QJsonObject{{"", "DocumentModifiedAfterMarksUpdate"}};
+	}
+	else
+	{
+		json["marks"] = QJsonObject{};
+	}
+
+	QJsonArray jsonLayers;
+	for (const auto& [layerId, layerErrors]: currentDoc->docLayerErrors.asKeyValueRange())
+	{
+		for (const auto& [key, errorLevel]: layerErrors.asKeyValueRange())
+		{
+			jsonLayers.push_back(QJsonObject{{"layer", currentDoc->layerName(layerId)}, {"error", errorsList[key]}});
+		}
+	}
+	json["layers"] = jsonLayers;
+
+	QMap<int, QVector<QPair<QString, QString>>> pagesWithErrors;
+
+	for (auto [pageItem, itemError]: currentDoc->masterItemErrors.asKeyValueRange())
+	{
+		const int pageNumber = pageItem->OwnPage;
+		for (auto [errorCode, errorLevel]: itemError.asKeyValueRange())
+		{
+			if (!showNonPrintingLayerErrors && !currentDoc->layerPrintable(pageItem->m_layerID))
+				continue;
+
+			if (!pagesWithErrors.contains(pageNumber))
+				pagesWithErrors[pageNumber] = {};
+
+			pagesWithErrors[pageNumber].push_back({pageItem->itemName(), errorsList[errorCode]});
+		}
+	}
+
+	QJsonObject jsonMasterPages;
+	for (auto [pageNumber, value]: pagesWithErrors.asKeyValueRange())
+	{
+		QJsonArray pageItems;
+		for (const auto& [item, error]: value)
+		{
+			pageItems.push_back(QJsonObject{{{"item", item}, {"error", error}}});
+		}
+		jsonMasterPages[currentDoc->MasterPages.at(pageNumber)->pageName()] = pageItems;
+	}
+	json["masterPages"] = jsonMasterPages;
+
+
+	pagesWithErrors.clear();
+
+	for (auto [pageNumber, pageErrors]: currentDoc->pageErrors.asKeyValueRange())
+	{
+		pagesWithErrors[pageNumber] = {};
+
+		for (auto [errorCode, value]: pageErrors.asKeyValueRange())
+		{
+			pagesWithErrors[pageNumber].push_back({"", errorsList[errorCode]});
+		}
+	}
+	QJsonArray jsonFreeItems;
+	for (auto [pageItem, itemErrors]: currentDoc->docItemErrors.asKeyValueRange())
+	{
+		if (!showNonPrintingLayerErrors && !currentDoc->layerPrintable(pageItem->m_layerID))
+			continue;
+		const int pageNumber = pageItem->OwnPage;
+		if (!pagesWithErrors.contains(pageNumber))
+			pagesWithErrors[pageNumber] = {};
+		for (auto [errorCode, errorLevel]: itemErrors.asKeyValueRange())
+		{
+			pagesWithErrors[pageNumber].push_back({pageItem->itemName(), errorsList[errorCode]});
+		}
+		if (currentDoc->OnPage(pageItem) == -1)
+		{
+			jsonFreeItems.push_back(pageItem->itemName());
+		}
+	}
+
+	QJsonObject jsonPages;
+	for (auto [pageNumber, value]: pagesWithErrors.asKeyValueRange())
+	{
+		QJsonArray pageItems;
+		for (const auto& [item, error]: value)
+		{
+			pageItems.push_back(QJsonObject{{{"item", item}, {"error", error}}});
+		}
+		jsonPages[QString::number(pageNumber + 1)] = pageItems;
+	}
+	json["pages"] = jsonPages;
+
+	json["freeItems"] = jsonFreeItems;
+
+	currentDoc->pageErrors.clear();
+	currentDoc->docItemErrors.clear();
+	currentDoc->masterItemErrors.clear();
+	currentDoc->docLayerErrors.clear();
+
+	if (targetFileName.isEmpty())
+		return PyUnicode_FromString(QJsonDocument(json).toJson());
+
+	QFile saveFile(targetFileName);
+	if (!saveFile.open(QIODevice::WriteOnly))
+	{
+		PyErr_SetString(ScribusException, QObject::tr("Failed to open the file '%1' for writing","python error").arg(targetFileName).toUtf8().constData());
+		return nullptr;
+	}
+	saveFile.write(QJsonDocument(json).toJson());
+
+	Py_RETURN_NONE;
+}
+
 /*! HACK: this removes "warning: 'blah' defined but not used" compiler warnings
 with header files structure untouched (docstrings are kept near declarations)
 PV */
diff --git a/scribus/plugins/scriptplugin/cmddoc.h b/scribus/plugins/scriptplugin/cmddoc.h
index 8a01a35e5..6638b2a0c 100644
--- a/scribus/plugins/scriptplugin/cmddoc.h
+++ b/scribus/plugins/scriptplugin/cmddoc.h
@@ -385,6 +385,49 @@ Apply master page masterPageName on page pageNumber.\n\
 "));
 PyObject* scribus_applymasterpage(PyObject* self, PyObject* args);
 
+PyDoc_STRVAR(scribus_exportdocumentcheck__doc__,
+QT_TR_NOOP("exportDocumentCheck([jsonFilePath, checkProfile=\"\", nonPrintingLayers=False])\n\
+\n\
+Export the result of the preflight verifier into a JSON string or a JSON file.\n\
+\n\
+jsonFilePath: the path to the json file to be written. If empty, a JSON string \n\
+is returned.\n\
+checkProfileName is the name of an existing preflight verifier profile.\n\
+\n\
+The resulting JSON always has five sections:\n\
+- freeItems: a list of page items that are in no page;\n\
+- layers: a list of errors in layers;\n\
+- marks: errors relating the the marks;\n\
+- masterPages: list of erroneous page items for each master page;\n\
+- pages: list of erroneous page items for each page.\n\
+\n\
+The errors are strings, mostly names from the PreflightError enum in scribusstruct.h:\n\
+- MissingGlyph\n\
+- TextOverflow\n\
+- ObjectNotOnPage\n\
+- MissingImage\n\
+- ImageDPITooLow\n\
+- Transparency\n\
+- PDFAnnotField\n\
+- PlacedPDF\n\
+- ImageDPITooHigh\n\
+- ImageIsGIF\n\
+- BlendMode\n\
+- WrongFontInAnnotation\n\
+- NotCMYKOrSpot\n\
+- DeviceColorsAndOutputIntent\n\
+- FontNotEmbedded\n\
+- EmbeddedFontIsOpenType\n\
+- OffConflictLayers\n\
+- PartFilledImageFrame\n\
+- MarksChanged\n\
+- AppliedMasterDifferentSide\n\
+- EmptyTextFrame\n\
+- ImageHasProgressiveEncoding\n\
+- DocumentModifiedAfterMarksUpdate\n\
+"));
+PyObject* scribus_exportdocumentcheck(PyObject* self, PyObject* args, PyObject* kw);
+
 #endif
 
 
diff --git a/scribus/plugins/scriptplugin/scriptplugin.cpp b/scribus/plugins/scriptplugin/scriptplugin.cpp
index fabb7350a..bc790d097 100644
--- a/scribus/plugins/scriptplugin/scriptplugin.cpp
+++ b/scribus/plugins/scriptplugin/scriptplugin.cpp
@@ -326,6 +326,7 @@ PyMethodDef scribus_methods[] = {
 	{ "deselectAll", (PyCFunction) scribus_deselectall, METH_NOARGS, tr(scribus_deselectall__doc__)},
 	{ "docChanged", scribus_docchanged, METH_VARARGS, tr(scribus_docchanged__doc__)},
 	{ "editMasterPage", scribus_editmasterpage, METH_VARARGS, tr(scribus_editmasterpage__doc__)},
+	{ "exportDocumentCheck", (PyCFunction) scribus_exportdocumentcheck, METH_VARARGS|METH_KEYWORDS, tr(scribus_exportdocumentcheck__doc__)},
 	{ "fileDialog", (PyCFunction) scribus_filedialog, METH_VARARGS|METH_KEYWORDS, tr(scribus_filedialog__doc__)},
 	{ "fileQuit", scribus_filequit, METH_VARARGS, tr(scribus_filequit__doc__)},
 	{ "flipObject", scribus_flipobject, METH_VARARGS, tr(scribus_flipobject__doc__)},
scripter-export-preflight.diff (9,860 bytes)   

Issue History

Date Modified Username Field Change
2017-01-29 19:16 JLuc New Issue
2017-01-29 19:21 JLuc Additional Information Updated
2017-01-30 23:18 jghali Severity minor => feature
2025-11-26 21:55 ale Note Added: 0053308
2025-11-26 21:55 ale Assigned To => ale
2025-11-26 21:55 ale Status new => assigned
2025-11-26 21:55 ale Status assigned => acknowledged
2025-12-23 11:19 JLuc Note Added: 0053402
2026-02-15 19:51 ale Note Added: 0053496
2026-02-15 19:51 ale File Added: scripter-export-preflight.diff
2026-02-15 19:51 ale Summary Script command to get preflight errors or warnings => [PATCH] Script command to get preflight errors or warnings
2026-02-15 19:51 ale Patch No => Yes