/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
/***************************************************************************
                          importcgm.cpp  -  description
                             -------------------
    begin                : Wed Dez 23 2009
    copyright            : (C) 2009 by Franz Schmid
    email                : Franz.Schmid@altmuehlnet.de
 ***************************************************************************/

#include <QByteArray>
#include <QCursor>
#include <QDrag>
#include <QFile>
#include <QList>
#include <QMimeData>
#include <QStack>
#include <QDebug>

#include <cstdlib>

#include "commonstrings.h"
#include "importcgm.h"
#include "loadsaveplugin.h"
#include "prefsmanager.h"
#include "scconfig.h"
#include "scmimedata.h"
#include "scribusXml.h"
#include "scribuscore.h"
#include "scribusview.h"
#include "selection.h"
#include "ui/multiprogressdialog.h"
#include "undomanager.h"
#include "util.h"
#include "util_math.h"

ScBitReader::ScBitReader(const QByteArray &data)
{
	buffer = data;
	actBit = 7;
	actByte = 0;
}

quint32 ScBitReader::getUInt(uint size)
{
	quint32 ret = 0;
	if (size > 32)
		return 0;
	quint8 dat = buffer[actByte];
	for (uint c = 0; c < size; c++)
	{
		ret = (ret << 1) | ((dat & (0x01 << actBit)) >> actBit);
		actBit--;
		if (actBit < 0)
		{
			actBit = 7;
			actByte++;
			if (actByte >= buffer.size())
				break;
			dat = buffer[actByte];
		}
	}
	return ret;
}

void ScBitReader::alignToWord()
{
	if (actByte < buffer.size() - 1)
	{
		actByte++;
		actByte += actByte % 2;
		actBit = 7;
	}
}

CgmPlug::CgmPlug(ScribusDoc* doc, int flags)
{
	tmpSel = new Selection(this, false);
	m_Doc = doc;
	importerFlags = flags;
	interactive = (flags & LoadSavePlugin::lfInteractive);
	progressDialog = nullptr;
}

QImage CgmPlug::readThumbnail(const QString& fName)
{
	QFileInfo fi(fName);
	baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath() + "/"));
	double b = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
	double h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
	docWidth = b;
	docHeight = h;
	progressDialog = nullptr;
	m_Doc = new ScribusDoc();
	m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
	m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
	m_Doc->addPage(0);
	m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
	baseX = m_Doc->currentPage()->xOffset();
	baseY = m_Doc->currentPage()->yOffset();
	Elements.clear();
	m_Doc->setLoading(true);
	m_Doc->DoDrawing = false;
	m_Doc->scMW()->setScriptRunning(true);
	QString CurDirP = QDir::currentPath();
	QDir::setCurrent(fi.path());
	if (convert(fName))
	{
		tmpSel->clear();
		QDir::setCurrent(CurDirP);
		if (Elements.count() > 1)
			m_Doc->groupObjectsList(Elements);
		m_Doc->DoDrawing = true;
		m_Doc->m_Selection->delaySignalsOn();
		QImage tmpImage;
		if (!Elements.isEmpty())
		{
			tmpSel->addItems(Elements);
			tmpSel->setGroupRect();
			double xs = tmpSel->width();
			double ys = tmpSel->height();
			tmpImage = Elements.at(0)->DrawObj_toImage(500);
			tmpImage.setText("XSize", QString("%1").arg(xs));
			tmpImage.setText("YSize", QString("%1").arg(ys));
		}
		m_Doc->scMW()->setScriptRunning(false);
		m_Doc->setLoading(false);
		m_Doc->m_Selection->delaySignalsOff();
		delete m_Doc;
		m_Doc = nullptr;
		return tmpImage;
	}
	QDir::setCurrent(CurDirP);
	m_Doc->DoDrawing = true;
	m_Doc->scMW()->setScriptRunning(false);
	delete m_Doc;
	m_Doc = nullptr;
	return QImage();
}

bool CgmPlug::importFile(const QString& fNameIn, const TransactionSettings& trSettings, int flags, bool showProgress)
{
	bool success = false;
	interactive = (flags & LoadSavePlugin::lfInteractive);
	importerFlags = flags;
	cancel = false;
	bool ret = false;
	CustColors.clear();
	QFileInfo fi(fNameIn);
	if (!ScCore->usingGUI())
	{
		interactive = false;
		showProgress = false;
	}
	baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath() + "/"));
	if (showProgress)
	{
		ScribusMainWindow* mw = (m_Doc == nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
		progressDialog = new MultiProgressDialog( tr("Importing: %1").arg(fi.fileName()), CommonStrings::tr_Cancel, mw );
		QStringList barNames, barTexts;
		barNames << "GI";
		barTexts << tr("Analyzing File:");
		QList<bool> barsNumeric;
		barsNumeric << false;
		progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
		progressDialog->setOverallTotalSteps(3);
		progressDialog->setOverallProgress(0);
		progressDialog->setProgress("GI", 0);
		progressDialog->show();
		connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
		QApplication::processEvents();
	}
	else
		progressDialog = nullptr;
/* Set default Page to size defined in Preferences */
	if (progressDialog)
	{
		progressDialog->setOverallProgress(1);
		QApplication::processEvents();
	}
	double b = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
	double h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
	docWidth = b;
	docHeight = h;
	baseX = 0;
	baseY = 0;
	if (m_Doc && (!interactive || (flags & LoadSavePlugin::lfInsertPage)))
	{
		m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
		m_Doc->addPage(0);
		m_Doc->view()->addPage(0, true);
		baseX = 0;
		baseY = 0;
	}
	else if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
	{
		m_Doc = ScCore->primaryMainWindow()->doFileNew(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
		ScCore->primaryMainWindow()->HaveNewDoc();
		ret = true;
		baseX = 0;
		baseY = 0;
		baseX = m_Doc->currentPage()->xOffset();
		baseY = m_Doc->currentPage()->yOffset();
	}
	if (!ret && interactive)
	{
		baseX = m_Doc->currentPage()->xOffset();
		baseY = m_Doc->currentPage()->yOffset();
	}
	if (ret || !interactive)
	{
		if (docWidth > docHeight)
			m_Doc->setPageOrientation(1);
		else
			m_Doc->setPageOrientation(0);
		m_Doc->setPageSize("Custom");
	}
	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
		m_Doc->view()->deselectItems();
	Elements.clear();
	m_Doc->setLoading(true);
	m_Doc->DoDrawing = false;
	if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
		m_Doc->view()->updatesOn(false);
	m_Doc->scMW()->setScriptRunning(true);
	QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
	QString CurDirP = QDir::currentPath();
	QDir::setCurrent(fi.path());
	if (convert(fNameIn))
	{
		tmpSel->clear();
		QDir::setCurrent(CurDirP);
		if ((Elements.count() > 1) && (!(importerFlags & LoadSavePlugin::lfCreateDoc)))
		{
			PageItem* group = m_Doc->groupObjectsList(Elements);
			if (!pictName.isEmpty())
				group->setItemName(group->generateUniqueCopyName(pictName, false).replace( QRegularExpression("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%\\.]"), "_" ));
		}
		m_Doc->DoDrawing = true;
		m_Doc->scMW()->setScriptRunning(false);
		m_Doc->setLoading(false);
		QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
		if (!Elements.isEmpty() && !ret && interactive)
		{
			if (flags & LoadSavePlugin::lfScripted)
			{
				bool loadF = m_Doc->isLoading();
				m_Doc->setLoading(false);
				m_Doc->changed();
				m_Doc->setLoading(loadF);
				if (!(flags & LoadSavePlugin::lfLoadAsPattern))
				{
					m_Doc->m_Selection->delaySignalsOn();
					m_Doc->m_Selection->addItems(Elements);
					m_Doc->m_Selection->delaySignalsOff();
					m_Doc->m_Selection->setGroupRect();
					if (m_Doc->view() != nullptr)
						m_Doc->view()->updatesOn(true);
				}
			}
			else
			{
				m_Doc->DragP = true;
				m_Doc->DraggedElem = nullptr;
				m_Doc->DragElements.clear();
				m_Doc->m_Selection->delaySignalsOn();
				tmpSel->addItems(Elements);
				tmpSel->setGroupRect();
				ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, tmpSel);
				m_Doc->itemSelection_DeleteItem(tmpSel);
				m_Doc->view()->updatesOn(true);
				m_Doc->m_Selection->delaySignalsOff();
				// We must copy the TransationSettings object as it is owned
				// by handleObjectImport method afterwards
				auto* transacSettings = new TransactionSettings(trSettings);
				m_Doc->view()->handleObjectImport(md, transacSettings);
				m_Doc->DragP = false;
				m_Doc->DraggedElem = nullptr;
				m_Doc->DragElements.clear();
			}
		}
		else
		{
			m_Doc->changed();
			m_Doc->reformPages();
			if (!(flags & LoadSavePlugin::lfLoadAsPattern))
				m_Doc->view()->updatesOn(true);
		}
		success = true;
	}
	else
	{
		QDir::setCurrent(CurDirP);
		m_Doc->DoDrawing = true;
		m_Doc->scMW()->setScriptRunning(false);
		m_Doc->view()->updatesOn(true);
		QApplication::changeOverrideCursor(QCursor(Qt::ArrowCursor));
	}
	if (interactive)
		m_Doc->setLoading(false);
	//CB If we have a gui we must refresh it if we have used the progressbar
	if (!(flags & LoadSavePlugin::lfLoadAsPattern))
	{
		if (showProgress && !interactive)
			m_Doc->view()->DrawNew();
	}
	QApplication::restoreOverrideCursor();
	return success;
}

CgmPlug::~CgmPlug()
{
	delete progressDialog;
	delete tmpSel;
}

void CgmPlug::parseHeader(const QString& fName, double &b, double &h)
{
}

bool CgmPlug::convert(const QString& fn)
{
	Coords.resize(0);
	Coords.svgInit();
	importedColors.clear();
	QList<PageItem*> gElements;
	groupStack.push(gElements);
	currentItemNr = 0;
	importRunning = true;
	firstPage = true;
	vcdSet = false;
	metaFileVersion = 1;
	vdcType = 0;
	vdcInt = 16;
	vdcReal = 1;
	vdcMantissa = 16;
	vcdFlippedH = false;
	vcdFlippedV = true;
	intPrecision = 16;
	realPrecision = 1;
	realMantissa = 16;
	realFraction = 16;
	realPrecisionSet = false;
	indexPrecision = 16;
	colorPrecision = 8;
	colorIndexPrecision = 8;
	maxColorIndex = 63;
	m_colorModel = 1;
	colorMode = 0;
	namePrecision = 16;
	metaFileScaleMode = 0;
	metaFileScale = 1.0;
	metaScale = 400.0 / 32768.0;
	lineWidthMode = 1;
	edgeWidthMode = 1;
	markerSizeMode = 1;
	viewPortScale = 1.0;
	viewPortScaleMode = 0;
	lineType = Qt::SolidLine;
	lineCap = Qt::FlatCap;
	lineJoin = Qt::MiterJoin;
	lineWidth = 1.0;
	lineColor = "Black";
	edgeType = Qt::SolidLine;
	edgeCap = Qt::FlatCap;
	edgeJoin = Qt::MiterJoin;
	edgeWidth = 0.0;
	edgeColor = "Black";
	fillColor = "Black";
	backgroundColor = "White";
	patternIndex = 1;
	patternTable.clear();
	patternScaleX = -1;
	patternScaleY = -1;
	backgroundSet = false;
	fillType = 1;
	minColor = 0;
	maxColor = 255;
	clipRect = QRectF();
	useClipRect = true;
	clipSet = false;
	lineVisible = true;
	recordRegion = false;
	wasEndPic = false;
	recordFigure = false;
	fontID_Map.clear();
	m_fontIndex = 1;
	textSize = 12;
	textColor = "Black";
	textAlignH = 0;
	textScaleMode = 1;
	currentRegion = 0;
	pictName = "";
	if (progressDialog)
	{
		progressDialog->setOverallProgress(2);
		progressDialog->setLabel("GI", tr("Generating Items"));
		QApplication::processEvents();
	}
	QFile f(fn);
	if (f.open(QIODevice::ReadOnly))
	{
		oldDocItemCount = m_Doc->Items->count();
		int fSize = (int) f.size();
		if (progressDialog)
		{
			progressDialog->setTotalSteps("GI", fSize);
			QApplication::processEvents();
		}
		QDataStream ts(&f);
		ts.setByteOrder(QDataStream::BigEndian);
		quint32 magic;
		ts >> magic;
		ts.device()->seek(0);
		if (magic == 0x4265674D)
			decodeText(f);
		else
		{
			while (!ts.atEnd() && importRunning)
			{
				quint16 data;
				ts >> data;
				quint16 elemClass = (data & 0xF000) >> 12;
				quint16 elemID    = (data & 0x0FE0) >>  5;
				quint16 paramLen  = data & 0x001F;
				if (paramLen == 31)
					ts >> paramLen;
			//	qDebug() << "CGM Command Class" << elemClass << "ID" << elemID << "ParamLen" << paramLen;
				decodeBinary(ts, elemClass, elemID, paramLen);
				if (progressDialog)
				{
					progressDialog->setProgress("GI", ts.device()->pos());
					QApplication::processEvents();
				}
			}
		}
		f.close();
		if (Elements.isEmpty())
		{
			for (const auto& importedColor : std::as_const(importedColors))
				m_Doc->PageColors.remove(importedColor);
		}
		else
		{
			if (backgroundSet)
			{
				tmpSel->clear();
				tmpSel->delaySignalsOn();
				tmpSel->addItems(Elements);
				tmpSel->setGroupRect();
				double gx, gy, gw, gh;
				tmpSel->getVisualGroupRect(&gx, &gy, &gw, &gh);
				tmpSel->clear();
				tmpSel->delaySignalsOff();
				int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, backgroundColor, CommonStrings::None);
				PageItem *ite = m_Doc->Items->takeAt(z);
				Elements.prepend(ite);
				m_Doc->Items->insert(oldDocItemCount, ite);
			}
		}
	}
	if (progressDialog)
		progressDialog->close();
	return true;
}

