View Issue Details

IDProjectCategoryView StatusLast Update
0016126ScribusImport / Exportpublic2020-06-21 12:40
Reporteroliverthered Assigned Tojghali  
PrioritynormalSeverityfeatureReproducibilityalways
Status closedResolutionduplicate 
PlatformanyOSanyOS Versionany
Product Version1.5.6.svn 
Summary0016126: refactor getChar so that it can be used for importing text as well as drawing vector characters
Descriptionrefactor getChar so that it can be used for importing text as well as drawing vector characters,

this involved separating out setFillAndStrokeForPDF from the function, some checks to see if we should be drawing vectors or collating text and implementing a new addChar function to collate text for textframes.
Steps To Reproducestart scribus
try to import an svg file that contains text
Additional Informationdefaulting to importing vectors for now. this needs to have an oprion for text or vectors in the gui and override the default.

see diff attached
Tagsimport, PDF, pdf import, vectorised fonts
PatchNo

Relationships

duplicate of 0016142 closedjghali Preliminary support for importing PDF text as text 

Activities

oliverthered

2020-06-03 16:35

reporter  

addChar.diff (15,269 bytes)   
 scribus/plugins/import/pdf/slaoutput.cpp | 222 +++++++++++++++++++++++--------
 scribus/plugins/import/pdf/slaoutput.h   |   8 +-
 2 files changed, 171 insertions(+), 59 deletions(-)

diff --git a/scribus/plugins/import/pdf/slaoutput.cpp b/scribus/plugins/import/pdf/slaoutput.cpp
index 05f17ce76..c98d3d9ec 100644
--- a/scribus/plugins/import/pdf/slaoutput.cpp
+++ b/scribus/plugins/import/pdf/slaoutput.cpp
@@ -3016,7 +3016,7 @@ void SlaOutputDev::markPoint(POPPLER_CONST char *name, Dict *properties)
 	beginMarkedContent(name, properties);
 }
 
-void SlaOutputDev::updateFont(GfxState *state)
+void SlaOutputDev::updateFontForVector(GfxState *state)
 {
 	GfxFont *gfxFont;
 	GfxFontLoc *fontLoc;
@@ -3252,11 +3252,16 @@ err1:
 		fontsrc->unref();
 }
 
