fonzie
clone your own copy | download snapshot

Snapshots | iceberg

No images in this repository’s iceberg at this time

Inside this repository

main.cpp
text/x-c++src

Download raw (15.1 KB)

/***************************************************************************
 *   Copyright (C) 2010 by Pierre Marchand   *
 *   pierre@oep-h.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//#define WITH_TESSERACT
#include <QCoreApplication>

#include "scanimage.h"
#include "glyphtrace.h"
#include "fontupdate.h"
#include "options.h"
#include "gridspec.h"
#include "names.h"
#include "magicmetrics.h"
#include "ufotemplate.h"

#ifdef WITH_TESSERACT
#include "document.h"
#include "composer.h"
#endif


// #define WITH_TESSERACT
#ifdef WITH_TESSERACT
#include "ocr.h"
#endif

#include <QStringList>
#include <QDebug>
#include <QMap>
#include <QFile>
#include <QDir>
#include <QString>

//#define WITH_CAPTURE
#ifdef WITH_CAPTURE
#include "orm.h"
#endif

//#define WITH_BOOK_SCANNER
#ifdef WITH_BOOK_SCANNER
#include "bookscanner.h"
#endif


int main(int ac, char ** av)
{
	QCoreApplication app(ac, av);
#ifdef WITH_TESSERACT
	if(app.argc() > 1)
	{
		Options opt(app.arguments());
		opt.Dump();

		GlyphTrace::Options ptOpt;
		if(opt.contains(OPTPT_ALPHAMAX))
			ptOpt.alphamax = opt.toDouble(OPTPT_ALPHAMAX);
		if(opt.contains(OPTPT_TURDSIZE))
			ptOpt.turdsize = opt.toDouble(OPTPT_TURDSIZE);
		if(opt.contains(OPTPT_OPTICURVE))
			ptOpt.opticurve = opt.toDouble(OPTPT_OPTICURVE);
		if(opt.contains(OPTPT_OPTTOLERANCE))
			ptOpt.opttolerance = opt.toDouble(OPTPT_OPTTOLERANCE);

		double scale(opt.toDouble(OPTSCALE));
		if(scale == 0.0)
			scale = 1.0;
		//	double offset(opt.toDouble(OPTOFFSET));
		//	int baseline(opt.toInt(OPTBASELINE));
		QList<GlyphTrace*> allGlyphs;

		bool doCrop(false);
		bool isRightPage(true);
		QRect cropRight;
		QRect cropLeft;
		if(opt.contains(OPTCROPPAGELEFT) && opt.contains(OPTCROPPAGERIGHT))
		{
			QStringList cr(opt.value(OPTCROPPAGERIGHT).split("+"));
			if(cr.count() >= 4)
			{
				cropRight = QRect(cr[0].toInt(),cr[1].toInt(),cr[2].toInt(),cr[3].toInt());
				cr = QStringList(opt.value(OPTCROPPAGELEFT).split("+"));
				if(cr.count() >= 4)
				{
					cropLeft = QRect(cr[0].toInt(),cr[1].toInt(),cr[2].toInt(),cr[3].toInt());
				}

				doCrop = true;
			}
		}

		int iCount(opt.Count(OPTIMAGE));
#ifdef WITH_CAPTURE
		ORM * orm;
		bool hasORM(false);
		if(opt.contains(OPTCAPTURE))
		{
			iCount = opt.toInt(OPTCAPTURE);
			orm = new ORM(opt.value(OPTCAMLEFT), opt.value(OPTCAMRIGHT));
			hasORM = true;
		}
		ORM::CameraSelect camsel(ORM::Left);
#endif

		qDebug()<<"Images Count: "<<iCount;
		QList<QChar> processed;
#ifdef WITH_BOOK_SCANNER
		BookScanner * bs = 0;
		if(opt.contains(OPTARDUINOSERIAL))
		{
			int asbr = opt.contains(OPTARDUINOSERIALBAUDRATE) ? opt.toInt(OPTARDUINOSERIALBAUDRATE) : 0;
			bs = new BookScanner(opt.value(OPTARDUINOSERIAL), asbr);
		}
#endif

		for(int ic(0); ic < iCount; ++ic)
		{
			Composer::NewPage();
#ifdef WITH_BOOK_SCANNER
			if(bs)
				bs->TurnPage();
sleep(5);
			continue;
#endif
#ifdef WITH_CAPTURE
			QImage image;
			if(hasORM)
			{
				qDebug()<<"CAPTURE FROM" << (camsel == ORM::Left ? "LEFT" : "RIGHT");
				image = orm->TakePicture(camsel);
				if(camsel == ORM::Left)
					camsel = ORM::Right;
				else
					camsel = ORM::Left;
			}
			else
				image = QImage(opt.toString(QString(OPTIMAGE), ic));

			qDebug()<<image.size();
			image.save(QString("capture_%1.png").arg(ic));
#else
			QImage image(opt.toString(QString(OPTIMAGE), ic));
#endif
			if(doCrop)
			{
				QRect cropRect;
				if(isRightPage)
					cropRect = cropRight;
				else
					cropRect = cropLeft;
				isRightPage = !isRightPage;
				image = image.copy(cropRect);
			}

			OCR ocr(opt.value(OPTTESSDATA));
			bool hasXHeight(false);
			double optXHeight;
			if(opt.contains(OPTXHEIGHT))
			{
				optXHeight = opt.toDouble(OPTXHEIGHT);
				hasXHeight = true;
			}
			ocr.loadImage(image);
			qDebug()<<"Image loaded";
			ocr.saveImages();
			foreach(const QChar& c, ocr.iDict.keys())
			{
				if(processed.contains(c)
					||!c.isPrint()
					|| c.category() == QChar::Separator_Line
					|| c.category() == QChar::Separator_Paragraph
					|| ocr.iDict.value(c).isNull())
					continue;
				processed << c;
				unsigned int charcode(c.unicode());
				bool isSpace(QChar::category(charcode) == QChar::Separator_Space);
				QString hexcode(QString::number(charcode ,16).toUpper());
				QString glifname(QString("uni%1").arg(hexcode,4,'0'));

				//ocr.iDict.value(c).save(QString("%1.png").arg(glifname));

				GlyphTrace* gt = new GlyphTrace(ocr.iDict.value(c), ptOpt);
				if(hasXHeight)
				{
					scale = optXHeight / ocr.xheightDict.value(c);
				}
				gt->SetScale(scale);
				gt->SetTy(ocr.offsetDict.value(c) * scale);
				gt->SetName(glifname);
				gt->SetCharcode(charcode);
				gt->SetHexcode(hexcode);
				qDebug()<<"Tracing"<<c<<glifname<<scale;

				bool hasPath(!gt->GetPath().isEmpty());
				if((hasPath) || (isSpace))
				{
					allGlyphs.append(gt);
				}
				else
				{
					ocr.iDict.value(c).save(QString("oops_%1.png").arg(glifname));
				}
			}
		}

		QString ref;
		if(opt.contains(OPTFONTREF))
			ref = opt.value(OPTFONTREF);
		MagicMetrics * mm;
		if(opt.contains(OPTFONTREFSTRICT))
			mm = new MagicMetrics(allGlyphs, ref, opt.toInt(OPTFONTREFSTRICT) > 0 ? true : false);
		else
			mm = new MagicMetrics(allGlyphs, ref);

		FontUpdate * fu;
		if(opt.contains("wc"))
		{
			fu = new FontUpdate(opt.value("wc"));
			fu->ClearWC();

		}
		else
		{
			QString fontDir(".");
			QString fontName("NN_");
			if(opt.contains(OPTDIRECTORY))
				fontDir = opt.value(OPTDIRECTORY);
			if(opt.contains(OPTFONTNAME))
				fontName = opt.value(OPTFONTNAME);
			UFOTemplate ut(fontName, fontDir);
			fu = new FontUpdate(ut.path());
		}
		foreach( GlyphTrace * gt, allGlyphs)
		{
			gt->Glyph();
			fu->Do(gt);

		}
		if(opt.contains(OPTGENERATEOTF) && opt.toBool(OPTGENERATEOTF))
			fu->Commit();
		else if(opt.contains(OPTPDF) )
		{
			QImage image(opt.toString(QString(OPTIMAGE)));
			QString theFont = fu->Commit();
			Document doc(theFont);
			doc.write(opt.value(OPTPDF), image.width(),image.height());

		}
		if(!opt.contains(OPTGENERATEUFO) || !opt.toBool(OPTGENERATEUFO))
			fu->ClearWC();
		delete fu;
		delete mm;


        if(opt.contains(OPTTXT))
        {
            QFile file(opt.toString(OPTTXT));
            if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
            {
                QString txt(Composer::GetText());
                file.write(txt.toUtf8());
                file.close();
            }
        }

#ifdef WITH_CAPTURE
		if(hasORM)
			delete orm;
#endif
#ifdef WITH_BOOK_SCANNER
		if(bs)
			delete bs;
#endif
	}
#else
	if(app.argc() > 1)
	{
		Options opt(app.arguments());
		QString suffix;
		QString cspace(" ");
		QString cescape("\\");
		QList<QStringList> scans;
		QStringList basescans(opt.toString(QString(OPTIMAGE), 0).split(","));
		scans.append(basescans);
		QString supstr(QString(OPTIMAGE) + QString("%1"));
		for(int s(1); s < 10000; ++s)
		{
			if(opt.contains(supstr.arg(s)))
			{
				scans.append(opt.value(supstr.arg(s)).split(","));
			}
		}

		GlyphTrace::Options ptOpt;
		if(opt.contains(OPTPT_ALPHAMAX))
			ptOpt.alphamax = opt.toDouble(OPTPT_ALPHAMAX);
		if(opt.contains(OPTPT_TURDSIZE))
			ptOpt.turdsize = opt.toDouble(OPTPT_TURDSIZE);
		if(opt.contains(OPTPT_OPTICURVE))
			ptOpt.opticurve = opt.toDouble(OPTPT_OPTICURVE);
		if(opt.contains(OPTPT_OPTTOLERANCE))
			ptOpt.opttolerance = opt.toDouble(OPTPT_OPTTOLERANCE);

		QMap<int ,GlyphTrace*> baseglyphs;
		QList<GlyphTrace*> allGlyphs;
		bool base(true);

		int PUA = 0xe000;

		QString saltfeature("feature calt{\n");
		int virtualW(0);
		int virtualH(0);
		for(int scancount(0); scancount < scans[0].count(); ++scancount)
		{
			if(scancount > 0)
				base = false;
			QString featureset(QString("@%1_set = [").arg(base ? "base" : QString("var%1").arg(scancount)));
			for(int range(0); range < scans.count(); ++range)
			{
				if(scans[range].count() > scancount)
				{
					double scale(opt.toDouble(OPTSCALE, range));
					double offset(opt.toDouble(OPTOFFSET, range));
					double compressFactor(opt.toDouble(OPTCOMPRESS, range));
					double crop(opt.toDouble(OPTCROP, range));

					qDebug()<<"Processing"<<scans[range][scancount]<<"at scale"<<scale<< range << scancount;

					if(scale == 0.0)
						scale = 1.0;
					if(compressFactor == 0.0)
						compressFactor = 3.33;

					GridSpec spec = opt.toSpec(OPTSPEC, range);
					int d(spec.discard);
					int cw(spec.cellWidth);
					int ch(spec.cellHeight - d);


					if(!base)
						suffix = QString(".var%1").arg(scancount);
					else
						suffix = QString();

					QImage di(scans[range][scancount]);
					if(base)
					{
						virtualW = di.width();
						virtualH = di.height();
					}
					unsigned int charcode(opt.toInt(OPTCHARCODE , range));
					int BaseCharcode = charcode;
					if(!base)
						charcode = PUA;

					QString debugStr;
					int maxY(di.height() - (spec.marginBottom + ch) );
					int maxX(di.width() - (spec.marginRight + cw) );
					for( int x(spec.marginLeft);
					x < maxX;
					x += cw)
					{
						for(int y(spec.marginTop);
						y < maxY ;
						y += ch + d )
						{
							bool isSpace(QChar::category(charcode) == QChar::Separator_Space);
							debugStr += QString(QChar(charcode)) + QString(" ");
							QString hexcode(QString::number(charcode ,16).toUpper());
							QString glifname(QString("uni%1").arg(hexcode,4,'0') + suffix);
							QImage tmpImg(di.copy(x + crop, y + crop, cw - (2*crop), ch - (2*crop)));
							//qDebug()<<"Cropping"<<x + crop<<y + crop<<cw - (2*crop)<<ch - (2*crop);

							GlyphTrace* gt = new GlyphTrace(tmpImg, ptOpt);
							gt->SetScale(scale);
							gt->SetTy(offset);
							gt->SetName(glifname);
							gt->SetCharcode(charcode);
							gt->SetHexcode(hexcode);
							bool hasPath(!gt->GetPath().isEmpty());
							if(base)
							{
//								qDebug()<<hexcode<<glifname<<hasPath<<x <<y;
								if((hasPath) || (isSpace))
								{
									if(isSpace) qDebug()<<"Inserting space"<<hexcode<<glifname<<hasPath<<QChar::category(charcode);
									baseglyphs.insert(charcode,gt);
									featureset.append(cescape + glifname + cspace);
									allGlyphs.append(gt);
								}
								else
								{
									tmpImg.save(QString("oops_%1.png").arg(glifname));
//									qDebug()<<"OOOPS (A)";
								}
							}
							else
							{
								if((hasPath) || (isSpace))
								{
									featureset.append(cescape + glifname + cspace);
									allGlyphs.append(gt);
								}
								else if(baseglyphs.contains(BaseCharcode))
								{
									featureset.append(cescape + glifname + cspace);
									GlyphTrace* bc = baseglyphs[BaseCharcode]->Clone();
									bc->SetScale(scale);
									bc->SetTy(offset);
									bc->SetName(glifname);
									bc->SetHexcode(hexcode);
									bc->SetCharcode(BaseCharcode);
									allGlyphs.append(bc);
								}
								else
								{
									qDebug()<<"OOOPS (B)";
								}
							}
							++charcode;
							++BaseCharcode;
							if(!base)
								++PUA;
						}

					}
					qDebug()<<range << debugStr;
				}
				else if(range > 0)
				{
					qDebug()<<"???";
					int BaseCharcode(opt.toInt(OPTCHARCODE , range));
					int charcode(PUA);
					GridSpec spec = opt.toSpec(OPTSPEC, range);
					int d(spec.discard);
					int cw(spec.cellWidth);
					int ch(spec.cellHeight - d);
					int ph = qRound(cw / 20.0);
					int pv = qRound(ch / 20.0);
					for( int x(spec.marginLeft);
					x < (virtualW - (spec.marginRight) );
					x += cw)
					{

						for(int y(spec.marginTop);
						y < (virtualH - (spec.marginBottom) ) ;
						y += ch + d )
						{
							QString hexcode(QString::number(charcode, 16).toUpper());
							QString glifname(QString("uni%1").arg(hexcode,4,'0') + suffix);
							if(baseglyphs.contains(BaseCharcode))
							{
								featureset.append(cescape + glifname + cspace);
								GlyphTrace* bc = baseglyphs[BaseCharcode]->Clone();
								bc->SetName(glifname);
								bc->SetHexcode(hexcode);
								bc->SetCharcode(BaseCharcode);
								allGlyphs.append(bc);
							}
							++charcode;
							++BaseCharcode;
							++PUA;
						}

					}

				}
			}
			featureset += QString("];\n\n");
			saltfeature += featureset;
			//			qDebug()<< featureset;
		}

//		QFile featurefile(opt.value("wc")+QString(QDir::separator())+QString("feature.fea"));
//		bool ffIsOpen(featurefile.open(QIODevice::WriteOnly|QIODevice::Truncate));
//		if(scans[0].count() > 1)
//		{
//			for(int scancount(0); scancount < (scans[0].count()-1); ++scancount)
//			{
//				if(scancount == 0)
//					saltfeature += QString("sub @base_set @base_set' by @var1_set;\n");
//				else
//					saltfeature += QString("sub @var%1_set @base_set' by @var%2_set;\n")
//						       .arg(scancount)
//						       .arg(scancount + 1);
//			}
//			saltfeature += QString("} calt;\n");

//			if(ffIsOpen)
//			{
//				featurefile.write(saltfeature.toUtf8());
//			}
//			else
//			{
//				qDebug()<<"ERROR: Could not write salt feature in "<< (opt.value("wc")+QString(QDir::separator())+QString("feature.fea"));
//			}
//		}

		// Here we go metrics
		QString ref;
		if(opt.contains(OPTFONTREF))
			ref = opt.value(OPTFONTREF);
		MagicMetrics * mm;
		if(opt.contains(OPTFONTREFSTRICT))
			mm = new MagicMetrics(allGlyphs, ref, opt.toInt(OPTFONTREFSTRICT) > 0 ? true : false);
		else
			mm = new MagicMetrics(allGlyphs, ref);
//		if(ffIsOpen)
//		{
//			featurefile.write(mm->gposfeature.toUtf8());
//		}
//		else
//		{
//			qDebug()<<"ERROR: Could not write gpos feature in "<< (opt.value("wc")+QString(QDir::separator())+QString("feature.fea"));
//		}

		FontUpdate * fu;
		if(opt.contains("wc"))
		{
			fu = new FontUpdate(opt.value("wc"));

		}
		else
		{
			QString fontDir(".");
			QString fontName("NN_");
			if(opt.contains(OPTDIRECTORY))
				fontDir = opt.value(OPTDIRECTORY);
			if(opt.contains(OPTFONTNAME))
				fontName = opt.value(OPTFONTNAME);
			UFOTemplate ut(fontName, fontDir);
			fu = new FontUpdate(ut.path());
		}
		foreach( GlyphTrace * gt, allGlyphs)
		{
			gt->Glyph();
			fu->Do(gt);

		}
		if(opt.contains(OPTGENERATEOTF) && opt.toBool(OPTGENERATEOTF))
			fu->Commit();
		if(!opt.contains(OPTGENERATEUFO) || !opt.toBool(OPTGENERATEUFO))
			fu->ClearWC();
		delete fu;
		delete mm;
//		qDebug()<<saltfeature;

	}
#endif

//		app.exec();
}