This commit is contained in:
Chenwenxuan
2024-03-06 14:54:30 +08:00
commit edac2715f0
1525 changed files with 809982 additions and 0 deletions

View File

@@ -0,0 +1,257 @@
/******************************************************************************
**
** This file was created for the LibreCAD project, a 2D CAD program.
**
** Copyright (C) 2018 Alexander Pravdin <aledin@mail.ru>
** Copyright (C) 2022 A. Stebich (librecad@mail.lordofbikes.de)
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file gpl-2.0.txt included in the
** packaging of this file.
**
** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
******************************************************************************/
#include <QtCore>
#include <QCoreApplication>
#include <QApplication>
#include "rs_debug.h"
#include "rs_fontlist.h"
#include "rs_patternlist.h"
#include "rs_settings.h"
#include "rs_system.h"
#include "main.h"
#include "console_dxf2pdf.h"
#include "pdf_print_loop.h"
static RS_Vector parsePageSizeArg(QString);
static void parsePagesNumArg(QString, PdfPrintParams&);
static void parseMarginsArg(QString, PdfPrintParams&);
int console_dxf2pdf(int argc, char* argv[])
{
RS_DEBUG->setLevel(RS_Debug::D_NOTHING);
QApplication app(argc, argv);
QCoreApplication::setOrganizationName("LibreCAD");
QCoreApplication::setApplicationName("LibreCAD");
QCoreApplication::setApplicationVersion(XSTR(LC_VERSION));
QFileInfo prgInfo(QFile::decodeName(argv[0]));
RS_SETTINGS->init(app.organizationName(), app.applicationName());
RS_SYSTEM->init( app.applicationName(), app.applicationVersion(), XSTR(QC_APPDIR), argv[0]);
QCommandLineParser parser;
QStringList appDesc;
QString librecad( prgInfo.filePath());
if (prgInfo.baseName() != "dxf2pdf") {
librecad += " dxf2pdf"; // executable is not dxf2pdf, thus argv[1] must be 'dxf2pdf'
appDesc << "";
appDesc << "dxf2pdf " + QObject::tr( "usage: ") + librecad + QObject::tr( " [options] <dxf_files>");
}
appDesc << "";
appDesc << "Print a bunch of DXF files to PDF file(s).";
appDesc << "";
appDesc << "Examples:";
appDesc << "";
appDesc << " " + librecad + QObject::tr( " *.dxf");
appDesc << " " + QObject::tr( "-- print all dxf files to pdf files with the same names.");
appDesc << "";
appDesc << " " + librecad + QObject::tr( " -o some.pdf *.dxf");
appDesc << " " + QObject::tr( "-- print all dxf files to 'some.pdf' file.");
parser.setApplicationDescription( appDesc.join( "\n"));
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption fitOpt(QStringList() << "a" << "fit",
QObject::tr( "Auto fit and center drawing to page."));
parser.addOption(fitOpt);
QCommandLineOption centerOpt(QStringList() << "c" << "center",
QObject::tr( "Auto center drawing on page."));
parser.addOption(centerOpt);
QCommandLineOption grayOpt(QStringList() << "k" << "grayscale",
QObject::tr( "Print grayscale."));
parser.addOption(grayOpt);
QCommandLineOption monoOpt(QStringList() << "m" << "monochrome",
QObject::tr( "Print monochrome (black/white)."));
parser.addOption(monoOpt);
QCommandLineOption pageSizeOpt(QStringList() << "p" << "paper",
QObject::tr( "Paper size (Width x Height) in mm.", "WxH"));
parser.addOption(pageSizeOpt);
QCommandLineOption resOpt(QStringList() << "r" << "resolution",
QObject::tr( "Output resolution (DPI).", "integer"));
parser.addOption(resOpt);
QCommandLineOption scaleOpt(QStringList() << "s" << "scale",
QObject::tr( "Output scale. E.g.: 0.01 (for 1:100 scale)."), "double");
parser.addOption(scaleOpt);
QCommandLineOption marginsOpt(QStringList() << "f" << "margins",
QObject::tr( "Paper margins in mm (integer or float)."), "L,T,R,B");
parser.addOption(marginsOpt);
QCommandLineOption pagesNumOpt(QStringList() << "z" << "pages",
QObject::tr( "Print on multiple pages (Horiz. x Vert.)."), "HxV");
parser.addOption(pagesNumOpt);
QCommandLineOption outFileOpt(QStringList() << "o" << "outfile",
QObject::tr( "Output PDF file.", "file"));
parser.addOption(outFileOpt);
QCommandLineOption outDirOpt(QStringList() << "t" << "directory",
QObject::tr( "Target output directory."), "path");
parser.addOption(outDirOpt);
parser.addPositionalArgument(QObject::tr( "<dxf_files>"), QObject::tr( "Input DXF file(s)"));
parser.process(app);
const QStringList args = parser.positionalArguments();
if (args.isEmpty() || (args.size() == 1 && args[0] == "dxf2pdf"))
parser.showHelp(EXIT_FAILURE);
PdfPrintParams params;
params.fitToPage = parser.isSet(fitOpt);
params.centerOnPage = parser.isSet(centerOpt);
params.grayscale = parser.isSet(grayOpt);
params.monochrome = parser.isSet(monoOpt);
params.pageSize = parsePageSizeArg(parser.value(pageSizeOpt));
bool resOk;
int res = parser.value(resOpt).toInt(&resOk);
if (resOk)
params.resolution = res;
bool scaleOk;
double scale = parser.value(scaleOpt).toDouble(&scaleOk);
if (scaleOk)
params.scale = scale;
parseMarginsArg(parser.value(marginsOpt), params);
parsePagesNumArg(parser.value(pagesNumOpt), params);
params.outFile = parser.value(outFileOpt);
params.outDir = parser.value(outDirOpt);
for (auto arg : args) {
QFileInfo dxfFileInfo(arg);
if (dxfFileInfo.suffix().toLower() != "dxf")
continue; // Skip files without .dxf extension
params.dxfFiles.append(arg);
}
if (params.dxfFiles.isEmpty())
parser.showHelp(EXIT_FAILURE);
if (!params.outDir.isEmpty()) {
// Create output directory
if (!QDir().mkpath(params.outDir)) {
qDebug() << "ERROR: Cannot create directory" << params.outDir;
return EXIT_FAILURE;
}
}
RS_FONTLIST->init();
RS_PATTERNLIST->init();
PdfPrintLoop *loop = new PdfPrintLoop(params, &app);
QObject::connect(loop, SIGNAL(finished()), &app, SLOT(quit()));
QTimer::singleShot(0, loop, SLOT(run()));
return app.exec();
}
static RS_Vector parsePageSizeArg(QString arg)
{
RS_Vector v(0.0, 0.0);
if (arg.isEmpty())
return v;
QRegularExpression re("^(?<width>\\d+)[x|X]{1}(?<height>\\d+)$");
QRegularExpressionMatch match = re.match(arg);
if (match.hasMatch()) {
QString width = match.captured("width");
QString height = match.captured("height");
v.x = width.toDouble();
v.y = height.toDouble();
} else {
qDebug() << "WARNING: Ignoring bad page size:" << arg;
}
return v;
}
static void parsePagesNumArg(QString arg, PdfPrintParams& params)
{
if (arg.isEmpty())
return;
QRegularExpression re("^(?<horiz>\\d+)[x|X](?<vert>\\d+)$");
QRegularExpressionMatch match = re.match(arg);
if (match.hasMatch()) {
QString h = match.captured("horiz");
QString v = match.captured("vert");
params.pagesH = h.toInt();
params.pagesV = v.toInt();
} else {
qDebug() << "WARNING: Ignoring bad number of pages:" << arg;
}
}
static void parseMarginsArg(QString arg, PdfPrintParams& params)
{
if (arg.isEmpty())
return;
QRegularExpression re("^(?<left>\\d+(?:\\.\\d+)?),"
"(?<top>\\d+(?:\\.\\d+)?),"
"(?<right>\\d+(?:\\.\\d+)?),"
"(?<bottom>\\d+(?:\\.\\d+)?)$");
QRegularExpressionMatch match = re.match(arg);
if (match.hasMatch()) {
QString left = match.captured("left");
QString top = match.captured("top");
QString right = match.captured("right");
QString bottom = match.captured("bottom");
params.margins.left = left.toDouble();
params.margins.top = top.toDouble();
params.margins.right = right.toDouble();
params.margins.bottom = bottom.toDouble();
} else {
qDebug() << "WARNING: Ignoring bad paper margins:" << arg;
}
}