-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)
+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)
 {
-//	qDebug() << "SlaOutputDev::drawChar code:" << code << "bytes:" << nBytes << "Unicode:" << u << "ulen:" << uLen << "render:" << state->getRender();
+	qDebug() << "SlaOutputDev::drawChar x:" << x << "y:" << y << "dx:" << dx << "dy" << dy << "code:" << code;
+	//for importing text as glyphs
 	double x1, y1, x2, y2;
-	updateFont(state);
+	//if (import_text_as_vectors) {
+	updateFontForVector(state); //this sets m_font a splashfont
+	//TODO: add support for fonts when importing pdf text
+	//_updateFontForText(state); //and this sets font_style and has a lkot more detail about the font, both work on the same details from gfxfont
+
 	if (!m_font)
 		return;
 
@@ -3276,7 +3281,7 @@ void SlaOutputDev::drawChar(GfxState *state, double x, double y, double dx, doub
 		return;
 	if (textRenderingMode < 8)
 	{
-		SplashPath * fontPath;
+		SplashPath* fontPath;
 		fontPath = m_font->getGlyphPath(code);
 		if (fontPath)
 		{
@@ -3287,7 +3292,7 @@ void SlaOutputDev::drawChar(GfxState *state, double x, double y, double dx, doub
 				Guchar f;
 				fontPath->getPoint(i, &x1, &y1, &f);
 				if (f & splashPathFirst)
-					qPath.moveTo(x1,y1);
+					qPath.moveTo(x1, y1);
 				else if (f & splashPathCurve)
 				{
 					double x3, y3;
@@ -3295,73 +3300,63 @@ void SlaOutputDev::drawChar(GfxState *state, double x, double y, double dx, doub
 					fontPath->getPoint(i, &x2, &y2, &f);
 					++i;
 					fontPath->getPoint(i, &x3, &y3, &f);
-					qPath.cubicTo(x1,y1,x2,y2,x3,y3);
+					qPath.cubicTo(x1, y1, x2, y2, x3, y3);
 				}
 				else
-					qPath.lineTo(x1,y1);
+					qPath.lineTo(x1, y1);
 				if (f & splashPathLast)
 					qPath.closeSubpath();
 			}
-			const double *ctm = state->getCTM();
+			const double* ctm = state->getCTM();
 			m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
 			double xCoor = m_doc->currentPage()->xOffset();
 			double yCoor = m_doc->currentPage()->yOffset();
 			FPointArray textPath;
 			textPath.fromQPainterPath(qPath);
 			FPoint wh = textPath.widthHeight();
-			if (textRenderingMode > 3)
-			{
-				QTransform mm;
-				mm.scale(1, -1);
-				mm.translate(x, -y);
-				// Remember the glyph for later clipping
- 				m_clipTextPath.addPath(m_ctm.map(mm.map(qPath)));
-			}
-			if ((textPath.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)) && (textRenderingMode != 7))
-			{
-				int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CommonStrings::None, CommonStrings::None);
-				PageItem* ite = m_doc->Items->at(z);
-				QTransform mm;
-				mm.scale(1, -1);
-				mm.translate(x, -y);
-				textPath.map(mm);
-				textPath.map(m_ctm);
-				ite->PoLine = textPath.copy();
-				ite->ClipEdited = true;
-				ite->FrameType = 3;
-				ite->setLineEnd(PLineEnd);
-				ite->setLineJoin(PLineJoin);
-				ite->setTextFlowMode(PageItem::TextFlowDisabled);
-				// Fill text rendering modes. See above
-				if (textRenderingMode == 0 || textRenderingMode == 2 || textRenderingMode == 4 || textRenderingMode == 6)
+			if (m_import_text_as_vectors) {
+				qDebug() << "drawChar() ";
+
+				if (textRenderingMode > 3)
 				{
-					CurrColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &CurrFillShade);
-					ite->setFillColor(CurrColorFill);
-					ite->setFillShade(CurrFillShade);
-					ite->setFillEvenOdd(false);
-					ite->setFillTransparency(1.0 - state->getFillOpacity());
-					ite->setFillBlendmode(getBlendMode(state));
+					QTransform mm;
+					mm.scale(1, -1);
+					mm.translate(x, -y);
+					// Remember the glyph for later clipping
+					m_clipTextPath.addPath(m_ctm.map(mm.map(qPath)));
 				}
-				// Stroke text rendering modes. See above
-				if (textRenderingMode == 1 || textRenderingMode == 2 || textRenderingMode == 5 || textRenderingMode == 6)
+				if ((textPath.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)) && (textRenderingMode != 7))
 				{
-					CurrColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &CurrStrokeShade);
-					ite->setLineColor(CurrColorStroke);
-					ite->setLineWidth(state->getTransformedLineWidth());
-					ite->setLineTransparency(1.0 - state->getStrokeOpacity());
-					ite->setLineBlendmode(getBlendMode(state));
-					ite->setLineShade(CurrStrokeShade);
-				}
-				m_doc->adjustItemSize(ite);
-				m_Elements->append(ite);
-				if (m_groupStack.count() != 0)
-				{
-					m_groupStack.top().Items.append(ite);
-					applyMask(ite);
+					PageItem* text_node = NULL;
+
+
+					int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CommonStrings::None, CommonStrings::None);
+					text_node = m_doc->Items->at(z);
+
+					// todo: merge this between vector and text implementations.
+
+					QTransform mm;
+					mm.scale(1, -1);
+					mm.translate(x, -y);
+					textPath.map(mm);
+					textPath.map(m_ctm);
+					text_node->PoLine = textPath.copy();
+					setFillAndStrokeForPDF(state, text_node);
+					// Fill text rendering modes. See above
+					m_doc->adjustItemSize(text_node);
+					m_Elements->append(text_node);
+					if (m_groupStack.count() != 0)
+					{
+						m_groupStack.top().Items.append(text_node);
+						applyMask(text_node);
+					}
 				}
 				delete fontPath;
 			}
 		}
+		if (!m_import_text_as_vectors) { // donm't render the char as vectors add it to an array so it can be rendred as a string
+			addChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
+		}
 	}
 }
 
