PDF4QT/Pdf4QtLibCore/sources/pdfpagecontenteditorprocessor.cpp
2024-06-09 20:03:25 +02:00

793 lines
31 KiB
C++

// Copyright (C) 2023-2024 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfpagecontenteditorprocessor.h"
namespace pdf
{
PDFPageContentEditorProcessor::PDFPageContentEditorProcessor(const PDFPage* page,
const PDFDocument* document,
const PDFFontCache* fontCache,
const PDFCMS* CMS,
const PDFOptionalContentActivity* optionalContentActivity,
QTransform pagePointToDevicePointMatrix,
const PDFMeshQualitySettings& meshQualitySettings) :
BaseClass(page, document, fontCache, CMS, optionalContentActivity, pagePointToDevicePointMatrix, meshQualitySettings)
{
m_clippingPaths.push(QPainterPath());
if (auto fontDictionary = getFontDictionary())
{
m_content.setFontDictionary(*fontDictionary);
}
if (auto xObjectDictionary = getXObjectDictionary())
{
m_content.setXObjectDictionary(*xObjectDictionary);
}
}
const PDFEditedPageContent& PDFPageContentEditorProcessor::getEditedPageContent() const
{
return m_content;
}
PDFEditedPageContent PDFPageContentEditorProcessor::takeEditedPageContent()
{
return std::move(m_content);
}
void PDFPageContentEditorProcessor::performInterceptInstruction(Operator currentOperator,
ProcessOrder processOrder,
const QByteArray& operatorAsText)
{
BaseClass::performInterceptInstruction(currentOperator, processOrder, operatorAsText);
if (processOrder == ProcessOrder::BeforeOperation)
{
if (currentOperator == Operator::TextBegin && !isTextProcessing())
{
m_contentElementText.reset(new PDFEditedPageContentElementText(*getGraphicState(), getGraphicState()->getCurrentTransformationMatrix()));
}
}
else
{
if (currentOperator == Operator::TextEnd && !isTextProcessing())
{
if (m_contentElementText)
{
m_contentElementText->optimize();
if (!m_contentElementText->isEmpty())
{
m_contentElementText->setTextPath(std::move(m_textPath));
m_contentElementText->setItemsAsText(PDFEditedPageContentElementText::createItemsAsText(m_contentElementText->getState(), m_contentElementText->getItems()));
m_content.addContentElement(std::move(m_contentElementText));
}
}
m_contentElementText.reset();
m_textPath = QPainterPath();
}
}
}
void PDFPageContentEditorProcessor::performPathPainting(const QPainterPath& path, bool stroke, bool fill, bool text, Qt::FillRule fillRule)
{
BaseClass::performPathPainting(path, stroke, fill, text, fillRule);
if (path.isEmpty())
{
return;
}
if (text)
{
m_textPath.addPath(path);
}
else
{
m_content.addContentPath(*getGraphicState(), path, stroke, fill);
}
}
void PDFPageContentEditorProcessor::performUpdateGraphicsState(const PDFPageContentProcessorState& state)
{
BaseClass::performUpdateGraphicsState(state);
if (isTextProcessing() && m_contentElementText)
{
PDFEditedPageContentElementText::Item item;
item.isUpdateGraphicState = true;
item.state = state;
m_contentElementText->addItem(item);
}
}
void PDFPageContentEditorProcessor::performProcessTextSequence(const TextSequence& textSequence, ProcessOrder order)
{
BaseClass::performProcessTextSequence(textSequence, order);
if (order == ProcessOrder::BeforeOperation)
{
PDFEditedPageContentElementText::Item item;
item.isText = true;
item.textSequence = textSequence;
m_contentElementText->addItem(item);
}
}
bool PDFPageContentEditorProcessor::performOriginalImagePainting(const PDFImage& image, const PDFStream* stream)
{
BaseClass::performOriginalImagePainting(image, stream);
PDFObject imageObject = PDFObject::createStream(std::make_shared<PDFStream>(*stream));
m_content.addContentImage(*getGraphicState(), std::move(imageObject), QImage());
return false;
}
void PDFPageContentEditorProcessor::performImagePainting(const QImage& image)
{
BaseClass::performImagePainting(image);
PDFEditedPageContentElement* backElement = m_content.getBackElement();
Q_ASSERT(backElement);
PDFEditedPageContentElementImage* imageElement = backElement->asImage();
imageElement->setImage(image);
}
void PDFPageContentEditorProcessor::performSaveGraphicState(ProcessOrder order)
{
BaseClass::performSaveGraphicState(order);
if (order == ProcessOrder::BeforeOperation)
{
m_clippingPaths.push(m_clippingPaths.top());
}
}
void PDFPageContentEditorProcessor::performRestoreGraphicState(ProcessOrder order)
{
BaseClass::performRestoreGraphicState(order);
if (order == ProcessOrder::AfterOperation)
{
m_clippingPaths.pop();
}
}
void PDFPageContentEditorProcessor::performClipping(const QPainterPath& path, Qt::FillRule fillRule)
{
BaseClass::performClipping(path, fillRule);
if (m_clippingPaths.top().isEmpty())
{
m_clippingPaths.top() = path;
}
else
{
m_clippingPaths.top() = m_clippingPaths.top().intersected(path);
}
}
bool PDFPageContentEditorProcessor::isContentKindSuppressed(ContentKind kind) const
{
switch (kind)
{
case ContentKind::Shading:
case ContentKind::Tiling:
return true;
default:
break;
}
return false;
}
QString PDFEditedPageContent::getOperatorToString(PDFPageContentProcessor::Operator operatorValue)
{
switch (operatorValue)
{
case pdf::PDFPageContentProcessor::Operator::SetLineWidth:
return "set_line_width";
case pdf::PDFPageContentProcessor::Operator::SetLineCap:
return "set_line_cap";
case pdf::PDFPageContentProcessor::Operator::SetLineJoin:
return "set_line_join";
case pdf::PDFPageContentProcessor::Operator::SetMitterLimit:
return "set_mitter_limit";
case pdf::PDFPageContentProcessor::Operator::SetLineDashPattern:
return "set_line_dash_pattern";
case pdf::PDFPageContentProcessor::Operator::SetRenderingIntent:
return "set_rendering_intent";
case pdf::PDFPageContentProcessor::Operator::SetFlatness:
return "set_flatness";
case pdf::PDFPageContentProcessor::Operator::SetGraphicState:
return "set_graphic_state";
case pdf::PDFPageContentProcessor::Operator::SaveGraphicState:
return "save";
case pdf::PDFPageContentProcessor::Operator::RestoreGraphicState:
return "restore";
case pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix:
return "set_cm";
case pdf::PDFPageContentProcessor::Operator::MoveCurrentPoint:
return "move_to";
case pdf::PDFPageContentProcessor::Operator::LineTo:
return "line_to";
case pdf::PDFPageContentProcessor::Operator::Bezier123To:
return "cubic123_to";
case pdf::PDFPageContentProcessor::Operator::Bezier23To:
return "cubic23_to";
case pdf::PDFPageContentProcessor::Operator::Bezier13To:
return "cubic13_to";
case pdf::PDFPageContentProcessor::Operator::EndSubpath:
return "close_path";
case pdf::PDFPageContentProcessor::Operator::Rectangle:
return "rect";
case pdf::PDFPageContentProcessor::Operator::PathStroke:
return "path_stroke";
case pdf::PDFPageContentProcessor::Operator::PathCloseStroke:
return "path_close_and_stroke";
case pdf::PDFPageContentProcessor::Operator::PathFillWinding:
return "path_fill_winding";
case pdf::PDFPageContentProcessor::Operator::PathFillWinding2:
return "path_fill_winding";
case pdf::PDFPageContentProcessor::Operator::PathFillEvenOdd:
return "path_fill_even_odd";
case pdf::PDFPageContentProcessor::Operator::PathFillStrokeWinding:
return "path_fill_stroke_winding";
case pdf::PDFPageContentProcessor::Operator::PathFillStrokeEvenOdd:
return "path_fill_stroke_even_odd";
case pdf::PDFPageContentProcessor::Operator::PathCloseFillStrokeWinding:
return "path_close_fill_stroke_winding";
case pdf::PDFPageContentProcessor::Operator::PathCloseFillStrokeEvenOdd:
return "path_close_fill_stroke_even_odd";
case pdf::PDFPageContentProcessor::Operator::PathClear:
return "path_clear";
case pdf::PDFPageContentProcessor::Operator::ClipWinding:
return "clip_winding";
case pdf::PDFPageContentProcessor::Operator::ClipEvenOdd:
return "clip_even_odd";
case pdf::PDFPageContentProcessor::Operator::TextBegin:
return "text_begin";
case pdf::PDFPageContentProcessor::Operator::TextEnd:
return "text_end";
case pdf::PDFPageContentProcessor::Operator::TextSetCharacterSpacing:
return "set_char_spacing";
case pdf::PDFPageContentProcessor::Operator::TextSetWordSpacing:
return "set_word_spacing";
case pdf::PDFPageContentProcessor::Operator::TextSetHorizontalScale:
return "set_hor_scale";
case pdf::PDFPageContentProcessor::Operator::TextSetLeading:
return "set_leading";
case pdf::PDFPageContentProcessor::Operator::TextSetFontAndFontSize:
return "set_font";
case pdf::PDFPageContentProcessor::Operator::TextSetRenderMode:
return "set_text_render_mode";
case pdf::PDFPageContentProcessor::Operator::TextSetRise:
return "set_text_rise";
case pdf::PDFPageContentProcessor::Operator::TextMoveByOffset:
return "text_move_by_offset";
case pdf::PDFPageContentProcessor::Operator::TextSetLeadingAndMoveByOffset:
return "text_set_leading_and_move_by_offset";
case pdf::PDFPageContentProcessor::Operator::TextSetMatrix:
return "text_set_matrix";
case pdf::PDFPageContentProcessor::Operator::TextMoveByLeading:
return "text_move_by_leading";
case pdf::PDFPageContentProcessor::Operator::TextShowTextString:
return "text_show_string";
case pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing:
return "text_show_string_with_spacing";
case pdf::PDFPageContentProcessor::Operator::TextNextLineShowText:
return "text_next_line_and_show_text";
case pdf::PDFPageContentProcessor::Operator::TextSetSpacingAndShowText:
return "text_set_spacing_and_show_text";
case pdf::PDFPageContentProcessor::Operator::Type3FontSetOffset:
return "text_t3_set_offset";
case pdf::PDFPageContentProcessor::Operator::Type3FontSetOffsetAndBB:
return "text_t3_set_offset_and_bb";
case pdf::PDFPageContentProcessor::Operator::ColorSetStrokingColorSpace:
return "set_stroke_color_space";
case pdf::PDFPageContentProcessor::Operator::ColorSetFillingColorSpace:
return "set_filling_color_space";
case pdf::PDFPageContentProcessor::Operator::ColorSetStrokingColor:
return "set_stroke_color";
case pdf::PDFPageContentProcessor::Operator::ColorSetStrokingColorN:
return "set_stroke_color_n";
case pdf::PDFPageContentProcessor::Operator::ColorSetFillingColor:
return "set_filling_color";
case pdf::PDFPageContentProcessor::Operator::ColorSetFillingColorN:
return "set_filling_color_n";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceGrayStroking:
return "set_stroke_gray_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceGrayFilling:
return "set_filling_gray_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceRGBStroking:
return "set_stroke_rgb_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceRGBFilling:
return "set_filling_rgb_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceCMYKStroking:
return "set_stroke_cmyk_cs";
case pdf::PDFPageContentProcessor::Operator::ColorSetDeviceCMYKFilling:
return "set_filling_cmyk_cs";
case pdf::PDFPageContentProcessor::Operator::ShadingPaintShape:
return "shading_paint";
case pdf::PDFPageContentProcessor::Operator::InlineImageBegin:
return "ib";
case pdf::PDFPageContentProcessor::Operator::InlineImageData:
return "id";
case pdf::PDFPageContentProcessor::Operator::InlineImageEnd:
return "ie";
case pdf::PDFPageContentProcessor::Operator::PaintXObject:
return "paint_object";
case pdf::PDFPageContentProcessor::Operator::MarkedContentPoint:
return "mc_point";
case pdf::PDFPageContentProcessor::Operator::MarkedContentPointWithProperties:
return "mc_point_prop";
case pdf::PDFPageContentProcessor::Operator::MarkedContentBegin:
return "mc_begin";
case pdf::PDFPageContentProcessor::Operator::MarkedContentBeginWithProperties:
return "mc_begin_prop";
case pdf::PDFPageContentProcessor::Operator::MarkedContentEnd:
return "mc_end";
case pdf::PDFPageContentProcessor::Operator::CompatibilityBegin:
return "compat_begin";
case pdf::PDFPageContentProcessor::Operator::CompatibilityEnd:
return "compat_end";
default:
break;
}
return QString();
}
QString PDFEditedPageContent::getOperandName(PDFPageContentProcessor::Operator operatorValue, int operandIndex)
{
static const std::map<std::pair<PDFPageContentProcessor::Operator, int>, QString> operands =
{
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetLineWidth, 0), "lineWidth" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetLineCap, 0), "lineCap" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetLineJoin, 0), "lineJoin" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetMitterLimit, 0), "mitterLimit" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetRenderingIntent, 0), "renderingIntent" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetFlatness, 0), "flatness" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::SetGraphicState, 0), "graphicState" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 0), "a" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 1), "b" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 2), "c" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 3), "d" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 4), "e" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::AdjustCurrentTransformationMatrix, 5), "f" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::MoveCurrentPoint, 0), "x" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::MoveCurrentPoint, 1), "y" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::LineTo, 0), "x" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::LineTo, 1), "y" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 0), "x1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 1), "y1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 2), "x2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 3), "y2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 4), "x3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier123To, 5), "y3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 0), "x2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 1), "y2" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 2), "x3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier23To, 3), "y3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 0), "x1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 1), "y1" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 2), "x3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Bezier13To, 3), "y3" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 0), "x" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 1), "y" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 2), "width" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::Rectangle, 3), "height" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetCharacterSpacing, 0), "charSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetWordSpacing, 0), "wordSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetHorizontalScale, 0), "scale" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetLeading, 0), "leading" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetFontAndFontSize, 0), "font" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetFontAndFontSize, 1), "fontSize" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetRenderMode, 0), "renderMode" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetRise, 0), "rise" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextMoveByOffset, 0), "tx" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextMoveByOffset, 1), "ty" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetLeadingAndMoveByOffset, 0), "tx" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetLeadingAndMoveByOffset, 1), "ty" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 0), "a" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 1), "b" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 2), "c" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 3), "d" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 4), "e" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetMatrix, 5), "f" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextString, 0), "string" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextNextLineShowText, 0), "string" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing, 0), "wSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing, 1), "chSpacing" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextShowTextIndividualSpacing, 2), "string" },
{ std::make_pair(pdf::PDFPageContentProcessor::Operator::TextSetSpacingAndShowText, 0), "string" },
};
auto it = operands.find(std::make_pair(operatorValue, operandIndex));
if (it != operands.cend())
{
return it->second;
}
return QString("op%1").arg(operandIndex);
}
void PDFEditedPageContent::addContentPath(PDFPageContentProcessorState state, QPainterPath path, bool strokePath, bool fillPath)
{
QTransform transform = state.getCurrentTransformationMatrix();
m_contentElements.emplace_back(new PDFEditedPageContentElementPath(std::move(state), std::move(path), strokePath, fillPath, transform));
}
void PDFEditedPageContent::addContentImage(PDFPageContentProcessorState state, PDFObject imageObject, QImage image)
{
QTransform transform = state.getCurrentTransformationMatrix();
m_contentElements.emplace_back(new PDFEditedPageContentElementImage(std::move(state), std::move(imageObject), std::move(image), transform));
}
void PDFEditedPageContent::addContentElement(std::unique_ptr<PDFEditedPageContentElement> element)
{
m_contentElements.emplace_back(std::move(element));
}
PDFEditedPageContentElement* PDFEditedPageContent::getBackElement() const
{
if (m_contentElements.empty())
{
return nullptr;
}
return m_contentElements.back().get();
}
PDFDictionary PDFEditedPageContent::getFontDictionary() const
{
return m_fontDictionary;
}
void PDFEditedPageContent::setFontDictionary(const PDFDictionary& newFontDictionary)
{
m_fontDictionary = newFontDictionary;
}
PDFDictionary PDFEditedPageContent::getXObjectDictionary() const
{
return m_xobjectDictionary;
}
void PDFEditedPageContent::setXObjectDictionary(const PDFDictionary& newXobjectDictionary)
{
m_xobjectDictionary = newXobjectDictionary;
}
PDFEditedPageContentElement::PDFEditedPageContentElement(PDFPageContentProcessorState state, QTransform transform) :
m_state(std::move(state)),
m_transform(transform)
{
}
const PDFPageContentProcessorState& PDFEditedPageContentElement::getState() const
{
return m_state;
}
void PDFEditedPageContentElement::setState(const PDFPageContentProcessorState& newState)
{
m_state = newState;
}
QTransform PDFEditedPageContentElement::getTransform() const
{
return m_transform;
}
void PDFEditedPageContentElement::setTransform(const QTransform& newTransform)
{
m_transform = newTransform;
}
PDFEditedPageContentElementPath::PDFEditedPageContentElementPath(PDFPageContentProcessorState state, QPainterPath path, bool strokePath, bool fillPath, QTransform transform) :
PDFEditedPageContentElement(std::move(state), transform),
m_path(std::move(path)),
m_strokePath(strokePath),
m_fillPath(fillPath)
{
}
PDFEditedPageContentElement::Type PDFEditedPageContentElementPath::getType() const
{
return Type::Path;
}
PDFEditedPageContentElementPath* PDFEditedPageContentElementPath::clone() const
{
return new PDFEditedPageContentElementPath(getState(), getPath(), getStrokePath(), getFillPath(), getTransform());
}
QRectF PDFEditedPageContentElementPath::getBoundingBox() const
{
QPainterPath mappedPath = getTransform().map(m_path);
return mappedPath.boundingRect();
}
QPainterPath PDFEditedPageContentElementPath::getPath() const
{
return m_path;
}
void PDFEditedPageContentElementPath::setPath(QPainterPath newPath)
{
m_path = newPath;
}
bool PDFEditedPageContentElementPath::getStrokePath() const
{
return m_strokePath;
}
void PDFEditedPageContentElementPath::setStrokePath(bool newStrokePath)
{
m_strokePath = newStrokePath;
}
bool PDFEditedPageContentElementPath::getFillPath() const
{
return m_fillPath;
}
void PDFEditedPageContentElementPath::setFillPath(bool newFillPath)
{
m_fillPath = newFillPath;
}
PDFEditedPageContentElementImage::PDFEditedPageContentElementImage(PDFPageContentProcessorState state, PDFObject imageObject, QImage image, QTransform transform) :
PDFEditedPageContentElement(std::move(state), transform),
m_imageObject(std::move(imageObject)),
m_image(std::move(image))
{
}
PDFEditedPageContentElement::Type PDFEditedPageContentElementImage::getType() const
{
return PDFEditedPageContentElement::Type::Image;
}
PDFEditedPageContentElementImage* PDFEditedPageContentElementImage::clone() const
{
return new PDFEditedPageContentElementImage(getState(), getImageObject(), getImage(), getTransform());
}
QRectF PDFEditedPageContentElementImage::getBoundingBox() const
{
return getTransform().mapRect(QRectF(0, 0, 1, 1));
}
PDFObject PDFEditedPageContentElementImage::getImageObject() const
{
return m_imageObject;
}
void PDFEditedPageContentElementImage::setImageObject(const PDFObject& newImageObject)
{
m_imageObject = newImageObject;
}
QImage PDFEditedPageContentElementImage::getImage() const
{
return m_image;
}
void PDFEditedPageContentElementImage::setImage(const QImage& newImage)
{
m_image = newImage;
}
PDFEditedPageContentElementText::PDFEditedPageContentElementText(PDFPageContentProcessorState state, QTransform transform) :
PDFEditedPageContentElement(state, transform)
{
}
PDFEditedPageContentElementText::PDFEditedPageContentElementText(PDFPageContentProcessorState state,
std::vector<Item> items,
QPainterPath textPath,
QTransform transform,
QString itemsAsText) :
PDFEditedPageContentElement(state, transform),
m_items(std::move(items)),
m_textPath(std::move(textPath)),
m_itemsAsText(itemsAsText)
{
}
PDFEditedPageContentElement::Type PDFEditedPageContentElementText::getType() const
{
return Type::Text;
}
PDFEditedPageContentElementText* PDFEditedPageContentElementText::clone() const
{
return new PDFEditedPageContentElementText(getState(), getItems(), getTextPath(), getTransform(), getItemsAsText());
}
void PDFEditedPageContentElementText::addItem(Item item)
{
m_items.emplace_back(std::move(item));
}
const std::vector<PDFEditedPageContentElementText::Item>& PDFEditedPageContentElementText::getItems() const
{
return m_items;
}
void PDFEditedPageContentElementText::setItems(const std::vector<Item>& newItems)
{
m_items = newItems;
}
QRectF PDFEditedPageContentElementText::getBoundingBox() const
{
return getTransform().mapRect(m_textPath.boundingRect());
}
QPainterPath PDFEditedPageContentElementText::getTextPath() const
{
return m_textPath;
}
void PDFEditedPageContentElementText::setTextPath(QPainterPath newTextPath)
{
m_textPath = newTextPath;
}
QString PDFEditedPageContentElementText::createItemsAsText(const PDFPageContentProcessorState& initialState,
const std::vector<Item>& items)
{
QString text;
PDFPageContentProcessorState state = initialState;
state.setStateFlags(PDFPageContentProcessorState::StateFlags());
for (const Item& item : items)
{
if (item.isText)
{
for (const TextSequenceItem& textItem : item.textSequence.items)
{
if (textItem.isCharacter())
{
if (!textItem.character.isNull())
{
text += QString(textItem.character).toHtmlEscaped();
}
else if (textItem.isAdvance())
{
text += QString("<space advance=\"%1\"/>").arg(textItem.advance);
}
else if (textItem.cid != 0)
{
text += QString("<character cid=\"%1\"/>").arg(textItem.cid);
}
}
}
}
else if (item.isUpdateGraphicState)
{
PDFPageContentProcessorState newState = state;
newState.setStateFlags(PDFPageContentProcessorState::StateFlags());
newState.setState(item.state);
PDFPageContentProcessorState::StateFlags flags = newState.getStateFlags();
if (flags.testFlag(PDFPageContentProcessorState::StateTextRenderingMode))
{
text += QString("<tr v=\"%1\"/>").arg(int(newState.getTextRenderingMode()));
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextRise))
{
text += QString("<ts v=\"%1\"/>").arg(newState.getTextRise());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextCharacterSpacing))
{
text += QString("<tc v=\"%1\"/>").arg(newState.getTextCharacterSpacing());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextWordSpacing))
{
text += QString("<tw v=\"%1\"/>").arg(newState.getTextWordSpacing());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextLeading))
{
text += QString("<tl v=\"%1\"/>").arg(newState.getTextLeading());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextHorizontalScaling))
{
text += QString("<tz v=\"%1\"/>").arg(newState.getTextHorizontalScaling());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextKnockout))
{
text += QString("<tk v=\"%1\"/>").arg(newState.getTextKnockout());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextFont) ||
flags.testFlag(PDFPageContentProcessorState::StateTextFontSize))
{
text += QString("<tf font=\"%1\" size=\"%2\"/>").arg(newState.getTextFont()->getFontId()).arg(newState.getTextFontSize());
}
if (flags.testFlag(PDFPageContentProcessorState::StateTextMatrix))
{
QTransform transform = newState.getTextMatrix();
qreal x = transform.dx();
qreal y = transform.dy();
if (transform.isTranslating())
{
text += QString("<tpos x=\"%1\" y=\"%2\"/>").arg(x).arg(y);
}
else
{
text += QString("<tmatrix m11=\"%1\" m12=\"%2\" m21=\"%3\" m22=\"%4\" x=\"%5\" y=\"%6\"/>").arg(transform.m11()).arg(transform.m12()).arg(transform.m21()).arg(transform.m22()).arg(x).arg(y);
}
}
state = newState;
state.setStateFlags(PDFPageContentProcessorState::StateFlags());
}
}
return text;
}
QString PDFEditedPageContentElementText::getItemsAsText() const
{
return m_itemsAsText;
}
void PDFEditedPageContentElementText::setItemsAsText(const QString& newItemsAsText)
{
m_itemsAsText = newItemsAsText;
}
void PDFEditedPageContentElementText::optimize()
{
while (!m_items.empty() && !m_items.back().isText)
{
m_items.pop_back();
}
}
} // namespace pdf