View File

@@ -0,0 +1,29 @@
/******************************************************************************
**
** This file was created for the LibreCAD project, a 2D CAD program.
**
** Copyright (C) 2018 Alexander Pravdin <aledin@mail.ru>
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file gpl-2.0.txt included in the
** packaging of this file.
**
** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
******************************************************************************/
#ifndef CONSOLE_DXF2PDF_H
#define CONSOLE_DXF2PDF_H
int console_dxf2pdf(int argc, char** argv);
#endif

View File

@@ -0,0 +1,300 @@
/******************************************************************************
**
** This file was created for the LibreCAD project, a 2D CAD program.
**
** Copyright (C) 2018 Alexander Pravdin <aledin@mail.ru>
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file gpl-2.0.txt included in the
** packaging of this file.
**
** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
******************************************************************************/
#include <QtCore>
#include "rs.h"
#include "rs_graphic.h"
#include "rs_painterqt.h"
#include "lc_printing.h"
#include "rs_staticgraphicview.h"
#include "pdf_print_loop.h"
static bool openDocAndSetGraphic(RS_Document**, RS_Graphic**, QString&);
static void touchGraphic(RS_Graphic*, PdfPrintParams&);
static void setupPrinterAndPaper(RS_Graphic*, QPrinter&, PdfPrintParams&);
static void drawPage(RS_Graphic*, QPrinter&, RS_PainterQt&);
void PdfPrintLoop::run()
{
if (params.outFile.isEmpty()) {
for (auto f : params.dxfFiles) {
printOneDxfToOnePdf(f);
}
} else {
printManyDxfToOnePdf();
}
emit finished();
}
void PdfPrintLoop::printOneDxfToOnePdf(QString& dxfFile) {
// Main code logic and flow for this method is originally stolen from
// QC_ApplicationWindow::slotFilePrint(bool printPDF) method.
// But finally it was split in to smaller parts.
QFileInfo dxfFileInfo(dxfFile);
params.outFile =
(params.outDir.isEmpty() ? dxfFileInfo.path() : params.outDir)
+ "/" + dxfFileInfo.completeBaseName() + ".pdf";
RS_Document *doc;
RS_Graphic *graphic;
if (!openDocAndSetGraphic(&doc, &graphic, dxfFile))
return;
qDebug() << "Printing" << dxfFile << "to" << params.outFile << ">>>>";
touchGraphic(graphic, params);
QPrinter printer(QPrinter::HighResolution);
setupPrinterAndPaper(graphic, printer, params);
RS_PainterQt painter(&printer);
if (params.monochrome)
painter.setDrawingMode(RS2::ModeBW);
drawPage(graphic, printer, painter);
painter.end();
qDebug() << "Printing" << dxfFile << "to" << params.outFile << "DONE";
delete doc;
}
void PdfPrintLoop::printManyDxfToOnePdf() {
struct DxfPage {
RS_Document* doc;
RS_Graphic* graphic;
QString dxfFile;
QPrinter::PageSize paperSize;
};
if (!params.outDir.isEmpty()) {
QFileInfo outFileInfo(params.outFile);
params.outFile = params.outDir + "/" + outFileInfo.fileName();
}
QVector<DxfPage> pages;
int nrPages = 0;
// FIXME: Should probably open and print all dxf files in one 'for' loop.
// Tried but failed to do this. It looks like some 'chicken and egg'
// situation for the QPrinter and RS_PainterQt. Therefore, first open
// all dxf files and apply required actions. Then run another 'for'
// loop for actual printing.
for (auto dxfFile : params.dxfFiles) {
DxfPage page;
page.dxfFile = dxfFile;
if (!openDocAndSetGraphic(&page.doc, &page.graphic, dxfFile))
continue;
qDebug() << "Opened" << dxfFile;
touchGraphic(page.graphic, params);
pages.append(page);
nrPages++;
}
QPrinter printer(QPrinter::HighResolution);
if (nrPages > 0) {
// FIXME: Is it possible to set up printer and paper for every
// opened dxf file and tie them with painter? For now just using
// data extracted from the first opened dxf file for all pages.
setupPrinterAndPaper(pages.at(0).graphic, printer, params);
}
RS_PainterQt painter(&printer);
if (params.monochrome)
painter.setDrawingMode(RS2::ModeBW);
// And now it's time to actually print all previously opened dxf files.
for (auto page : pages) {
nrPages--;
qDebug() << "Printing" << page.dxfFile
<< "to" << params.outFile << ">>>>";
drawPage(page.graphic, printer, painter);
qDebug() << "Printing" << page.dxfFile
<< "to" << params.outFile << "DONE";
delete page.doc;
if (nrPages > 0)
printer.newPage();
}
painter.end();
}
static bool openDocAndSetGraphic(RS_Document** doc, RS_Graphic** graphic,
QString& dxfFile)
{
*doc = new RS_Graphic();
if (!(*doc)->open(dxfFile, RS2::FormatUnknown)) {
qDebug() << "ERROR: Failed to open document" << dxfFile;
delete *doc;
return false;
}
*graphic = (*doc)->getGraphic();
if (*graphic == nullptr) {
qDebug() << "ERROR: No graphic in" << dxfFile;
delete *doc;
return false;
}
return true;
}
static void touchGraphic(RS_Graphic* graphic, PdfPrintParams& params)
{
graphic->calculateBorders();
graphic->setMargins(params.margins.left, params.margins.top,
params.margins.right, params.margins.bottom);
graphic->setPagesNum(params.pagesH, params.pagesV);
if (params.scale > 0.0)
graphic->setPaperScale(params.scale);
if (params.pageSize != RS_Vector(0.0, 0.0))
graphic->setPaperSize(params.pageSize);
if (params.fitToPage)
graphic->fitToPage(); // fit and center
else if (params.centerOnPage)
graphic->centerToPage();
}
static void setupPrinterAndPaper(RS_Graphic* graphic, QPrinter& printer,
PdfPrintParams& params)
{
bool landscape = false;
RS2::PaperFormat pf = graphic->getPaperFormat(&landscape);
QPrinter::PageSize paperSize = LC_Printing::rsToQtPaperFormat(pf);
if (paperSize == QPrinter::Custom){
RS_Vector r = graphic->getPaperSize();
RS_Vector&& s = RS_Units::convert(r, graphic->getUnit(),
RS2::Millimeter);
if (landscape)
s = s.flipXY();
printer.setPaperSize(QSizeF(s.x,s.y), QPrinter::Millimeter);
} else {
printer.setPaperSize(paperSize);
}
if (landscape) {
printer.setOrientation(QPrinter::Landscape);
} else {
printer.setOrientation(QPrinter::Portrait);
}
printer.setOutputFileName(params.outFile);
printer.setOutputFormat(QPrinter::PdfFormat);
printer.setResolution(params.resolution);
printer.setFullPage(true);
if (params.grayscale)
printer.setColorMode(QPrinter::GrayScale);
else
printer.setColorMode(QPrinter::Color);
}
static void drawPage(RS_Graphic* graphic, QPrinter& printer,
RS_PainterQt& painter)
{
double printerFx = (double)printer.width() / printer.widthMM();
double printerFy = (double)printer.height() / printer.heightMM();
double marginLeft = graphic->getMarginLeft();
double marginTop = graphic-> getMarginTop();
double marginRight = graphic->getMarginRight();
double marginBottom = graphic->getMarginBottom();
painter.setClipRect(marginLeft * printerFx, marginTop * printerFy,
printer.width() - (marginLeft + marginRight) * printerFx,
printer.height() - (marginTop + marginBottom) * printerFy);
RS_StaticGraphicView gv(printer.width(), printer.height(), &painter);
gv.setPrinting(true);
gv.setBorders(0,0,0,0);
double fx = printerFx * RS_Units::getFactorToMM(graphic->getUnit());
double fy = printerFy * RS_Units::getFactorToMM(graphic->getUnit());
double f = (fx + fy) / 2.0;
double scale = graphic->getPaperScale();
gv.setOffset((int)(graphic->getPaperInsertionBase().x * f),
(int)(graphic->getPaperInsertionBase().y * f));
gv.setFactor(f*scale);
gv.setContainer(graphic);
double baseX = graphic->getPaperInsertionBase().x;
double baseY = graphic->getPaperInsertionBase().y;
int numX = graphic->getPagesNumHoriz();
int numY = graphic->getPagesNumVert();
RS_Vector printArea = graphic->getPrintAreaSize(false);
for (int pY = 0; pY < numY; pY++) {
double offsetY = printArea.y * pY;
for (int pX = 0; pX < numX; pX++) {
double offsetX = printArea.x * pX;
// First page is created automatically.
// Extra pages must be created manually.
if (pX > 0 || pY > 0) printer.newPage();
gv.setOffset((int)((baseX - offsetX) * f),
(int)((baseY - offsetY) * f));
gv.drawEntity(&painter, graphic );
}
}
}