@@ -4043,16 +4038,16 @@ void SlaOutputDev::addGlyphAtPoint(QPointF newGlyphPoint, PdfGlyph new_glyph) {
 		//m_activeTextRegion->glyphs.push_back(new_glyph);
 
 		//at the moment a new segment only gets added when the line is created. a new segment should also get added if there's any change in style or layout etc...but that feature can be added llater, it's not needed for basic textframe support with no style.
-		 m_activeTextRegion->textRegionLines.back().glyphIndex = m_glyphs.size() - 1;
+		m_activeTextRegion->textRegionLines.back().glyphIndex = m_glyphs.size() - 1;
 		if (m_activeTextRegion->textRegionLines.back().segments.empty())
 		{
 			// add a new segment
 			TextRegionLine newSegment = TextRegionLine();
 			m_activeTextRegion->textRegionLines.back().segments.push_back(newSegment);
 		}
-		if(m_activeTextRegion->textRegionLines.back().segments.back().width == 0)
+		if (m_activeTextRegion->textRegionLines.back().segments.back().width == 0)
 		{
-			TextRegionLine &segment = m_activeTextRegion->textRegionLines.back().segments.back();
+			TextRegionLine& segment = m_activeTextRegion->textRegionLines.back().segments.back();
 			segment.width = new_glyph.dx;
 			segment.baseOrigin = QPointF(newGlyphPoint.x(), m_activeTextRegion->textRegionLines.back().baseOrigin.y());
 			segment.modeHeigth = newGlyphPoint.y() - segment.baseOrigin.y();
@@ -4074,3 +4069,114 @@ void SlaOutputDev::addGlyphAtPoint(QPointF newGlyphPoint, PdfGlyph new_glyph) {
 	}
 }
 
+/**
+ * \brief Adds the specified character to the text buffer
+ * Takes care of converting it to UTF-8 and generates a new style repr if style
+ * has changed since the last call.
+ */
+void SlaOutputDev::addChar(GfxState* state, double x, double y,
+	double dx, double dy,
+	double originX, double originY,
+	CharCode code, int nBytes, Unicode const* u, int uLen) {
+	qDebug() << "addChar() '" << u << " : " << uLen;
+	// TODO: Compleatly gut this function so all that it ends up doing is placing a character and some positioning information on a stack get rid of all the other junk as it's not needed
+
+	bool is_space = (uLen == 1 && u[0] == 32);
+	// Skip beginning space
+	if (is_space && m_glyphs.empty()) {
+		QPoint delta(dx, dy);
+		m_text_position += delta;
+		return;
+	}
+	// Allow only one space in a row
+	if (is_space &&
+		(m_glyphs[m_glyphs.size() - 1].code == QChar::SpecialCharacter::Space)) {
+		QPoint delta(dx, dy);
+		m_text_position += delta;
+		return;
+	}
+
+	PdfGlyph new_glyph;
+	new_glyph.is_space = is_space;
+	new_glyph.position = QPoint(x - originX, y - originY);
+	//TODO:work out if this is still needed
+	//new_glyph.text_position = m_text_position;
+	new_glyph.dx = dx;
+	new_glyph.dy = dy;
+	//TODO: This only need to be called for the very first point, replace with an abstract version of addchar that does this for brand new textregions so there's no need to record dx or dy or check is glyphs is empty or empty glyphs
+	if (m_glyphs.empty())
+	{
+		addGlyphAtPoint(QPointF(x, y), new_glyph);
+	}
+	//TODO:work out if this is still needed
+	QPoint delta(dx, dy);
+	m_text_position += delta;
+
+	// Convert the character to UTF-16 since that's our SVG document's encoding
+	{
+		for (int i = 0; i < uLen; i++) {
+			new_glyph.code += (char16_t)u[i];
+		}
+	}
+
+	new_glyph.rise = state->getRise();
+	m_glyphs.push_back(new_glyph);
+}
+
+void SlaOutputDev::setFillAndStrokeForPDF(GfxState* state, PageItem* text_node) {
+
+	text_node->ClipEdited = true;
+	text_node->FrameType = 3;
+	text_node->setLineEnd(PLineEnd);
+	text_node->setLineJoin(PLineJoin);
+	text_node->setTextFlowMode(PageItem::TextFlowDisabled);
+
+	int textRenderingMode = state->getRender();
+	// Invisible or only used for clipping
+	if (textRenderingMode == 3)
+		return;
+	// Fill text rendering modes. See above
+	if (textRenderingMode == 0 || textRenderingMode == 2 || textRenderingMode == 4 || textRenderingMode == 6)
+	{
+
+		CurrColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &CurrFillShade);
+		if (text_node->isTextFrame()) { //fill colour sets the background colour for the frame not the fill colour fore  the text			
+			text_node->setFillTransparency(1.0 - (state->getFillOpacity() > state->getStrokeOpacity() ? state->getFillOpacity() : state->getStrokeOpacity()));
+			text_node->setLineTransparency(1.0); // this ssets the transparency of the textbox border and we don't want to see it			
+			text_node->setFillColor(CommonStrings::None);
+			text_node->setLineColor(CommonStrings::None);
+			text_node->setLineWidth(0);//line  width doesn't effect drawing text, it creates a bounding box state->getTransformedLineWidth());
+			text_node->setFillShade(CurrFillShade);
+		}
+		else {
+			text_node->setFillColor(CurrColorFill);
+			text_node->setFillShade(CurrFillShade);
+			text_node->setFillEvenOdd(false);
+			text_node->setFillTransparency(1.0 - state->getFillOpacity());
+			text_node->setFillBlendmode(getBlendMode(state));
+		}
+	}
+	// Stroke text rendering modes. See above
+	if (textRenderingMode == 1 || textRenderingMode == 2 || textRenderingMode == 5 || textRenderingMode == 6)
+	{
+		CurrColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &CurrStrokeShade);
+		if (text_node->isTextFrame()) { //fil;l colour sets the background colour for the frame not the fill colour fore  the text			
+			text_node->setFillTransparency(1.0 - (state->getFillOpacity() > state->getStrokeOpacity() ? state->getFillOpacity() : state->getStrokeOpacity()));
+			text_node->setLineTransparency(1.0); // this sets the transparency of the textbox border and we don't want to see it			
+			text_node->setFillColor(CommonStrings::None); //TODO: Check if we ov erride the stroke colour with the fil,l colour when threre is a choice
+			text_node->setLineColor(CommonStrings::None);
+			text_node->setLineWidth(0);//line  width doesn't effect drawing text, it creates a bounding box state->getTransformedLineWidth());
+			text_node->setFillBlendmode(getBlendMode(state));
+			text_node->setFillShade(CurrFillShade);
+		}
+		else {
+			text_node->setLineColor(CurrColorStroke);
+			text_node->setLineWidth(0);//line  width doesn't effect drawing text, it creates a bounding box state->getTransformedLineWidth());
+			text_node->setFillTransparency(1.0 - state->getFillOpacity() > state->getStrokeOpacity() ? state->getFillOpacity() : state->getStrokeOpacity());
+			text_node->setLineTransparency(1.0); // this sets the transparency of the textbox border and we don't want to see it
+			text_node->setLineBlendmode(getBlendMode(state));
+			text_node->setLineShade(CurrStrokeShade);
+		}
+	}
+}
+
diff --git a/scribus/plugins/import/pdf/slaoutput.h b/scribus/plugins/import/pdf/slaoutput.h
index aa81839ef..017b871bc 100644
--- a/scribus/plugins/import/pdf/slaoutput.h
+++ b/scribus/plugins/import/pdf/slaoutput.h
@@ -269,6 +269,7 @@ public:
 	void endMarkedContent(GfxState *state) override;
 	void markPoint(POPPLER_CONST char *name) override;
 	void markPoint(POPPLER_CONST char *name, Dict *properties) override;