void CgmPlug::decodeText(QFile &f)
{
	qDebug() << "Parsing Text Data not supported yet";
}

/* Start binary Decoder */
void CgmPlug::decodeBinary(QDataStream &ts, quint16 elemClass, quint16 elemID, quint16 paramLen)
{
	qint64 pos = ts.device()->pos();
	if (elemClass == 0)
		decodeClass0(ts, elemID, paramLen);
	else if (elemClass == 1)
		decodeClass1(ts, elemID, paramLen);
	else if (elemClass == 2)
		decodeClass2(ts, elemID, paramLen);
	else if (elemClass == 3)
		decodeClass3(ts, elemID, paramLen);
	else if (elemClass == 4)
		decodeClass4(ts, elemID, paramLen);
	else if (elemClass == 5)
		decodeClass5(ts, elemID, paramLen);
	else if (elemClass == 6)
		decodeClass6(ts, elemID, paramLen);
	else if (elemClass == 7)
		decodeClass7(ts, elemID, paramLen);
	else if (elemClass == 8)
		decodeClass8(ts, elemID, paramLen);
	else if (elemClass == 9)
		decodeClass9(ts, elemID, paramLen);
	else
	{
		importRunning = false;
		qDebug() << "Class" << elemClass << "ID" << elemID << "Len" << paramLen << "at" << ts.device()->pos();
	}
	ts.device()->seek(pos);
	alignStreamToWord(ts, paramLen);
	alignStreamToWord(ts, 0);
}