View File

@@ -0,0 +1,82 @@
/******************************************************************************
**
** This file was created for the LibreCAD project, a 2D CAD program.
**
** Copyright (C) 2018 Alexander Pravdin <aledin@mail.ru>
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file gpl-2.0.txt included in the
** packaging of this file.
**
** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
******************************************************************************/
#ifndef PDF_PRINT_LOOP_H
#define PDF_PRINT_LOOP_H
#include <QtCore>
#include <QPrinter>
#include "rs_vector.h"
struct PdfPrintParams {
QStringList dxfFiles;
QString outDir;
QString outFile;
int resolution = 1200;
bool centerOnPage;
bool fitToPage;
bool monochrome;
bool grayscale;
double scale = 0.0; // If scale <= 0.0, use value from dxf file.
RS_Vector pageSize; // If zeros, use value from dxf file.
struct {
double left = -1.0;
double top = -1.0;
double right = -1.0;
double bottom = -1.0;
} margins; // If margin < 0.0, use value from dxf file.
int pagesH = 0; // If number of pages < 1,
int pagesV = 0; // use value from dxf file.
};
class PdfPrintLoop : public QObject {
Q_OBJECT
public:
PdfPrintLoop(PdfPrintParams& params, QObject* parent=0) :
QObject(parent) {
this->params = params;
};
public slots:
void run();
signals:
void finished();
private:
PdfPrintParams params;
void printOneDxfToOnePdf(QString&);
void printManyDxfToOnePdf();
};
#endif