+	
 
 	//----- image drawing
 	void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool interpolate, GBool inlineImg) override;
@@ -299,7 +300,8 @@ public:
 
 	void updateFillColor(GfxState *state) override;
 	void updateStrokeColor(GfxState *state) override;
-	void updateFont(GfxState *state) override;
+	void updateFontForVector(GfxState* state);
+	bool m_import_text_as_vectors = true;
 
 	//----- text drawing
 	void  beginTextObject(GfxState *state) override;
@@ -352,6 +354,8 @@ private:
 	bool linearTest(QPointF point, bool xInLimits, bool yInLimits);
 	void moveToPoint(QPointF newPoint);
 	void addGlyphAtPoint(QPointF newGlyphPoint, PdfGlyph new_glyph);
+	void addChar(GfxState* state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode const* u, int uLen);
+	void setFillAndStrokeForPDF(GfxState* state, PageItem* text_node);
 
 	bool pathIsClosed {false};
 	QString CurrColorFill;
@@ -423,6 +427,8 @@ private:
 	TextRegion *m_activeTextRegion = NULL;
 	std::vector<PdfGlyph> m_glyphs; //this may replace some of the other settings or it may not, certainly not font as text gets flushed if the font changes
 
+	//PDF Text import
+	QPoint m_text_position = QPoint(0,0);
 };
 
 #endif
addChar.diff (15,269 bytes)   

jghali

2020-06-03 21:34

administrator   ~0047667

As in 0016125, patch does not follow properly our code style:
- braces must be on their own line
- if a code block has a single line, then no braces
- variable naming: m_import_text_as_vectors => not correct, use m_importTextAsVectors instead

Issue History

Date Modified Username Field Change
2020-06-03 16:35 oliverthered New Issue
2020-06-03 16:35 oliverthered Tag Attached: import
2020-06-03 16:35 oliverthered Tag Attached: PDF
2020-06-03 16:35 oliverthered Tag Attached: pdf import
2020-06-03 16:35 oliverthered Tag Attached: vectorised fonts
2020-06-03 16:35 oliverthered File Added: addChar.diff
2020-06-03 21:34 jghali Note Added: 0047667
2020-06-21 12:39 jghali Assigned To => jghali
2020-06-21 12:39 jghali Status new => resolved
2020-06-21 12:39 jghali Resolution open => duplicate
2020-06-21 12:39 jghali Relationship added duplicate of 0016142
2020-06-21 12:40 jghali Status resolved => closed