void CgmPlug::decodeClass0(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 0)
	{
		qDebug() << "NO OP";
	}
	else if (elemID == 1)
		handleStartMetaFile(getBinaryText(ts));
	else if (elemID == 2)
	{
		importRunning = false;
		// qDebug() << "END METAFILE";
	}
	else if (elemID == 3)
		handleStartPicture(getBinaryText(ts));
	else if (elemID == 4)
	{
		if (vcdSet)
		{
			double w = vdcWidth * metaScale;
			double h = vdcHeight * metaScale;
			handleStartPictureBody(w, h);
		}
		else
		{
			handleStartPictureBody(docWidth, docHeight);
			firstPage = true;
		}
	//	qDebug() << "BEGIN PICTURE BODY";
	}
	else if (elemID == 5)
	{
		if (vcdSet)
		{
			if (firstPage)
			{
				double w = vdcWidth * metaScale;
				double h = vdcHeight * metaScale;
				handleStartPictureBody(w, h);
			}
		}
		else
		{
			if (firstPage)
				handleStartPictureBody(docWidth, docHeight);
		}
		wasEndPic = true;
	//	qDebug() << "END PICTURE";
	}
	else if (elemID == 6)
	{
		qDebug() << "BEGIN SEGMENT";
	}
	else if (elemID == 7)
	{
		qDebug() << "END SEGMENT";
	}
	else if (elemID == 8)
	{
		recordFigure = true;
		figurePath = QPainterPath();
		figClose = false;
		figDocIndex = m_Doc->Items->count();
		figElemIndex = Elements.count();
		figGstIndex = 0;
		figFillColor = fillColor;
		if (!groupStack.isEmpty())
			figGstIndex = groupStack.top().count();
	//	qDebug() << "BEGIN FIGURE";
	}
	else if (elemID == 9)
	{
		recordFigure = false;
		if (!figurePath.isEmpty())
		{
			figurePath.closeSubpath();
			Coords.fromQPainterPath(figurePath);
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, 0, figFillColor, CommonStrings::None);
			ite->PoLine = Coords.copy();
			ite->ClipEdited = true;
			ite->FrameType = 3;
			FPoint wh = getMaxClipF(&ite->PoLine);
			ite->setWidthHeight(wh.x(),wh.y());
			ite->setTextFlowMode(PageItem::TextFlowDisabled);
			m_Doc->adjustItemSize(ite);
			ite->OldB2 = ite->width();
			ite->OldH2 = ite->height();
			ite->updateClip();
			m_Doc->Items->takeLast();
			m_Doc->Items->insert(figDocIndex, ite);
			Elements.insert(figElemIndex, ite);
			if (!groupStack.isEmpty())
				groupStack.top().insert(figGstIndex, ite);
		}
		figurePath = QPainterPath();
	//	qDebug() << "END FIGURE";
	}
	else if (elemID == 13)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		currentRegion = type;
		recordRegion = true;
		regionPath = QPainterPath();
		// qDebug() << "BEGIN PROTECTION REGION" << type;
	}
	else if (elemID == 14)
	{
		recordRegion = false;
		regionMap.insert(currentRegion, regionPath);
		// qDebug() << "END PROTECTION REGION";
	}
	else if (elemID == 15)
	{
		qDebug() << "BEGIN COMPOUND LINE";
	}
	else if (elemID == 16)
	{
		qDebug() << "END COMPOUND LINE";
	}
	else if (elemID == 17)
	{
		qDebug() << "BEGIN COMPOUND TEXT PATH";
	}
	else if (elemID == 18)
	{
		qDebug() << "END COMPOUND TEXT PATH";
	}
	else if (elemID == 19)
	{
		qDebug() << "BEGIN TILE ARRAY";
	}
	else if (elemID == 20)
	{
		qDebug() << "END TILE ARRAY";
	}
	else if (elemID == 21)
	{
		qDebug() << "BEGIN APPLICATION STRUCTURE";
	}
	else if (elemID == 22)
	{
		qDebug() << "BEGIN APPLICATION STRUCTURE BODY";
	}
	else if (elemID == 23)
	{
		qDebug() << "END APPLICATION STRUCTURE";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 0 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass1(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	quint16 data;
	if (elemID == 1)
	{
		ts >> data;
		metaFileVersion = data;
		//qDebug() << "METAFILE VERSION" << data;
	}
	else if (elemID == 2)
		handleMetaFileDescription(getBinaryText(ts));
	else if (elemID == 3)
	{
		ts >> data;
		vdcType = data;
		//qDebug() << "VDC TYPE" << data;
	}
	else if (elemID == 4)
	{
		ts >> data;
		intPrecision = data;
	//	qDebug() << "INTEGER PRECISION" << data;
	}
	else if (elemID == 5)
	{
		ts >> data;
		realPrecision = data;
		ts >> data;
		realMantissa = data;
		ts >> data;
		realFraction = data;
		if (realPrecision == 0)
			realPrecisionSet = true;
	//	qDebug() << "REAL PRECISION" << realPrecision << realMantissa << realFraction;
	}
	else if (elemID == 6)
	{
		ts >> data;
		indexPrecision = data;
	//	qDebug() << "INDEX PRECISION" << indexPrecision;
	}
	else if (elemID == 7)
	{
		ts >> data;
		colorPrecision = data;
	//	qDebug() << "COLOUR PRECISION" << colorPrecision;
	}
	else if (elemID == 8)
	{
		ts >> data;
		colorIndexPrecision = data;
		//qDebug() << "COLOUR INDEX PRECISION" << colorIndexPrecision;
	}
	else if (elemID == 9)
	{
		ts >> data;
		maxColorIndex = data;
		// qDebug() << "MAXIMUM COLOUR INDEX" << maxColorIndex;
	}
	else if (elemID == 10)
	{
		if (m_colorModel == 1)		// RGB
		{
			if (colorPrecision == 8)
			{
				quint8 r, g, b;
				ts >> r >> g >> b;
				minColor = r;
				ts >> r >> g >> b;
				maxColor = r;
			}
			else if (colorPrecision == 16)
			{
				quint16 r, g, b;
				ts >> r >> g >> b;
				minColor = r;
				ts >> r >> g >> b;
				maxColor = r;
			}
		}
		else if (m_colorModel == 4)	// CMYK
		{
			if (colorPrecision == 8)
			{
				quint8 c, m, y, k;
				ts >> c >> m >> y >> k;
				minColor = c;
				ts >> c >> m >> y >> k;
				maxColor = c;
			}
			else if (colorPrecision == 16)
			{
				quint16 c, m, y, k;
				ts >> c >> m >> y >> k;
				minColor = c;
				ts >> c >> m >> y >> k;
				maxColor = c;
			}
		}
		// qDebug() << "COLOUR VALUE EXTENT" << minColor << maxColor;
	}
	else if (elemID == 11)
	{
	//	qDebug() << "METAFILE ELEMENT LIST";
	}
	else if (elemID == 12)
	{
		qDebug() << "METAFILE DEFAULTS REPLACEMENT" << paramLen;
	/*	quint16 data, elemClass, elemID, paramLenN;
		ts >> data;
		elemClass = (data & 0xF000) >> 12;
		elemID    = (data & 0x0FE0) >>  5;
		paramLenN  = data & 0x001F;
		if (paramLenN == 31)
			ts >> paramLenN;
		qDebug() << "CGM Command Class" << elemClass << "ID" << elemID << "ParamLen" << paramLenN;
		decodeBinary(ts, elemClass, elemID, paramLenN);*/
	}
	else if (elemID == 13)
	{
		quint16 bytesRead = 0;
		int fontID = 1;
		while (bytesRead < paramLen)
		{
			auto posA = ts.device()->pos();
			QString p = getBinaryText(ts);
			auto posN = ts.device()->pos();
			bytesRead += posN - posA;
			fontID_Map.insert(fontID, p);
		}
	//	qDebug() << "FONT LIST" << fontID_Map;
	}
	else if (elemID == 14)
	{
		qDebug() << "CHARACTER SET LIST";
	}
	else if (elemID == 15)
	{
		qDebug() << "CHARACTER CODING ANNOUNCER";
	}
	else if (elemID == 16)
	{
		ts >> data;
		namePrecision = data;
 		// qDebug() << "NAME PRECISION" << namePrecision;
	}
	else if (elemID == 17)
	{
		QPointF max = getBinaryCoords(ts);
		QPointF min = getBinaryCoords(ts);
	//	qDebug() << "MAXIMUM VDC EXTENT" << min.x() << min.y() << max.x() << max.y();
	}
	else if (elemID == 18)
	{
		qDebug() << "SEGMENT PRIORITY EXTENT";
	}
	else if (elemID == 19)
	{
		ts >> data;
		m_colorModel = data;
	//	qDebug() << "COLOUR MODEL" << colorModel;
	}
	else if (elemID == 20)
	{
		qDebug() << "COLOUR CALIBRATION";
	}
	else if (elemID == 21)
	{
		qDebug() << "FONT PROPERTIES";
	}
	else if (elemID == 22)
	{
		qDebug() << "GLYPH MAPPING";
	}
	else if (elemID == 23)
	{
		qDebug() << "SYMBOL LIBRARY LIST";
	}
	else if (elemID == 24)
	{
		qDebug() << "PICTURE DIRECTORY";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 1 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass2(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	quint16 data;
	if (elemID == 1)
	{
		ts >> data;
		metaFileScaleMode = data;
		double sc = 1.0;
		if (realPrecisionSet)
			sc = getBinaryReal(ts, 0, realMantissa);
		else
			sc = getBinaryReal(ts, 0, 9);
		if (metaFileScaleMode != 0)
			metaFileScale = sc;
	//	qDebug() << "SCALING MODE" << metaFileScaleMode << metaFileScale;
	}
	else if (elemID == 2)
	{
		ts >> data;
		colorMode = data;
//		qDebug() << "COLOUR SELECTION MODE" << colorMode;
	}
	else if (elemID == 3)
	{
		ts >> data;
		lineWidthMode = data;
		if (lineWidthMode == 0)
			lineWidth = 0; // qMax(vdcWidth, vdcHeight) / 1000;
		else if (lineWidthMode == 1)
			lineWidth = 1.0;
		else if (lineWidthMode == 2)
			lineWidth = 0.001;
		else if (lineWidthMode == 3)
			lineWidth = 0.35;
	//	qDebug() << "LINE WIDTH SPECIFICATION MODE" << lineWidthMode;
	}
	else if (elemID == 4)
	{
		ts >> data;
		markerSizeMode = data;
		// qDebug() << "MARKER SIZE SPECIFICATION MODE" << markerSizeMode;
	}
	else if (elemID == 5)
	{
		ts >> data;
		edgeWidthMode = data;
		if (edgeWidthMode == 0)
			edgeWidth = 0; // qMax(vdcWidth, vdcHeight) / 1000;
		else if (edgeWidthMode == 1)
			edgeWidth = 1.0;
		else if (edgeWidthMode == 2)
			edgeWidth = 0.001;
		else if (edgeWidthMode == 3)
			edgeWidth = 0.35;
	//	qDebug() << "EDGE WIDTH SPECIFICATION MODE" << edgeWidthMode;
	}
	else if (elemID == 6)
	{
		QPointF max = getBinaryCoords(ts, true);
		QPointF min = getBinaryCoords(ts, true);
		QRectF vd(max, min);
		vcdFlippedV = (vd.height() > 0);
		vcdFlippedH = (vd.width() < 0);
		vd = vd.normalized();
		vdcWidth = vd.width();
		vdcHeight = vd.height();
		metaScale = 400.0 / qMax(vdcWidth, vdcHeight);
		if (lineWidthMode == 0)
			lineWidth = 0; // qMax(vdcWidth, vdcHeight) / 1000;
		else if (lineWidthMode == 1)
			lineWidth = 1.0;
		else if (lineWidthMode == 2)
			lineWidth = 0.001;
		else if (lineWidthMode == 3)
			lineWidth = 0.35;
		baseX = -vd.left() * metaScale;
		baseY = vd.top() * metaScale;
		vcdSet = true;
		if (!clipSet)
		{
			clipRect = QRectF(vd.left() * metaScale, vd.top() * metaScale, vdcWidth * metaScale, vdcHeight * metaScale);
			clipSet = true;
		}
	//	qDebug() << "VDC EXTENT" << vd.left() << vd.top() << vdcWidth << vdcHeight << vcdFlippedV;
	}
	else if (elemID == 7)
	{
		ScColor color = getBinaryDirectColor(ts);
		backgroundColor = handleColor(color, "FromCGM"+color.name());
		if (colorMode == 1)
			backgroundSet = true;
		else
			ColorTableMap.insert(0, backgroundColor);
//		qDebug() << "BACKGROUND COLOUR" << backgroundColor;
	}
	else if (elemID == 8)
	{
		QPointF max = getBinaryCoords(ts);
		QPointF min = getBinaryCoords(ts);
	//	qDebug() << "DEVICE VIEWPORT" << min.x() << min.y() << max.x() << max.y();
	}
	else if (elemID == 9)
	{
		ts >> data;
		viewPortScaleMode = data;
		if (realPrecisionSet)
			viewPortScale = getBinaryReal(ts, 0, realMantissa);
		else
			viewPortScale = getBinaryReal(ts, 0, 9);
		// qDebug() << "DEVICE VIEWPORT SPECIFICATION MODE" << viewPortScaleMode << viewPortScale;
	}
	else if (elemID == 10)
	{
		qDebug() << "DEVICE VIEWPORT MAPPING";
	}
	else if (elemID == 11)
	{
		qDebug() << "LINE REPRESENTATION";
	}
	else if (elemID == 12)
	{
		qDebug() << "MARKER REPRESENTATION";
	}
	else if (elemID == 13)
	{
		qDebug() << "TEXT REPRESENTATION";
	}
	else if (elemID == 14)
	{
		qDebug() << "FILL REPRESENTATION";
	}
	else if (elemID == 15)
	{
		qDebug() << "EDGE REPRESENTATION";
	}
	else if (elemID == 16)
	{
		qDebug() << "INTERIOR STYLE SPECIFICATION MODE";
	}
	else if (elemID == 17)
	{
		qDebug() << "LINE AND EDGE TYPE DEFINITION";
	}
	else if (elemID == 18)
	{
		qDebug() << "HATCH STYLE DEFINITION";
	}
	else if (elemID == 19)
	{
		qDebug() << "GEOMETRIC PATTERN DEFINITION";
	}
	else if (elemID == 20)
	{
		qDebug() << "APPLICATION STRUCTURE DIRECTORY";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 2 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass3(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	quint16 data;
	if (elemID == 1)
	{
		ts >> data;
		vdcInt = data;
 		// qDebug() << "VDC INTEGER PRECISION" << vdcInt;
	}
	else if (elemID == 2)
	{
		ts >> data;
		vdcReal = data;
		ts >> data;
		vdcMantissa = data;
		ts >> data;
 		// qDebug() << "VDC REAL PRECISION" << vdcReal << vdcMantissa;
	}
	else if (elemID == 3)
	{
		qDebug() << "AUXILIARY COLOUR";
	}
	else if (elemID == 4)
	{
		qDebug() << "TRANSPARENCY";
	}
	else if (elemID == 5)
	{
		QPointF max = getBinaryCoords(ts);
		QPointF min = getBinaryCoords(ts);
		QRectF vd(max, min);
		vd = vd.normalized();
		double w = convertCoords(vd.width());
		double h = convertCoords(vd.height());
		double x = convertCoords(vd.left());
		double y = convertCoords(vd.top());
		x += m_Doc->currentPage()->xOffset();
		y += m_Doc->currentPage()->yOffset();
		clipRect = QRectF(x, y, w, h);
		clipSet = true;
	//	qDebug() << "CLIP RECTANGLE" << clipRect;
	}
	else if (elemID == 6)
	{
		ts >> data;
		useClipRect = (data != 0);
		// qDebug() << "CLIP INDICATOR" << useClipRect;
	}
	else if (elemID == 7)
	{
		qDebug() << "LINE CLIPPING MODE";
	}
	else if (elemID == 8)
	{
		qDebug() << "MARKER CLIPPING MODE";
	}
	else if (elemID == 9)
	{
		qDebug() << "EDGE CLIPPING MODE";
	}
	else if (elemID == 10)
	{
		if (recordRegion)
			regionPath.closeSubpath();
		if (recordFigure)
			figurePath.closeSubpath();
		figClose = true;
	//	qDebug() << "NEW REGION";
	}
	else if (elemID == 11)
	{
		qDebug() << "SAVE PRIMITIVE CONTEXT";
	}
	else if (elemID == 12)
	{
		qDebug() << "RESTORE PRIMITIVE CONTEXT";
	}
	else if (elemID == 17)
	{
		uint index = getBinaryUInt(ts, indexPrecision);
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
		{
			if (!groupStack.isEmpty())
			{
				QList<PageItem*> gElements = groupStack.pop();
				tmpSel->clear();
				if (!gElements.isEmpty())
				{
					for (int dre = 0; dre < gElements.count(); ++dre)
					{
						tmpSel->addItem(gElements.at(dre));
						Elements.removeAll(gElements.at(dre));
					}
					PageItem *ite = m_Doc->itemSelection_GroupObjects(false, false, tmpSel);
					QPainterPath clip = regionMap[index];
					if (!clip.isEmpty())
					{
						ite->PoLine.fromQPainterPath(clip);
						ite->PoLine.translate(-ite->xPos(), -ite->yPos());
						ite->PoLine.translate(baseX, baseY);
					}
					tmpSel->clear();
					tmpSel->addItem(ite);
					Elements.append(ite);
				}
				if (!groupStack.isEmpty())
				{
					for (int as = 0; as < tmpSel->count(); ++as)
					{
						groupStack.top().append(tmpSel->itemAt(as));
					}
				}
				tmpSel->clear();
			}
		}
		else if ((type == 2) || (type == 3))
		{
			QList<PageItem*> gElements;
			groupStack.push(gElements);
		}
		// qDebug() << "PROTECTION REGION INDICATOR" << index << type;
	}
	else if (elemID == 18)
	{
		qDebug() << "GENERALIZED TEXT PATH MODE";
	}
	else if (elemID == 19)
	{
		qDebug() << "MITRE LIMIT";
	}
	else if (elemID == 20)
	{
		qDebug() << "TRANSPARENT CELL COLOUR";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 3 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass4(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 1)
	{
		getBinaryPath(ts, paramLen);
		if (Coords.size() > 3)
		{
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordRegion)
				regionPath.connectPath(Coords.toQPainterPath(false));
			else
			{
				if (recordFigure)
				{
					if (figClose)
					{
						QPainterPath ell = Coords.toQPainterPath(false);
						appendPath(figurePath, ell);
						figClose = false;
					}
					else
						figurePath.connectPath(Coords.toQPainterPath(false));
				}
				int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, lineWidth, CommonStrings::None, lineColor);
				PageItem *ite = m_Doc->Items->at(z);
				ite->PoLine = Coords.copy();
				finishItem(ite);
			}
		}
		// qDebug() << "POLYLINE";
	}
	else if (elemID == 2)
	{
		getBinaryPath(ts, paramLen, true);
		if (Coords.size() > 3)
		{
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordRegion)
				regionPath.connectPath(Coords.toQPainterPath(false));
			else
			{
				if (recordFigure)
				{
					if (figClose)
					{
						QPainterPath ell = Coords.toQPainterPath(false);
						appendPath(figurePath, ell);
						figClose = false;
					}
					else
						figurePath.connectPath(Coords.toQPainterPath(false));
				}
				int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, lineWidth, CommonStrings::None, lineColor);
				PageItem *ite = m_Doc->Items->at(z);
				ite->PoLine = Coords.copy();
				finishItem(ite);
			}
		}
		// qDebug() << "DISJOINT POLYLINE";
	}
	else if (elemID == 3)
	{
		qDebug() << "POLYMARKER";
	}
	else if (elemID == 4)
	{
		QPointF center = getBinaryCoords(ts);
		double txX = convertCoords(center.x());
		double txY = convertCoords(center.y());
		quint16 flag;
		ts >> flag;
		QString txt = getBinaryText(ts);
		QPainterPath ell;
		ell.addText(0, 0, QFont(fontID_Map[m_fontIndex], textSize), txt);
		ell.translate(txX, txY);
		if (textAlignH == 2)
			ell.translate(-ell.boundingRect().width() / 2.0, 0);
		else if (textAlignH == 3)
			ell.translate(-ell.boundingRect().width(), 0);
		ell.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
		if (recordRegion)
			regionPath.addPath(ell);
		else
		{
			if (recordFigure)
				figurePath.addPath(ell);
			Coords.fromQPainterPath(ell, true);
			int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, 0, textColor, CommonStrings::None);
			PageItem *ite = m_Doc->Items->at(z);
			ite->PoLine = Coords.copy();
			finishItem(ite, false);
		}
	//	qDebug() << "TEXT Len" << textAlignH;
	}
	else if (elemID == 5)
	{
		double sx = convertCoords(getBinaryDistance(ts));
		double sy = convertCoords(getBinaryDistance(ts));
		QPointF center = getBinaryCoords(ts);
		double txX = convertCoords(center.x());
		double txY = convertCoords(center.y());
		quint16 flag;
		ts >> flag;
		QString txt = getBinaryText(ts);
		QPainterPath ell;
		ell.addText(0, 0, QFont(fontID_Map[m_fontIndex], textSize), txt);
		double scx = sx / ell.boundingRect().width();
		double scy = sy / ell.boundingRect().height();
		if ((textScaleMode > 1) || ((ell.boundingRect().width() > sx) || (ell.boundingRect().height() > sy)))
		{
			QTransform mm;
			mm.scale(scx, scy);
			ell = mm.map(ell);
		}
		ell.translate(txX, txY);
		if (textAlignH == 2)
			ell.translate(-ell.boundingRect().width() / 2.0, 0);
		else if (textAlignH == 3)
			ell.translate(-ell.boundingRect().width(), 0);
		ell.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
		if (recordRegion)
			regionPath.addPath(ell);
		else
		{
			if (recordFigure)
				figurePath.addPath(ell);
			Coords.fromQPainterPath(ell, true);
			int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, 0, textColor, CommonStrings::None);
			PageItem *ite = m_Doc->Items->at(z);
			ite->PoLine = Coords.copy();
			finishItem(ite, false);
		}
	//	qDebug() << "RESTRICTED TEXT";
	}
	else if (elemID == 6)
	{
		qDebug() << "APPEND TEXT";
	}
	else if (elemID == 7)
	{
		getBinaryPath(ts, paramLen);
		if (Coords.size() > 3)
		{
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordRegion)
				regionPath.addPath(Coords.toQPainterPath(true));
			else
			{
				if (recordFigure)
					figurePath.addPath(Coords.toQPainterPath(true));
				PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, edgeWidth, fillColor, edgeColor);
				ite->PoLine = Coords.copy();
				finishItem(ite, false);
			}
		}
		// qDebug() << "POLYGON";
	}
	else if (elemID == 8)
	{
	//	qDebug() << "POLYGON SET" << "Fill Type" << fillType;
		quint16 bytesRead = 0;
		bool first = true;
		Coords.resize(0);
		Coords.svgInit();
		quint16 flag;
		paramLen = paramLen & 0x7FFF;
		QPainterPath polySetPath;
		QPointF startPoint;
		while (bytesRead < paramLen)
		{
			auto posA = ts.device()->pos();
			QPointF p = getBinaryCoords(ts);
			ts >> flag;
			auto posN = ts.device()->pos();
			bytesRead += posN - posA;
			if (first)
			{
				polySetPath.moveTo(convertCoords(p.x()), convertCoords(p.y()));
				startPoint = p;
				first = false;
			}
			else
				polySetPath.lineTo(convertCoords(p.x()), convertCoords(p.y()));
			if ((flag == 2) || (flag == 3))
			{
				polySetPath.lineTo(convertCoords(startPoint.x()), convertCoords(startPoint.y()));
				polySetPath.closeSubpath();
				first = true;
			}
		}
		polySetPath.lineTo(convertCoords(startPoint.x()), convertCoords(startPoint.y()));
		polySetPath.closeSubpath();
		if (recordFigure)
		{
			polySetPath.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			figurePath.addPath(polySetPath);
		}
		else
		{
		//	qDebug() << "POLYGON SET" << "Fill Color" << fillColor;
			Coords.fromQPainterPath(polySetPath, true);
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, edgeWidth, fillColor, edgeColor);
			ite->PoLine = Coords.copy();
			ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			finishItem(ite, false);
		}
	}
	else if (elemID == 9)
	{
		auto pos = ts.device()->pos();
		quint16 mode;
		QPointF p = convertCoords(getBinaryCoords(ts));
		QPointF q = convertCoords(getBinaryCoords(ts));
		QPointF r = convertCoords(getBinaryCoords(ts));
		int nx = getBinaryUInt(ts, intPrecision);
		int ny = getBinaryUInt(ts, intPrecision);
		int t_colorPrecision = colorPrecision;
		int t_colorIndexPrecision = colorIndexPrecision;
		colorPrecision = getBinaryUInt(ts, intPrecision);
		colorIndexPrecision = colorPrecision;
//		qDebug() << "CELL ARRAY at" << pos << "Size" << nx << ny << "Compression" << mode << "Color Prec" << colorPrecision;
		if (colorPrecision == 0)
		{
			colorPrecision = t_colorPrecision;
			colorIndexPrecision = t_colorIndexPrecision;
		}
		ts >> mode;
		auto bytesRead = ts.device()->pos() - pos;
		QLineF pr(p, r);
		QLineF rq(r, q);
		double originX = p.x();
		double originY = p.y();
		bool flipX = false;
		bool flipY = false;
		if (p.x() > r.x())
		{
			flipX = true;
			originX = r.x();
		}
		if (p.y() > q.y())
		{
			flipY = true;
			originY = q.y();
		}
		int z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Rectangle, baseX + originX, baseY + originY, pr.length(), rq.length(), edgeWidth, CommonStrings::None, CommonStrings::None);
		PageItem *ite = m_Doc->Items->at(z);
		ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
		finishItem(ite, false);
		QImage image(nx, ny, QImage::Format_ARGB32);
		quint16 flag = paramLen & 0x8000;
		quint16 pLen = (paramLen & 0x7FFF) - bytesRead;
		QByteArray imageData;
		imageData.resize(0);
		QByteArray rD = ts.device()->read(pLen);
		imageData.append(rD);
		while (flag)
		{
			ts >> pLen;
			flag = pLen & 0x8000;
			pLen = pLen & 0x7FFF;
			QByteArray rD = ts.device()->read(pLen);
			imageData.append(rD);
		}
		if (colorPrecision < 8)
		{
			auto *breader = new ScBitReader(imageData);
			for (int yy = 0; yy < ny; yy++)
			{
				ScColor color;
				auto *s = (QRgb*)(image.scanLine(yy));
				if (mode == 1)
				{
					for (int xx = 0; xx < nx; xx++)
					{
						if (colorMode == 0)
							color = m_Doc->PageColors[getBinaryIndexedColor(breader)];
						else
							color = getBinaryDirectColor(breader);
						QColor co = color.getRawRGBColor();
						*s++ = qRgba(co.red(), co.green(), co.blue(), 255);
					}
				}
				else
				{
					int xx = 0;
					while (xx < nx)
					{
						int counter = breader->getUInt(intPrecision);
						if ((counter > nx) || (counter == 0))
						{
							importRunning = false;
							return;
						}
						if (colorMode == 0)
							color = m_Doc->PageColors[getBinaryIndexedColor(breader)];
						else
							color = getBinaryDirectColor(breader);
						QColor co = color.getRawRGBColor();
						for (int xc = 0; xc < counter; xc++)
						{
							*s++ = qRgba(co.red(), co.green(), co.blue(), 255);
							xx++;
							if (xx >= nx)
								break;
						}
					}
				}
				breader->alignToWord();
			}
		}
		else
		{
			QDataStream istr(imageData);
			istr.setByteOrder(QDataStream::BigEndian);
			for (int yy = 0; yy < ny; yy++)
			{
				ScColor color;
				auto *s = (QRgb*)(image.scanLine(yy));
				if (mode == 1)
				{
					for (int xx = 0; xx < nx; xx++)
					{
						if (colorMode == 0)
							color = m_Doc->PageColors[getBinaryIndexedColor(istr)];
						else
							color = getBinaryDirectColor(istr);
						QColor co = color.getRawRGBColor();
						*s++ = qRgba(co.red(), co.green(), co.blue(), 255);
					}
				}
				else
				{
					int xx = 0;
					while (xx < nx)
					{
						int counter = getBinaryUInt(istr, intPrecision);
						if ((counter > nx) || (counter == 0))
						{
							importRunning = false;
							return;
						}
						if (colorMode == 0)
							color = m_Doc->PageColors[getBinaryIndexedColor(istr)];
						else
							color = getBinaryDirectColor(istr);
						QColor co = color.getRawRGBColor();
						for (int xc = 0; xc < counter; xc++)
						{
							*s++ = qRgba(co.red(), co.green(), co.blue(), 255);
							xx++;
							if (xx >= nx)
								break;
						}
					}
				}
				uint adj = istr.device()->pos() % 2;
				if (adj != 0)
					istr.skipRawData(1);
			}
		}
		QTemporaryFile tempFile(QDir::tempPath() + "/scribus_temp_cgm_XXXXXX.png");
		if (tempFile.open())
		{
			QString fileName = getLongPathName(tempFile.fileName());
			tempFile.setAutoRemove(false);
			tempFile.close();
			ite->isInlineImage = true;
			ite->isTempFile = true;
			image.save(fileName, "PNG");
			if ((image.width() < 20) || image.height() < 20)
				ite->pixm.imgInfo.lowResType = 0;
			m_Doc->loadPict(fileName, ite);
			ite->setImageFlippedH(flipX);
			ite->setImageFlippedV(flipY);
			ite->setImageScalingMode(false, false);
			ite->adjustPictScale();
		}
		colorPrecision = t_colorPrecision;
		colorIndexPrecision = t_colorIndexPrecision;
	}
	else if (elemID == 10)
	{
		qDebug() << "GENERALIZED DRAWING PRIMITIVE";
	}
	else if (elemID == 11)
	{
		QPointF max = getBinaryCoords(ts);
		QPointF min = getBinaryCoords(ts);
		QRectF vd(max, min);
		vd = vd.normalized();
		double w = convertCoords(vd.width());
		double h = convertCoords(vd.height());
		double x = convertCoords(vd.left());
		double y = convertCoords(vd.top());
		if (recordRegion)
			regionPath.addRect(QRectF(x + m_Doc->currentPage()->xOffset(), y + m_Doc->currentPage()->yOffset(), w, h));
		else
		{
			if (recordFigure)
				figurePath.addRect(QRectF(x + m_Doc->currentPage()->xOffset(), y + m_Doc->currentPage()->yOffset(), w, h));
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Rectangle, baseX + x, baseY + y, w, h, edgeWidth, fillColor, edgeColor);
			ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			finishItem(ite, false);
		}
	//	qDebug() << "RECTANGLE";
	}
	else if (elemID == 12)
	{
		QPointF max = getBinaryCoords(ts);
		double x = convertCoords(max.x());
		double y = convertCoords(max.y());
		double r = convertCoords(getBinaryDistance(ts));
		x = x - r;
		y = y - r;
		if (recordRegion)
			regionPath.addEllipse(QPointF(x + m_Doc->currentPage()->xOffset(), y + m_Doc->currentPage()->yOffset()), r * 2.0, r * 2.0);
		else
		{
			if (recordFigure)
				figurePath.addEllipse(QRectF(x + m_Doc->currentPage()->xOffset(), y + m_Doc->currentPage()->yOffset(), r * 2.0, r * 2.0));
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Ellipse, baseX + x, baseY + y, r * 2.0, r * 2.0, edgeWidth, fillColor, edgeColor);
			ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			finishItem(ite, false);
		}
	//	qDebug() << "CIRCLE";
	}
	else if (elemID == 13)
	{
		QPointF pStart = convertCoords(getBinaryCoords(ts));
		QPointF pInter = convertCoords(getBinaryCoords(ts));
		QPointF pEnd = convertCoords(getBinaryCoords(ts));
		QLineF s_e(pStart, pEnd);
		QLineF n_s = s_e.normalVector();
		n_s.translate(s_e.pointAt(0.5) - s_e.p1());
		QLineF s_i(pStart, pInter);
		QLineF n_i = s_i.normalVector();
		n_i.translate(s_i.pointAt(0.5) - s_i.p1());
		QPointF center;
		if (n_s.intersects(n_i, &center) != QLineF::NoIntersection)
		{
			QLineF rad1(center, pStart);
			QLineF rad3(center, pInter);
			double radius = rad1.length();
			Coords.resize(0);
			Coords.svgInit();
			Coords.svgMoveTo(pStart.x(), pStart.y());
			Coords.svgArcTo(radius, radius, 0, false, rad1.angle() >= rad3.angle(), pInter.x(), pInter.y());
			Coords.svgArcTo(radius, radius, 0, false, rad1.angle() >= rad3.angle(), pEnd.x(), pEnd.y());
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordRegion)
				regionPath.connectPath(Coords.toQPainterPath(false));
			else
			{
				if (recordFigure)
				{
					if (figClose)
					{
						QPainterPath ell = Coords.toQPainterPath(false);
						appendPath(figurePath, ell);
						figClose = false;
					}
					else
						figurePath.connectPath(Coords.toQPainterPath(false));
				}
				int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, lineWidth, CommonStrings::None, lineColor);
				PageItem *ite = m_Doc->Items->at(z);
				ite->PoLine = Coords.copy();
				finishItem(ite);
			}
		}
	//	qDebug() << "CIRCULAR ARC 3 POINT";
	}
	else if (elemID == 14)
	{
		QPointF pStart = convertCoords(getBinaryCoords(ts));
		QPointF pInter = convertCoords(getBinaryCoords(ts));
		QPointF pEnd = convertCoords(getBinaryCoords(ts));
		quint16 mode;
		ts >> mode;
		QLineF s_e(pStart, pEnd);
		QLineF n_s = s_e.normalVector();
		n_s.translate(s_e.pointAt(0.5) - s_e.p1());
		QLineF s_i(pStart, pInter);
		QLineF n_i = s_i.normalVector();
		n_i.translate(s_i.pointAt(0.5) - s_i.p1());
		QPointF center;
		if (n_s.intersects(n_i, &center) != QLineF::NoIntersection)
		{
			QLineF rad1(center, pStart);
			QLineF rad3(center, pInter);
			double radius = rad1.length();
			Coords.resize(0);
			Coords.svgInit();
			if (mode == 0)
			{
				Coords.svgMoveTo(center.x(), center.y());
				Coords.svgLineTo(pStart.x(), pStart.y());
			}
			else
				Coords.svgMoveTo(pStart.x(), pStart.y());
			Coords.svgArcTo(radius, radius, 0, false, rad1.angle() >= rad3.angle(), pInter.x(), pInter.y());
			Coords.svgArcTo(radius, radius, 0, false, rad1.angle() >= rad3.angle(), pEnd.x(), pEnd.y());
			if (mode == 0)
				Coords.svgLineTo(center.x(), center.y());
			else
				Coords.svgLineTo(pStart.x(), pStart.y());
			Coords.svgClosePath();
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordRegion)
				regionPath.addPath(Coords.toQPainterPath(false));
			else
			{
				if (recordFigure)
					figurePath.addPath(Coords.toQPainterPath(false));
				PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, edgeWidth, fillColor, edgeColor);
				ite->PoLine = Coords.copy();
				finishItem(ite, false);
			}
		}
	//	qDebug() << "CIRCULAR ARC 3 POINT CLOSE";
	}
	else if (elemID == 15)
	{
		QPointF center = getBinaryCoords(ts);
		double sx = convertCoords(getBinaryDistance(ts));
		double sy = convertCoords(getBinaryDistance(ts));
		double ex = convertCoords(getBinaryDistance(ts));
		double ey = convertCoords(getBinaryDistance(ts));
		double r = convertCoords(getBinaryDistance(ts));
		double cx = convertCoords(center.x()) + m_Doc->currentPage()->xOffset();
		double cy = convertCoords(center.y()) + m_Doc->currentPage()->yOffset();
		if (vcdFlippedV)
		{
			sy *= -1;
			ey *= -1;
		}
		if (vcdFlippedH)
		{
			sx *= -1;
			ex *= -1;
		}
		QLineF stv(cx, cy, cx + sx, cy + sy);
		QLineF env(cx, cy, cx + ex, cy + ey);
		QPainterPath ell;
		if (qFuzzyCompare(sx, ex) && qFuzzyCompare(sy, ey))
		{
			ell.addEllipse(QPointF(cx, cy), r, r);
		}
		else
		{
			stv.setLength(r);
			ell.moveTo(stv.p2().x(), stv.p2().y());
			ell.arcTo(cx - r, cy - r, r * 2.0, r * 2.0, stv.angle(), stv.angleTo(env));
		}
		if (recordRegion)
			regionPath.connectPath(ell);
		else
		{
			if (recordFigure)
			{
				if (figClose)
				{
					appendPath(figurePath, ell);
					figClose = false;
				}
				else
					figurePath.connectPath(ell);
			}
			Coords.fromQPainterPath(ell, false);
			int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, lineWidth, CommonStrings::None, lineColor);
			PageItem *ite = m_Doc->Items->at(z);
			ite->PoLine = Coords.copy();
			finishItem(ite);
		}
	//	qDebug() << "CIRCULAR ARC CENTRE";
	}
	else if (elemID == 16)
	{
		quint16 mode;
		QPointF center = getBinaryCoords(ts);
		double sx = convertCoords(getBinaryDistance(ts));
		double sy = convertCoords(getBinaryDistance(ts));
		double ex = convertCoords(getBinaryDistance(ts));
		double ey = convertCoords(getBinaryDistance(ts));
		double r = convertCoords(getBinaryDistance(ts));
		ts >> mode;
		double cx = convertCoords(center.x()) + m_Doc->currentPage()->xOffset();
		double cy = convertCoords(center.y()) + m_Doc->currentPage()->yOffset();
		if (vcdFlippedV)
		{
			sy *= -1;
			ey *= -1;
		}
		if (vcdFlippedH)
		{
			sx *= -1;
			ex *= -1;
		}
		QLineF stv(cx, cy, cx + sx, cy + sy);
		QLineF env(cx, cy, cx + ex, cy + ey);
		QPainterPath ell;
		if (qFuzzyCompare(sx, ex) && qFuzzyCompare(sy, ey))
		{
			ell.addEllipse(QPointF(cx, cy), r, r);
		}
		else
		{
			stv.setLength(r);
			if (mode == 0)
			{
				ell.moveTo(cx, cy);
				ell.arcTo(cx - r, cy - r, r * 2.0, r * 2.0, stv.angle(), stv.angleTo(env));
				ell.lineTo(cx, cy);
				ell.closeSubpath();
			}
			else
			{
				ell.moveTo(stv.p2().x(), stv.p2().y());
				ell.arcTo(cx - r, cy - r, r * 2.0, r * 2.0, stv.angle(), stv.angleTo(env));
				ell.lineTo(stv.p2().x(), stv.p2().y());
				ell.closeSubpath();
			}
		}
		if (recordRegion)
			regionPath.addPath(ell);
		else
		{
			if (recordFigure)
				figurePath.addPath(ell);
			Coords.fromQPainterPath(ell, true);
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, edgeWidth, fillColor, edgeColor);
			ite->PoLine = Coords.copy();
			finishItem(ite, false);
		}
	//	qDebug() << "CIRCULAR ARC CENTRE CLOSE";
	}
	else if (elemID == 17)
	{
		QPointF center = getBinaryCoords(ts);
		double cx = convertCoords(center.x());
		double cy = convertCoords(center.y());
		QPointF r1 = getBinaryCoords(ts);
		double r1x = convertCoords(r1.x());
		double r1y = convertCoords(r1.y());
		QPointF r2 = getBinaryCoords(ts);
		double r2x = convertCoords(r2.x());
		double r2y = convertCoords(r2.y());
		double distX = distance(r1x - cx, r1y - cy);
		double distY = distance(r2x - cx, r2y - cy);
		double rotB = xy2Deg(r1x - cx, r1y - cy);
		QPainterPath ell;
		ell.addEllipse(QPointF(0, 0), distX, distY);
		QTransform mm;
		mm.rotate(rotB);
		ell = mm.map(ell);
		ell.translate(cx, cy);
		if (recordRegion)
		{
			ell.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			regionPath.addPath(ell);
		}
		else
		{
			ell.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordFigure)
				figurePath.addPath(ell);
			Coords.fromQPainterPath(ell, true);
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, edgeWidth, fillColor, edgeColor);
			ite->PoLine = Coords.copy();
			finishItem(ite, false);
		}
	//	qDebug() << "ELLIPSE";
	}
	else if (elemID == 18)
	{
		QPointF center = getBinaryCoords(ts);
		double cx = convertCoords(center.x());
		double cy = convertCoords(center.y());
		QPointF r1 = getBinaryCoords(ts);
		double r1x = convertCoords(r1.x());
		double r1y = convertCoords(r1.y());
		QPointF r2 = getBinaryCoords(ts);
		double r2x = convertCoords(r2.x());
		double r2y = convertCoords(r2.y());
		QLineF dstX(cx, cy, r1x, r1y);
		QLineF dstY(cx, cy, r2x, r2y);
		double distX = dstX.length();
		double distY = dstY.length();
		double rotB = dstX.angle();
		double sx = convertCoords(getBinaryDistance(ts));
		double sy = convertCoords(getBinaryDistance(ts));
		double ex = convertCoords(getBinaryDistance(ts));
		double ey = convertCoords(getBinaryDistance(ts));
		if (vcdFlippedV)
		{
			sy *= -1;
			ey *= -1;
		}
		if (vcdFlippedH)
		{
			sx *= -1;
			ex *= -1;
		}
		QLineF stv(cx, cy, cx + sx, cy + sy);
		QLineF env(cx, cy, cx + ex, cy + ey);
		QPainterPath ell;
		ell.addEllipse(QPointF(cx, cy), distX, distY);
		ell.translate(-cx, -cy);
		QTransform mm;
		mm.rotate(rotB);
		ell = mm.map(ell);
		ell.translate(cx, cy);
		QPolygonF elPo = ell.toFillPolygon();
		QPointF stP = stv.p2();
		QPointF enP = env.p2();
		if (qFuzzyCompare(sx, ex) && qFuzzyCompare(sy, ey))
		{
			ell.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			Coords.fromQPainterPath(ell);
		}
		else
		{
			for (int a = 0; a < elPo.size() - 1; a++)
			{
				QPointF intersect;
				if (QLineF(elPo[a], elPo[a+1]).intersects(stv, &intersect) == QLineF::BoundedIntersection)
				{
					stP = intersect;
					break;
				}
			}
			for (int a = 0; a < elPo.size() - 1; a++)
			{
				QPointF intersect;
				if (QLineF(elPo[a], elPo[a+1]).intersects(env, &intersect) == QLineF::BoundedIntersection)
				{
					enP = intersect;
					break;
				}
			}
			Coords.resize(0);
			Coords.svgInit();
			if (dstX.angleTo(dstY) > 180)
			{
				Coords.svgMoveTo(stP.x(), stP.y());
				Coords.svgArcTo(distX, distY, rotB, stv.angleTo(env) < 180, dstX.angleTo(dstY) > 180, enP.x(), enP.y());
			}
			else
			{
				Coords.svgMoveTo(stP.x(), stP.y());
				Coords.svgArcTo(distX, distY, rotB, stv.angleTo(env) > 180, dstX.angleTo(dstY) > 180, enP.x(), enP.y());
			}
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			ell = Coords.toQPainterPath(false);
		}
		if (recordRegion)
			regionPath.connectPath(ell);
		else
		{
			if (recordFigure)
			{
				if (figClose)
				{
					appendPath(figurePath, ell);
					figClose = false;
				}
				else
					figurePath.connectPath(ell);
			}
			int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, lineWidth, CommonStrings::None, lineColor);
			PageItem *ite = m_Doc->Items->at(z);
			ite->PoLine = Coords.copy();
			finishItem(ite);
		}
	//	qDebug() << "ELLIPTICAL ARC";
	}
	else if (elemID == 19)
	{
		quint16 mode;
		QPointF center = getBinaryCoords(ts);
		double cx = convertCoords(center.x());
		double cy = convertCoords(center.y());
		QPointF r1 = getBinaryCoords(ts);
		double r1x = convertCoords(r1.x());
		double r1y = convertCoords(r1.y());
		QPointF r2 = getBinaryCoords(ts);
		double r2x = convertCoords(r2.x());
		double r2y = convertCoords(r2.y());
		QLineF dstX(cx, cy, r1x, r1y);
		QLineF dstY(cx, cy, r2x, r2y);
		double distX = dstX.length();
		double distY = dstY.length();
		double rotB = dstX.angle();
		double sx = convertCoords(getBinaryDistance(ts));
		double sy = convertCoords(getBinaryDistance(ts));
		double ex = convertCoords(getBinaryDistance(ts));
		double ey = convertCoords(getBinaryDistance(ts));
		ts >> mode;
		if (vcdFlippedV)
		{
			sy *= -1;
			ey *= -1;
		}
		if (vcdFlippedH)
		{
			sx *= -1;
			ex *= -1;
		}
		QLineF stv(cx, cy, cx + sx, cy + sy);
		QLineF env(cx, cy, cx + ex, cy + ey);
		QPainterPath ell;
		ell.addEllipse(QPointF(cx, cy), distX, distY);
		ell.translate(-cx, -cy);
		QTransform mm;
		mm.rotate(rotB);
		ell = mm.map(ell);
		ell.translate(cx, cy);
		QPolygonF elPo = ell.toFillPolygon();
		QPointF stP = stv.p2();
		for (int a = 0; a < elPo.size() - 1; a++)
		{
			QPointF intersect;
			if (QLineF(elPo[a], elPo[a+1]).intersects(stv, &intersect) == QLineF::BoundedIntersection)
			{
				stP = intersect;
				break;
			}
		}
		QPointF enP = env.p2();
		for (int a = 0; a < elPo.size() - 1; a++)
		{
			QPointF intersect;
			if (QLineF(elPo[a], elPo[a+1]).intersects(env, &intersect) == QLineF::BoundedIntersection)
			{
				enP = intersect;
				break;
			}
		}
		Coords.resize(0);
		Coords.svgInit();
		if (mode == 0)
		{
			Coords.svgMoveTo(cx, cy);
			if (dstX.angleTo(dstY) > 180)
			{
				Coords.svgLineTo(stP.x(), stP.y());
				Coords.svgArcTo(distX, distY, rotB, stv.angleTo(env) < 180, dstX.angleTo(dstY) > 180, enP.x(), enP.y());
			}
			else
			{
				Coords.svgLineTo(stP.x(), stP.y());
				Coords.svgArcTo(distX, distY, rotB, stv.angleTo(env) > 180, dstX.angleTo(dstY) > 180, enP.x(), enP.y());
			}
			Coords.svgLineTo(cx, cy);
			Coords.svgClosePath();
		}
		else
		{
			if (dstX.angleTo(dstY) > 180)
			{
				Coords.svgMoveTo(stP.x(), stP.y());
				Coords.svgArcTo(distX, distY, rotB, stv.angleTo(env) < 180, dstX.angleTo(dstY) > 180, enP.x(), enP.y());
			}
			else
			{
				Coords.svgMoveTo(stP.x(), stP.y());
				Coords.svgArcTo(distX, distY, rotB, stv.angleTo(env) > 180, dstX.angleTo(dstY) > 180, enP.x(), enP.y());
			}
			Coords.svgLineTo(stP.x(), stP.y());
			Coords.svgClosePath();
		}
		Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
		if (recordRegion)
			regionPath.addPath(Coords.toQPainterPath(false));
		else
		{
			if (recordFigure)
				figurePath.addPath(Coords.toQPainterPath(false));
			PageItem *ite = itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, edgeWidth, fillColor, edgeColor);
			ite->PoLine = Coords.copy();
			finishItem(ite, false);
		}
	//	qDebug() << "ELLIPTICAL ARC CLOSE";
	}
	else if (elemID == 20)
	{
		qDebug() << "CIRCULAR ARC CENTRE REVERSED";
	}
	else if (elemID == 21)
	{
		qDebug() << "CONNECTING EDGE";
	}
	else if (elemID == 22)
	{
		qDebug() << "HYPERBOLIC ARC";
	}
	else if (elemID == 23)
	{
		qDebug() << "PARABOLIC ARC";
	}
	else if (elemID == 24)
	{
		qDebug() << "NON-UNIFORM B-SPLINE";
	}
	else if (elemID == 25)
	{
		qDebug() << "NON-UNIFORM RATIONAL B-SPLINE";
	}
	else if (elemID == 26)
	{
		getBinaryBezierPath(ts, paramLen);
		if (Coords.size() > 3)
		{
			Coords.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
			if (recordRegion)
				regionPath.addPath(Coords.toQPainterPath(false));
			else
			{
				if (recordFigure)
				{
					if (figClose)
					{
						QPainterPath ell = Coords.toQPainterPath(false);
						appendPath(figurePath, ell);
						figClose = false;
					}
					else
						figurePath.connectPath(Coords.toQPainterPath(false));
				}
				int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, lineWidth, CommonStrings::None, lineColor);
				PageItem *ite = m_Doc->Items->at(z);
				ite->PoLine = Coords.copy();
				finishItem(ite);
			}
		}
		// qDebug() << "POLYBEZIER";
	}
	else if (elemID == 27)
	{
		qDebug() << "POLYSYMBOL";
	}
	else if (elemID == 28)
	{
		uint comp = getBinaryUInt(ts, indexPrecision);
		uint pad = getBinaryUInt(ts, intPrecision);
		QString backColor = getBinaryColor(ts);
		QString foreColor = getBinaryColor(ts);
		uint prec = getBinaryUInt(ts, intPrecision);
		qDebug() << "BITONAL TILE  Compression" << comp << "Padding" << pad << "Background" << backColor << "Foreground" << foreColor << "Precision" << prec;
	}
	else if (elemID == 29)
	{
		qDebug() << "TILE";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 4 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass5(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 1)
	{
		lineBundleIndex = getBinaryUInt(ts, indexPrecision);
 		// qDebug() << "LINE BUNDLE INDEX" << lineBundleIndex;
	}
	else if (elemID == 2)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
			lineType = Qt::SolidLine;
		else if (type == 2)
			lineType = Qt::DashLine;
		else if (type == 3)
			lineType = Qt::DotLine;
		else if (type == 4)
			lineType = Qt::DashDotLine;
		else if (type == 5)
			lineType = Qt::DashDotDotLine;
		else
			lineType = Qt::SolidLine;
 		// qDebug() << "LINE TYPE" << lineType;
	}
	else if (elemID == 3)
	{
		lineWidth = getBinaryDistance(ts);
		if (lineWidthMode == 0)
			lineWidth *= metaScale;
		else if (lineWidthMode == 1)
			lineWidth *= 1.0;
		else if (lineWidthMode == 2)
			lineWidth *= 0.001;
		else if (lineWidthMode == 3)
			lineWidth *= 0.35;
	//	if (lineWidth < 1)
	//		lineWidth = 0;
 		// qDebug() << "LINE WIDTH" << lineWidth;
	}
	else if (elemID == 4)
	{
		lineColor = getBinaryColor(ts);
		// qDebug() << "LINE COLOUR" << lineColor;
	}
	else if (elemID == 5)
	{
 		qDebug() << "MARKER BUNDLE INDEX";
	}
	else if (elemID == 6)
	{
 		qDebug() << "MARKER TYPE";
	}
	else if (elemID == 7)
	{
 		qDebug() << "MARKER SIZE";
	}
	else if (elemID == 8)
	{
 		qDebug() << "MARKER COLOUR";
	}
	else if (elemID == 9)
	{
		qDebug() << "TEXT BUNDLE INDEX";
	}
	else if (elemID == 10)
	{
		m_fontIndex = getBinaryUInt(ts, indexPrecision);
	//	qDebug() << "TEXT FONT INDEX" << m_fontIndex;
	}
	else if (elemID == 11)
	{
		qDebug() << "TEXT PRECISION";
	}
	else if (elemID == 12)
	{
		qDebug() << "CHARACTER EXPANSION FACTOR";
	}
	else if (elemID == 13)
	{
		qDebug() << "CHARACTER SPACING";
	}
	else if (elemID == 14)
	{
		textColor = getBinaryColor(ts);
	//	qDebug() << "TEXT COLOUR" << textColor;
	}
	else if (elemID == 15)
	{
		textSize = getBinaryDistance(ts);
		textSize *= metaScale;
	//	qDebug() << "CHARACTER HEIGHT" << textSize;
	}
	else if (elemID == 16)
	{
		qDebug() << "CHARACTER ORIENTATION";
	}
	else if (elemID == 17)
	{
		qDebug() << "TEXT PATH";
	}
	else if (elemID == 18)
	{
		quint16 hFlag;
		ts >> hFlag;
		textAlignH = hFlag;
	//	qDebug() << "TEXT ALIGNMENT" << hFlag;
	}
	else if (elemID == 19)
	{
		qDebug() << "CHARACTER SET INDEX";
	}
	else if (elemID == 20)
	{
		qDebug() << "ALTERNATE CHARACTER SET INDEX";
	}
	else if (elemID == 21)
	{
 		qDebug() << "FILL BUNDLE INDEX";
	}
	else if (elemID == 22)
	{
		quint16 data;
		ts >> data;
		fillType = data;
	//	qDebug() << "INTERIOR STYLE" << fillType;
	}
	else if (elemID == 23)
	{
		fillColor = getBinaryColor(ts);
	//	qDebug() << "Fill COLOUR" << fillColor;
	}
	else if (elemID == 24)
	{
 		qDebug() << "HATCH INDEX";
	}
	else if (elemID == 25)
	{
		patternIndex = getBinaryUInt(ts, indexPrecision);
		// Hack to fix some broken(?) CGM files
		//fillType = 2;
	//	qDebug() << "PATTERN INDEX" << patternIndex;
	}
	else if (elemID == 26)
	{
 		qDebug() << "EDGE BUNDLE INDEX";
	}
	else if (elemID == 27)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
			edgeType = Qt::SolidLine;
		else if (type == 2)
			edgeType = Qt::DashLine;
		else if (type == 3)
			edgeType = Qt::DotLine;
		else if (type == 4)
			edgeType = Qt::DashDotLine;
		else if (type == 5)
			edgeType = Qt::DashDotDotLine;
		else
			edgeType = Qt::SolidLine;
 		// qDebug() << "EDGE TYPE";
	}
	else if (elemID == 28)
	{
		edgeWidth = getBinaryDistance(ts);
		if (edgeWidthMode == 0)
			edgeWidth *= metaScale;
		else if (edgeWidthMode == 1)
			edgeWidth *= 1.0;
		else if (edgeWidthMode == 2)
			edgeWidth *= 0.001;
		else if (edgeWidthMode == 3)
			edgeWidth *= 0.35;
	//	if (edgeWidth < 1)
	//		edgeWidth = 0;
 		// qDebug() << "EDGE WIDTH" << edgeWidth;
	}
	else if (elemID == 29)
	{
		edgeColor = getBinaryColor(ts);
		// qDebug() << "EDGE COLOUR" << edgeColor;
	}
	else if (elemID == 30)
	{
		quint16 data;
		ts >> data;
		lineVisible = data != 0;
 		// qDebug() << "EDGE VISIBILITY";
	}
	else if (elemID == 31)
	{
		QPointF p = getBinaryCoords(ts);
		double x = convertCoords(p.x());
		double y = convertCoords(p.y());
		fillRefPoint = QPointF(x + m_Doc->currentPage()->xOffset(), y + m_Doc->currentPage()->yOffset());
	//	qDebug() << "FILL REFERENCE POINT" << fillRefPoint;
	}
	else if (elemID == 32)
	{
		uint index = getBinaryUInt(ts, indexPrecision);
		uint nx = getBinaryUInt(ts, intPrecision);
		uint ny = getBinaryUInt(ts, intPrecision);
		int t_colorPrecision = colorPrecision;
		colorPrecision = getBinaryUInt(ts, intPrecision);
		QImage tmpImg(nx, ny, QImage::Format_ARGB32);
		for (uint a = 0; a < ny; a++)
		{
			auto *s = (QRgb*) tmpImg.scanLine(a);
			for (uint b = 0; b < nx; b++)
			{
				ScColor color;
				if (colorMode == 0)
					color = m_Doc->PageColors[getBinaryIndexedColor(ts)];
				else
					color = getBinaryDirectColor(ts);
				QColor co = color.getRawRGBColor();
				*s = qRgba(co.red(), co.green(), co.blue(), 255);
				s++;
			}
		}
		int z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Rectangle, 0, 0, tmpImg.width(), tmpImg.height(), 0, CommonStrings::None, CommonStrings::None);
		PageItem* ite = m_Doc->Items->at(z);
		ite->SetRectFrame();
		ite->setTextFlowMode(PageItem::TextFlowDisabled);
		m_Doc->adjustItemSize(ite);
		ite->OldB2 = ite->width();
		ite->OldH2 = ite->height();
		QTemporaryFile tempFile(QDir::tempPath() + "/scribus_temp_cgm_XXXXXX.png");
		if (tempFile.open())
		{
			QString fileName = getLongPathName(tempFile.fileName());
			if (!fileName.isEmpty())
			{
				tempFile.setAutoRemove(false);
				tempFile.close();
				ite->isInlineImage = true;
				ite->isTempFile = true;
				tmpImg.save(fileName, "PNG");
				m_Doc->loadPict(fileName, ite);
				ite->setImageScalingMode(false, true);
				ScPattern pat(m_Doc);
				pat.pattern = tmpImg;
				pat.xoffset = 0;
				pat.yoffset = 0;
				pat.width = ite->width();
				pat.height = ite->height();
				ite->gXpos = 0;
				ite->gYpos = 0;
				ite->setXYPos(ite->gXpos, ite->gYpos, true);
				pat.items.append(ite);
				m_Doc->Items->removeAll(ite);
				QString id = QString("Pattern_from_CGM_%1").arg(m_Doc->docPatterns.count() + 1);
				m_Doc->addPattern(id, pat);
				patternTable.insert(index, id);
			}
			else
			{
				m_Doc->Items->removeAll(ite);
				delete ite;
			}
		}
		else
		{
			m_Doc->Items->removeAll(ite);
			delete ite;
		}
		colorPrecision = t_colorPrecision;
	//	qDebug() << "PATTERN TABLE" << "Index" << index << "NX" << nx << "NY" << ny;
	}
	else if (elemID == 33)
	{
		double phx = convertCoords(getBinaryDistance(ts));
		double phy = convertCoords(getBinaryDistance(ts));
		double pwx = convertCoords(getBinaryDistance(ts));
		double pwy = convertCoords(getBinaryDistance(ts));
		QLineF hp(0, 0, phx, phy);
		QLineF wp(0, 0, pwx, pwy);
		patternScaleX = wp.length();
		patternScaleY = hp.length();
	//	qDebug() << "PATTERN SIZE" << wp.length() << hp.length();
	}
	else if (elemID == 34)
	{
//		qDebug() << "COLOUR TABLE" << "Starting at" << ts.device()->pos();
		getBinaryColorTable(ts, paramLen);
	}
	else if (elemID == 35)
	{
		qDebug() << "ASPECT SOURCE FLAGS";
	}
	else if (elemID == 36)
	{
		qDebug() << "PICK IDENTIFIER";
	}
	else if (elemID == 37)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
			lineCap = Qt::FlatCap;
		else if (type == 2)
			lineCap = Qt::RoundCap;
		else if (type == 3)
			lineCap = Qt::SquareCap;
		else
			lineCap = Qt::FlatCap;
		type = getBinaryUInt(ts, indexPrecision);		// dummy reading unsupported parameter
		// qDebug() << "LINE CAP";
	}
	else if (elemID == 38)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
			lineJoin = Qt::MiterJoin;
		else if (type == 2)
			lineJoin = Qt::RoundJoin;
		else if (type == 3)
			lineJoin = Qt::BevelJoin;
		else
			lineJoin = Qt::MiterJoin;
		// qDebug() << "LINE JOIN";
	}
	else if (elemID == 39)
	{
		qDebug() << "LINE TYPE CONTINUATION";
	}
	else if (elemID == 40)
	{
		qDebug() << "LINE TYPE INITIAL OFFSET";
	}
	else if (elemID == 41)
	{
		qDebug() << "TEXT SCORE TYPE";
	}
	else if (elemID == 42)
	{
		textScaleMode = getBinaryUInt(ts, indexPrecision);
		qDebug() << "RESTRICTED TEXT TYPE" << textScaleMode;
	}
	else if (elemID == 43)
	{
		auto posI = ts.device()->pos();
		uint type = getBinaryUInt(ts, indexPrecision);
		QPointF p1 = convertCoords(getBinaryCoords(ts));
		QPointF p2 = convertCoords(getBinaryCoords(ts));
		uint index = getBinaryUInt(ts, intPrecision);
	//	qDebug() << "INTERPOLATED INTERIOR  Type" << type << "from" << p1 << "to" << p2 << "Stages" << index << "at" << posI << realPrecision << realMantissa;
		for (uint s = 0; s < index; s++)
		{
			double s1 = getBinaryReal(ts, realPrecision, realMantissa);
			qDebug() << "Stages " << s1;
		}
		Q_UNUSED(posI);
		Q_UNUSED(type);
		Q_UNUSED(p1);
		Q_UNUSED(p2);
/*		int pos = ts.device()->pos();
		uint type = getBinaryUInt(ts, indexPrecision);
		QPointF p, p2;
		if (type == 1)
		{
			int posE = ts.device()->pos();
			p = QPointF(convertCoords(getBinaryDistance(ts)), convertCoords(getBinaryDistance(ts)));
			qDebug() << "End Point" << p << " at" << posE;
		}
		else if (type == 2)
		{
			int posE = ts.device()->pos();
			p = QPointF(convertCoords(getBinaryDistance(ts)), convertCoords(getBinaryDistance(ts)));
			p2 = QPointF(convertCoords(getBinaryDistance(ts)), convertCoords(getBinaryDistance(ts)));
			qDebug() << "Points" << p << p2 << " at" << posE;
		}
		int posI = ts.device()->pos();
		uint index = getBinaryUInt(ts, intPrecision);
		qDebug() << "Stages " << index << " at" << posI;
		for (uint s = 0; s < index; s++)
		{
			double s1 = getBinaryReal(ts, realPrecision, realMantissa);
			qDebug() << "first 2 Stages " << s1;
		}
		ts.device()->seek(pos); */
	//	qDebug() << "INTERPOLATED INTERIOR  Type" << type << "from" << p1 << "to" << p2 << "Stages" << index << "at" << posI;
	}
	else if (elemID == 44)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
			edgeCap = Qt::FlatCap;
		else if (type == 2)
			edgeCap = Qt::RoundCap;
		else if (type == 3)
			edgeCap = Qt::SquareCap;
		else
			edgeCap = Qt::FlatCap;
		type = getBinaryUInt(ts, indexPrecision);		// dummy reading unsupported parameter
 		// qDebug() << "EDGE CAP";
	}
	else if (elemID == 45)
	{
		uint type = getBinaryUInt(ts, indexPrecision);
		if (type == 1)
			edgeJoin = Qt::MiterJoin;
		else if (type == 2)
			edgeJoin = Qt::RoundJoin;
		else if (type == 3)
			edgeJoin = Qt::BevelJoin;
		else
			edgeJoin = Qt::MiterJoin;
		// qDebug() << "EDGE JOIN";
	}
	else if (elemID == 46)
	{
		qDebug() << "EDGE TYPE CONTINUATION";
	}
	else if (elemID == 47)
	{
		qDebug() << "EDGE TYPE INITIAL OFFSET";
	}
	else if (elemID == 48)
	{
		qDebug() << "SYMBOL LIBRARY INDEX";
	}
	else if (elemID == 49)
	{
		qDebug() << "SYMBOL COLOUR";
	}
	else if (elemID == 50)
	{
		qDebug() << "SYMBOL SIZE";
	}
	else if (elemID == 51)
	{
		qDebug() << "SYMBOL ORIENTATION";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 5 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass6(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 1)
	{
		qDebug() << "ESCAPE";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 6 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass7(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 1)
	{
		qDebug() << "MESSAGE";
	}
	else if (elemID == 2)
	{
		qDebug() << "APPLICATION DATA" << paramLen << "at" << ts.device()->pos();
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 7 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass8(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 1)
	{
		qDebug() << "COPY SEGMENT";
	}
	else if (elemID == 2)
	{
		qDebug() << "INHERITANCE FILTER";
	}
	else if (elemID == 3)
	{
		qDebug() << "CLIP INHERITANCE";
	}
	else if (elemID == 4)
	{
		qDebug() << "SEGMENT TRANSFORMATION";
	}
	else if (elemID == 5)
	{
		qDebug() << "SEGMENT HIGHLIGHTING";
	}
	else if (elemID == 6)
	{
		qDebug() << "SEGMENT DISPLAY PRIORITY";
	}
	else if (elemID == 7)
	{
		qDebug() << "SEGMENT PICK PRIORITY";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 8 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::decodeClass9(QDataStream &ts, quint16 elemID, quint16 paramLen)
{
	if (elemID == 1)
	{
		qDebug() << "APPLICATION STRUCTURE ATTRIBUTE";
	}
	else
	{
		importRunning = false;
		qDebug() << "Class 9 ID" << elemID << "Len" << paramLen;
	}
}

void CgmPlug::getBinaryBezierPath(QDataStream &ts, quint16 paramLen)
{
	quint16 bytesRead = 0;
	bool first = true;
	Coords.resize(0);
	Coords.svgInit();
	quint16 flag;
	flag = paramLen & 0x8000;
	paramLen = paramLen & 0x7FFF;
	uint type = getBinaryUInt(ts, indexPrecision);
	while (bytesRead < paramLen - 2)
	{
		auto posA = ts.device()->pos();
		if (first || (type == 1))
		{
			QPointF p = getBinaryCoords(ts);
			Coords.svgMoveTo(convertCoords(p.x()), convertCoords(p.y()));
			first = false;
		}
		QPointF p1 = getBinaryCoords(ts);
		QPointF p2 = getBinaryCoords(ts);
		QPointF p3 = getBinaryCoords(ts);
		Coords.svgCurveToCubic(convertCoords(p1.x()), convertCoords(p1.y()), convertCoords(p2.x()), convertCoords(p2.y()), convertCoords(p3.x()), convertCoords(p3.y()));
		auto posN = ts.device()->pos();
		bytesRead += posN - posA;
	}
	while (flag)
	{
		bytesRead = 0;
		ts >> paramLen;
		flag = paramLen & 0x8000;
		paramLen = paramLen & 0x7FFF;
		while (bytesRead < paramLen)
		{
			auto posA = ts.device()->pos();
			if (type == 1)
			{
				QPointF p = getBinaryCoords(ts);
				Coords.svgMoveTo(convertCoords(p.x()), convertCoords(p.y()));
			}
			QPointF p1 = getBinaryCoords(ts);
			QPointF p2 = getBinaryCoords(ts);
			QPointF p3 = getBinaryCoords(ts);
			Coords.svgCurveToCubic(convertCoords(p1.x()), convertCoords(p1.y()), convertCoords(p2.x()), convertCoords(p2.y()), convertCoords(p3.x()), convertCoords(p3.y()));
			auto posN = ts.device()->pos();
			bytesRead += posN - posA;
		}
	}
}

void CgmPlug::getBinaryPath(QDataStream &ts, quint16 paramLen, bool disjoint)
{
	quint16 bytesRead = 0;
	bool first = true;
	Coords.resize(0);
	Coords.svgInit();
	quint16 flag;
	flag = paramLen & 0x8000;
	paramLen = paramLen & 0x7FFF;
	while (bytesRead < paramLen)
	{
		auto posA = ts.device()->pos();
		QPointF p = getBinaryCoords(ts);
		if (first)
		{
			Coords.svgMoveTo(convertCoords(p.x()), convertCoords(p.y()));
			first = false;
		}
		else
		{
			Coords.svgLineTo(convertCoords(p.x()), convertCoords(p.y()));
			if (disjoint)
				first = true;
		}
		auto posN = ts.device()->pos();
		bytesRead += posN - posA;
	}
	while (flag)
	{
		bytesRead = 0;
		ts >> paramLen;
		flag = paramLen & 0x8000;
		paramLen = paramLen & 0x7FFF;
		while (bytesRead < paramLen)
		{
			auto posA = ts.device()->pos();
			if (disjoint)
			{
				QPointF p = getBinaryCoords(ts);
				if (first)
				{
					Coords.svgMoveTo(convertCoords(p.x()), convertCoords(p.y()));
					first = false;
				}
				else
				{
					Coords.svgLineTo(convertCoords(p.x()), convertCoords(p.y()));
					if (disjoint)
						first = true;
				}
			}
			else
			{
				QPointF p = getBinaryCoords(ts);
				Coords.svgLineTo(convertCoords(p.x()), convertCoords(p.y()));
			}
			auto posN = ts.device()->pos();
			bytesRead += posN - posA;
		}
	}
}

void CgmPlug::getBinaryColorTable(QDataStream &ts, quint16 paramLen)
{
	quint16 flag;
	flag = paramLen & 0x8000;
	paramLen = paramLen & 0x7FFF;
	quint16 bytesRead = 0;
	auto posA = ts.device()->pos();
	uint c = getBinaryUInt(ts, colorIndexPrecision);
	auto posN = ts.device()->pos();
	bytesRead += posN - posA;
	QString tmpName = CommonStrings::None;
	while (bytesRead < paramLen)
	{
		posA = ts.device()->pos();
		ScColor cc = getBinaryDirectColor(ts);
		tmpName = handleColor(cc, "FromCGM"+cc.name());
		ColorTableMap.insert(c, tmpName);
		c++;
		posN = ts.device()->pos();
		bytesRead += posN - posA;
	}
	while (flag)
	{
		bytesRead = 0;
		ts >> paramLen;
		flag = paramLen & 0x8000;
		paramLen = paramLen & 0x7FFF;
		while (bytesRead < paramLen)
		{
			posA = ts.device()->pos();
			//ScColor cc = getBinaryDirectColor(ts);
			ColorTableMap.insert(c, tmpName);
			c++;
			posN = ts.device()->pos();
			bytesRead += posN - posA;
		}
	}
}

ScColor CgmPlug::getBinaryDirectColor(ScBitReader *breader) const
{
	ScColor ret;
	if (m_colorModel == 1)		// RGB
	{
		int r = breader->getUInt(colorPrecision);
		int g = breader->getUInt(colorPrecision);
		int b = breader->getUInt(colorPrecision);
		r = qRound(r * (maxColor - minColor) / static_cast<double>(maxColor));
		g = qRound(g * (maxColor - minColor) / static_cast<double>(maxColor));
		b = qRound(b * (maxColor - minColor) / static_cast<double>(maxColor));
		ret = ScColor(r, g, b);
	}
	else if (m_colorModel == 4)	// CMYK
	{
		uint c = breader->getUInt(colorPrecision);
		uint m = breader->getUInt(colorPrecision);
		uint y = breader->getUInt(colorPrecision);
		uint k = breader->getUInt(colorPrecision);
		c = qRound(c * (maxColor - minColor) / static_cast<double>(maxColor));
		m = qRound(m * (maxColor - minColor) / static_cast<double>(maxColor));
		y = qRound(y * (maxColor - minColor) / static_cast<double>(maxColor));
		k = qRound(k * (maxColor - minColor) / static_cast<double>(maxColor));
		ret = ScColor(c, m, y, k);
	}
	return ret;
}

ScColor CgmPlug::getBinaryDirectColor(QDataStream &ts) const
{
	ScColor ret;
	if (m_colorModel == 1)		// RGB
	{
		if (colorPrecision == 8)
		{
			quint8 ri, gi, bi;
			ts >> ri >> gi >> bi;
			int r = ri;
			int g = gi;
			int b = bi;
			r = qRound(r * (maxColor - minColor) / static_cast<double>(maxColor));
			g = qRound(g * (maxColor - minColor) / static_cast<double>(maxColor));
			b = qRound(b * (maxColor - minColor) / static_cast<double>(maxColor));
			ret = ScColor(r, g, b);
		}
		else if (colorPrecision == 16)
		{
			quint16 ri, gi, bi;
			ts >> ri >> gi >> bi;
			int r = ri;
			int g = gi;
			int b = bi;
			r = qRound((r * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			g = qRound((g * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			b = qRound((b * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			ret = ScColor(r, g, b);
		}
		else if (colorPrecision == 24)
		{
			quint8  p1;
			quint16 p2;
			quint32 ri = 0;
			quint32 gi = 0;
			quint32 bi = 0;
			ts >> p2;
			ts >> p1;
			ri = p2 << 8;
			ri |= p1;
			ts >> p2;
			ts >> p1;
			gi = p2 << 8;
			gi |= p1;
			ts >> p2;
			ts >> p1;
			bi = p2 << 8;
			bi |= p1;
			int r = ri;
			int g = gi;
			int b = bi;
			r = qRound((r * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			g = qRound((g * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			b = qRound((b * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			ret = ScColor(r, g, b);
		}
		else if (colorPrecision == 32)
		{
			quint32 ri, gi, bi;
			ts >> ri >> gi >> bi;
			int r = ri;
			int g = gi;
			int b = bi;
			r = qRound((r * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			g = qRound((g * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			b = qRound((b * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			ret = ScColor(r, g, b);
		}
	}
	else if (m_colorModel == 4)	// CMYK
	{
		if (colorPrecision == 8)
		{
			quint8 ci, mi, yi, ki;
			ts >> ci >> mi >> yi >> ki;
			uint c = ci;
			uint m = mi;
			uint y = yi;
			uint k = ki;
			c = qRound(c * (maxColor - minColor) / static_cast<double>(maxColor));
			m = qRound(m * (maxColor - minColor) / static_cast<double>(maxColor));
			y = qRound(y * (maxColor - minColor) / static_cast<double>(maxColor));
			k = qRound(k * (maxColor - minColor) / static_cast<double>(maxColor));
			ret = ScColor(c, m, y, k);
		}
		else if (colorPrecision == 16)
		{
			quint16 ci, mi, yi, ki;
			ts >> ci >> mi >> yi >> ki;
			uint c = ci;
			uint m = mi;
			uint y = yi;
			uint k = ki;
			c = qRound((c * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			m = qRound((m * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			y = qRound((y * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			k = qRound((k * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			ret = ScColor(c, m, y, k);
		}
		else if (colorPrecision == 24)
		{
			quint8  p1;
			quint16 p2;
			quint32 ci = 0;
			ts >> p2;
			ts >> p1;
			ci = p2 << 8;
			ci |= p1;
			quint32 mi = 0;
			ts >> p2;
			ts >> p1;
			mi = p2 << 8;
			mi |= p1;
			quint32 yi = 0;
			ts >> p2;
			ts >> p1;
			yi = p2 << 8;
			yi |= p1;
			quint32 ki = 0;
			ts >> p2;
			ts >> p1;
			ki = p2 << 8;
			ki |= p1;
			uint c = ci;
			uint m = mi;
			uint y = yi;
			uint k = ki;
			c = qRound((c * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			m = qRound((m * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			y = qRound((y * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			k = qRound((k * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			ret = ScColor(c, m, y, k);
		}
		else if (colorPrecision == 32)
		{
			quint32 ci, mi, yi, ki;
			ts >> ci >> mi >> yi >> ki;
			uint c = ci;
			uint m = mi;
			uint y = yi;
			uint k = ki;
			c = qRound((c * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			m = qRound((m * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			y = qRound((y * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			k = qRound((k * (maxColor - minColor) / static_cast<double>(maxColor)) / static_cast<double>(maxColor) * 255.0);
			ret = ScColor(c, m, y, k);
		}
	}
	return ret;
}

QString CgmPlug::getBinaryIndexedColor(ScBitReader *breader)
{
	QString ret = "Black";
	uint c = breader->getUInt(colorIndexPrecision);
	if (ColorTableMap.contains(c) && (c <= maxColorIndex))
		ret = ColorTableMap[c];
	return ret;
}

QString CgmPlug::getBinaryIndexedColor(QDataStream &ts)
{
	QString ret = "Black";
	uint c = getBinaryUInt(ts, colorIndexPrecision);
	if (ColorTableMap.contains(c) && (c <= maxColorIndex)) 
		ret = ColorTableMap[c];
	return ret;
}

QString CgmPlug::getBinaryColor(QDataStream &ts)
{
	QString ret;
	ScColor color;
	if (colorMode == 0)
	{
		ret = getBinaryIndexedColor(ts);
	}
	else
	{
		color = getBinaryDirectColor(ts);
		ret = handleColor(color, "FromCGM"+color.name());
	}
	return ret;
}

double CgmPlug::getBinaryDistance(QDataStream &ts) const
{
	double ret = 0.0;
	if (vdcType == 0)				// integer coords
	{
		int x = getBinaryInt(ts, vdcInt);
		ret = x;
	}
	else
		ret = getBinaryReal(ts, vdcReal, vdcMantissa);
	return ret;
}

QPointF CgmPlug::getBinaryCoords(QDataStream &ts, bool raw) const
{
	QPointF ret(0.0, 0.0);
	if (vdcType == 0)				// integer coords
	{
		int x = getBinaryInt(ts, vdcInt);
		int y = getBinaryInt(ts, vdcInt);
		if (!raw)
		{
			if (vcdFlippedV)
				y = vdcHeight - y;
			if (vcdFlippedH)
				x = vdcWidth - x;
		}
		ret = QPointF(x, y);
	}
	else
	{
		double x = getBinaryReal(ts, vdcReal, vdcMantissa);
		double y = getBinaryReal(ts, vdcReal, vdcMantissa);
		if (!raw)
		{
			if (vcdFlippedV)
				y = vdcHeight - y;
			if (vcdFlippedH)
				x = vdcWidth - x;
		}
		ret = QPointF(x, y);
	}
	return ret;
}

uint CgmPlug::getBinaryUInt(QDataStream &ts, int intP) const
{
	uint val = 0;
	if (intP == 1)
	{
		quint8 data;
		ts >> data;
		val = data >> 7;
	}
	else if (intP == 8)
	{
		quint8 data;
		ts >> data;
		val = data;
	}
	else if (intP == 16)
	{
		quint16 data;
		ts >> data;
		val = data;
	}
	else if (intP == 24)
	{
		quint8  p1;
		quint16 p2;
		quint32 data = 0;
		ts >> p2;
		ts >> p1;
		data = p2 << 8;
		data |= p1;
		val = data;
	}
	else if (intP == 32)
	{
		quint32 data;
		ts >> data;
		val = data;
	}
	return val;
}

int CgmPlug::getBinaryInt(QDataStream &ts, int intP) const
{
	int val = 0;
	if (intP == 8)
	{
		qint8 data;
		ts >> data;
		val = data;
	}
	else if (intP == 16)
	{
		qint16 data;
		ts >> data;
		val = data;
	}
	else if (intP == 24)
	{
		qint8  p1;
		qint16 p2;
		qint32 data = 0;
		ts >> p2;
		ts >> p1;
		data = p2 << 8;
		data |= p1;
		val = data;
	}
	else if (intP == 32)
	{
		qint32 data;
		ts >> data;
		val = data;
	}
	return val;
}

double CgmPlug::getBinaryReal(QDataStream &ts, int realP, int realM) const
{
	double val = 0.0;
	if (realP == 0)			// real Format
	{
		if (realM == 9)		// 32bit
		{
			ts.setFloatingPointPrecision(QDataStream::SinglePrecision);
			float data;
			ts >> data;
			val = data;
		}
		else
		{
			ts.setFloatingPointPrecision(QDataStream::DoublePrecision);
			double data;
			ts >> data;
			val = data;
		}
	}
	else							// fixed Point Format
	{
		if (realM == 16)	// 32bit
		{
			quint16 fraction;
			qint16 whole;
			ts >> whole;
			ts >> fraction;
			int gpart = whole;
			val = gpart + (fraction / static_cast<double>(0xFFFF));
/*			quint16 flag = whole & 0x8000;
			whole = whole & 0x7FFF;
			if (flag)
				val = whole - (fraction / static_cast<double>(0xFFFF));
			else
				val = whole + (fraction / static_cast<double>(0xFFFF)); */
		}
		else
		{
			quint32 fraction;
			qint32 whole;
			ts >> whole;
			ts >> fraction;
			int gpart = whole;
			val = gpart + (fraction / static_cast<double>(0xFFFFFFFF));
/*			quint32 flag = whole & 0x80000000;
			whole = whole & 0x7FFFFFFF;
			if (flag)
				val = whole - (fraction / static_cast<double>(0xFFFFFFFF));
			else
				val = whole + (fraction / static_cast<double>(0xFFFFFFFF)); */
		}
	}
	return val;
}

QString CgmPlug::getBinaryText(QDataStream &ts) const
{
	quint8 textLen;
	QByteArray text;
	ts >> textLen;
	if (textLen == 0)
		ts >> textLen;
	if (textLen < 255)
	{
		text.resize(textLen);
		ts.readRawData(text.data(), textLen);
	}
	else
	{
		quint16 extTextLen;
		quint16 flag;
		QByteArray textE;
		ts >> extTextLen;
		flag = extTextLen & 0x8000;
		extTextLen = extTextLen & 0x7FFF;
		textE.resize(extTextLen);
		ts.readRawData(textE.data(), extTextLen);
		alignStreamToWord(ts, 0);
		text += textE;
		while (flag)
		{
			ts >> extTextLen;
			flag = extTextLen & 0x8000;
			extTextLen = extTextLen & 0x7FFF;
			textE.resize(extTextLen);
			ts.readRawData(textE.data(), extTextLen);
			text += textE;
		}
	}
	return text;
}

void CgmPlug::alignStreamToWord(QDataStream &ts, uint len) const
{
	quint16 flag;
	flag = len & 0x8000;
	quint16 paramLen = len & 0x7FFF;
	ts.skipRawData(paramLen);
	while (flag)
	{
		ts >> paramLen;
		flag = paramLen & 0x8000;
		paramLen = paramLen & 0x7FFF;
		ts.skipRawData(paramLen);
	}
	uint adj = ts.device()->pos() % 2;
	if (adj != 0)
		ts.skipRawData(1);
}
/* End binary Decoder */

/* Start of core Functions common to both Decoders */

void CgmPlug::handleStartMetaFile(const QString& value)
{
	if (importerFlags & LoadSavePlugin::lfCreateDoc)
		m_Doc->documentInfo().setTitle(value);
	// qDebug() << "Start Metafile" << value;
}

void CgmPlug::handleStartPicture(const QString& value)
{
	pictName = value;
//	qDebug() << "Start Picture" << value;
}

void CgmPlug::handleStartPictureBody(double width, double height)
{
	if (importerFlags & LoadSavePlugin::lfCreateDoc)
	{
		if (firstPage)
		{
			m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
			if (width > height)
				m_Doc->setPageOrientation(1);
			else
				m_Doc->setPageOrientation(0);
			m_Doc->setPageSize("Custom");
			m_Doc->changePageProperties(0, 0, 0, 0, height, width, height, width, m_Doc->pageOrientation(), m_Doc->pageSize(), m_Doc->currentPage()->pageNr(), false);
		}
		else
		{
			if (wasEndPic)
			{
				m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
				m_Doc->addPage(m_Doc->currentPage()->pageNr()+1);
				m_Doc->view()->addPage(m_Doc->currentPage()->pageNr(), true);
			}
		}
		wasEndPic = false;
		firstPage = false;
	}
}

void CgmPlug::handleMetaFileDescription(const QString& value)
{
	if (importerFlags & LoadSavePlugin::lfCreateDoc)
		m_Doc->documentInfo().setComments(value);
	// qDebug() << "Metafile Description" << value;
}

QString CgmPlug::handleColor(const ScColor &color, const QString& proposedName)
{
	QString tmpName = m_Doc->PageColors.tryAddColor(proposedName, color);
	if (tmpName == proposedName)
		importedColors.append(tmpName);
	return tmpName;
}

double CgmPlug::convertCoords(double input) const
{
	return input * metaScale;
}

QPointF CgmPlug::convertCoords(const QPointF& input) const
{
	return input * metaScale;
}

void CgmPlug::appendPath(QPainterPath &path1, const QPainterPath &path2) const
{
	for (int i = 0; i < path2.elementCount(); ++i)
	{
		const QPainterPath::Element &elm = path2.elementAt(i);
		switch (elm.type)
		{
			case QPainterPath::MoveToElement:
				path1.moveTo(elm.x, elm.y);
				break;
			case QPainterPath::LineToElement:
				path1.lineTo(elm.x, elm.y);
				break;
			case QPainterPath::CurveToElement:
				path1.cubicTo(elm.x, elm.y, path2.elementAt(i+1).x, path2.elementAt(i+1).y, path2.elementAt(i+2).x, path2.elementAt(i+2).y );
				break;
			default:
				break;
		}
	}
}

PageItem* CgmPlug::itemAdd(PageItem::ItemType itemType, PageItem::ItemFrameType frameType, double x, double y, double b, double h, double w, const QString& fill, const QString& stroke)
{
	int z;
	if (lineVisible)
	{
		if (fillType == 0)
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, CommonStrings::None, stroke);
		else if ((fillType == 1) || (fillType == 3))
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, fill, stroke);
		else if (fillType == 2)
		{
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, fill, stroke);
			if (patternTable.contains(patternIndex))
			{
				PageItem *ite = m_Doc->Items->at(z);
				ite->setPattern(patternTable[patternIndex]);
				ScPattern pat = m_Doc->docPatterns[patternTable[patternIndex]];
				double patSX = 1.0;
				double patSY = 1.0;
				if (patternScaleX > -1)
					patSX = patternScaleX / pat.width;
				if (patternScaleY > -1)
					patSY = patternScaleY / pat.height;
				ite->setPatternTransform(patSX, patSY, 0, 0, 0, 0.0, 0.0);
				ite->GrType = Gradient_Pattern;
			}
		}
		else if (fillType == 4)
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, CommonStrings::None, stroke);
		else
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, fill, stroke);
	}
	else
	{
		if (fillType == 0)
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, CommonStrings::None, fill);
		else if ((fillType == 1) || (fillType == 3))
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, fill, CommonStrings::None);
		else if (fillType == 2)
		{
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, fill, CommonStrings::None);
			if (patternTable.contains(patternIndex))
			{
				PageItem *ite = m_Doc->Items->at(z);
				ite->setPattern(patternTable[patternIndex]);
				ScPattern pat = m_Doc->docPatterns[patternTable[patternIndex]];
				double patSX = 1.0;
				double patSY = 1.0;
				if (patternScaleX > -1)
					patSX = patternScaleX / pat.width;
				if (patternScaleY > -1)
					patSY = patternScaleY / pat.height;
				ite->setPatternTransform(patSX, patSY, 0, 0, 0, 0.0, 0.0);
				ite->GrType = Gradient_Pattern;
			}
		}
		else
			z = m_Doc->itemAdd(itemType, frameType, x, y, b, h, w, CommonStrings::None, CommonStrings::None);
	}
	return m_Doc->Items->at(z);
}

void CgmPlug::finishItem(PageItem* ite, bool line)
{
	ite->ClipEdited = true;
	ite->FrameType = 3;
	FPoint wh = getMaxClipF(&ite->PoLine);
	ite->setWidthHeight(wh.x(),wh.y());
	ite->setTextFlowMode(PageItem::TextFlowDisabled);
	m_Doc->adjustItemSize(ite);
	ite->OldB2 = ite->width();
	ite->OldH2 = ite->height();
	if (line)
	{
		ite->setLineStyle(lineType);
		ite->setLineEnd(lineCap);
		ite->setLineJoin(lineJoin);
	}
	else
	{
		ite->setLineStyle(edgeType);
		ite->setLineEnd(edgeCap);
		ite->setLineJoin(edgeJoin);
	}
	ite->updateClip();
	Elements.append(ite);
	if (!groupStack.isEmpty())
		groupStack.top().append(ite);
	Coords.resize(0);
	Coords.svgInit();
}
