Subversion Repositories Scribus

Rev

Rev 20681 | Rev 20761 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
3133 fschmid 7
/***************************************************************************
14043 jghali 8
                                                  pdflib_core.cpp  -  description
9
                                                         -------------------
10
        begin                : Sat Jan 19 2002
11
        copyright            : (C) 2002 by Franz Schmid
12
        email                : Franz.Schmid@altmuehlnet.de
3133 fschmid 13
 ***************************************************************************/
14
 
15
/***************************************************************************
16
 *                                                                         *
17
 *   This program is free software; you can redistribute it and/or modify  *
18
 *   it under the terms of the GNU General Public License as published by  *
19
 *   the Free Software Foundation; either version 2 of the License, or     *
20
 *   (at your option) any later version.                                   *
21
 *                                                                         *
22
 ***************************************************************************/
23
 
10054 craig 24
#include "pdflib_core.h"
3133 fschmid 25
 
26
#include "scconfig.h"
27
 
17539 jghali 28
#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
14170 jghali 29
#define _USE_MATH_DEFINES
30
#endif
12080 avox 31
#include <cmath>
32
#include <cstdlib>
4229 craig 33
#include <string>
12080 avox 34
#ifdef HAVE_UNISTD_H
35
#include <unistd.h>
36
#endif
37
 
38
#include "rc4.h"
39
 
40
#include <QByteArray>
19914 craig 41
#include <QCryptographicHash>
10223 cbradney 42
#include <QDateTime>
10004 fschmid 43
#include <QDataStream>
12080 avox 44
#include <QDebug>
10223 cbradney 45
#include <QDir>
12080 avox 46
#include <QFileInfo>
47
#include <QImage>
9803 fschmid 48
#include <QList>
11453 fschmid 49
#include <QPainterPath>
8501 cbradney 50
#include <QPixmap>
12080 avox 51
#include <QRect>
52
#include <QRegExp>
19671 jghali 53
#include <QScopedPointer>
12080 avox 54
#include <QStack>
55
#include <QString>
13839 fschmid 56
#include <QTemporaryFile>
10614 cbradney 57
#include <QTextCodec>
14043 jghali 58
#include <QtXml>
59
#include <QUuid>
3133 fschmid 60
 
10601 mrdocs 61
#include "cmsettings.h"
4028 cbradney 62
#include "commonstrings.h"
3133 fschmid 63
#include "pageitem.h"
10601 mrdocs 64
#include "pageitem_textframe.h"
16258 fschmid 65
#include "pageitem_group.h"
17023 fschmid 66
#include "pageitem_pathtext.h"
17312 fschmid 67
#include "pageitem_table.h"
10212 cbradney 68
#include "pdfoptions.h"
69
#include "prefscontext.h"
70
#include "prefsmanager.h"
71
#include "sccolor.h"
72
#include "sccolorengine.h"
73
#include "scfonts.h"
20103 avox 74
#include "fonts/cff.h"
75
#include "fonts/sfnt.h"
16736 jghali 76
#include "scpage.h"
5917 jghali 77
#include "scpaths.h"
10212 cbradney 78
#include "scpattern.h"
19115 avox 79
 
5243 cbradney 80
#include "scribuscore.h"
3699 cbradney 81
#include "scribusdoc.h"
11599 jghali 82
#include "scstreamfilter_flate.h"
83
#include "scstreamfilter_rc4.h"
17312 fschmid 84
#include "tableutils.h"
3133 fschmid 85
#include "util.h"
11605 jghali 86
#include "util_file.h"
10212 cbradney 87
#include "util_formats.h"
10203 cbradney 88
#include "util_math.h"
12517 fschmid 89
#include "util_ghostscript.h"
16736 jghali 90
 
13839 fschmid 91
#ifdef HAVE_OSG
14930 fschmid 92
        #include "third_party/prc/exportPRC.h"
13839 fschmid 93
#endif
3133 fschmid 94
 
16736 jghali 95
#include "ui/bookmwin.h"
96
#include "ui/bookmarkpalette.h"
97
#include "ui/multiprogressdialog.h"
98
 
3133 fschmid 99
using namespace std;
17312 fschmid 100
using namespace TableUtils;
3133 fschmid 101
 
12096 jghali 102
#if defined(_WIN32)
103
#undef GetObject
104
#endif
3133 fschmid 105
 
6562 fschmid 106
 
10054 craig 107
PDFLibCore::PDFLibCore(ScribusDoc & docu)
4264 craig 108
        : QObject(&docu),
4223 craig 109
        doc(docu),
110
        ActPageP(0),
14925 cbradney 111
        Options(doc.pdfOptions()),
4223 craig 112
        Bvie(0),
19114 avox 113
        ucs2Codec(0),
20103 avox 114
//      ObjCounter(7),
4223 craig 115
        ResNam("RE"),
116
        ResCount(0),
117
        NDnam("LI"),
118
        NDnum(0),
20103 avox 119
//      KeyGen(""),
120
//      OwnerKey(""),
121
//      UserKey(""),
122
//      FileID(""),
123
//      EncryKey(""),
124
//      Encrypt(0),
125
//      KeyLen(5),
4223 craig 126
        colorsToUse(),
127
        spotNam("Spot"),
128
        spotCount(0),
4225 craig 129
        progressDialog(0),
4223 craig 130
        abortExport(false),
20089 jghali 131
        usingGUI(ScCore->usingGUI()),
132
        bleedDisplacementX(0),
133
        bleedDisplacementY(0)
3133 fschmid 134
{
20103 avox 135
//      KeyGen.resize(32);
136
//      OwnerKey.resize(32);
137
//      UserKey.resize(32);
138
//      FileID.resize(16);
139
//      EncryKey.resize(5);
3133 fschmid 140
        Catalog.Outlines = 2;
141
        Catalog.PageTree = 3;
142
        Catalog.Dest = 4;
143
        PageTree.Count = 0;
144
        Outlines.First = 0;
145
        Outlines.Last = 0;
146
        Outlines.Count = 0;
20103 avox 147
        pageData.ObjNum = 0;
148
        pageData.Thumb = 0;
149
//      int kg_array[] = {0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa,
150
//                        0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe,
151
//                        0x64, 0x53, 0x69, 0x7a};
152
//      for (int a = 0; a < 32; ++a)
153
//              KeyGen[a] = kg_array[a];
4028 cbradney 154
        if (usingGUI)
155
        {
10508 cbradney 156
                progressDialog = new MultiProgressDialog( tr("Saving PDF"), CommonStrings::tr_Cancel, doc.scMW());
4224 craig 157
                Q_CHECK_PTR(progressDialog);
158
                QStringList barNames, barTexts;
159
                barNames << "EMP" << "EP" << "ECPI";
5370 cbradney 160
                barTexts << tr("Exporting Master Page:") << tr("Exporting Page:") << tr("Exporting Items on Current Page:");
9803 fschmid 161
                QList<bool> barsNumeric;
5370 cbradney 162
                barsNumeric << true << true << false;
163
                progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
8559 subik 164
                connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
4028 cbradney 165
        }
3133 fschmid 166
}
167
 
10054 craig 168
PDFLibCore::~PDFLibCore()
4224 craig 169
{
170
        delete progressDialog;
171
}
172
 
20103 avox 173
static inline QByteArray FToStr(double c)
4229 craig 174
{
15283 fschmid 175
        double v = c;
176
        if (fabs(c) < 0.0000001)
177
                v = 0.0;
20112 jghali 178
        return QByteArray::number(v, 'f', 5);
4229 craig 179
};
180
 
19115 avox 181
bool PDFLibCore::PDF_IsPDFX()
182
{
183
        if (Options.Version == PDFOptions::PDFVersion_X1a)
184
                return true;
185
        if (Options.Version == PDFOptions::PDFVersion_X3)
186
                return true;
187
        if (Options.Version == PDFOptions::PDFVersion_X4)
188
                return true;
189
        return false;
190
}
191
 
192
bool PDFLibCore::PDF_IsPDFX(PDFOptions::PDFVersion ver)
193
{
194
        if (ver == PDFOptions::PDFVersion_X1a)
195
                return true;
196
        if (ver == PDFOptions::PDFVersion_X3)
197
                return true;
198
        if (ver == PDFOptions::PDFVersion_X4)
199
                return true;
200
        return false;
201
}
202
 
10054 craig 203
bool PDFLibCore::doExport(const QString& fn, const QString& nam, int Components,
4264 craig 204
                                          const std::vector<int> & pageNs, const QMap<int,QPixmap> & thumbs)
3133 fschmid 205
{
206
        QPixmap pm;
11060 jghali 207
        bool ret = false, error = false;
208
        int  pc_exportpages=0;
209
        int  pc_exportmasterpages=0;
4224 craig 210
        if (usingGUI)
211
                progressDialog->show();
5387 avox 212
        QMap<QString, QMap<uint, FPointArray> > usedFonts;
213
        usedFonts.clear();
214
        doc.getUsedFonts(usedFonts);
19114 avox 215
        ucs2Codec = QTextCodec::codecForName("ISO-10646-UCS-2");
17758 jghali 216
        if (!ucs2Codec)
19114 avox 217
                ucs2Codec = QTextCodec::codecForName("UTF-16");
218
        if (!ucs2Codec)
13764 jghali 219
        {
13791 pierre 220
                PDF_Error( tr("Qt build miss both \"UTF-16\" and \"ISO-10646-UCS-2\" text codecs, pdf export is not possible") );
13764 jghali 221
                return false;
222
        }
13955 cbradney 223
        if (PDF_Begin_Doc(fn, PrefsManager::instance()->appPrefs.fontPrefs.AvailFonts, usedFonts, doc.scMW()->bookmarkPalette->BView))
3133 fschmid 224
        {
225
                QMap<int, int> pageNsMpa;
226
                for (uint a = 0; a < pageNs.size(); ++a)
227
                {
14653 jghali 228
                        pageNsMpa.insert(doc.MasterNames[doc.DocPages.at(pageNs[a]-1)->MPageNam], 0);
3133 fschmid 229
                }
4028 cbradney 230
                if (usingGUI)
3133 fschmid 231
                {
4028 cbradney 232
                        progressDialog->setOverallTotalSteps(pageNsMpa.count()+pageNs.size());
233
                        progressDialog->setTotalSteps("EMP", pageNsMpa.count());
234
                        progressDialog->setTotalSteps("EP", pageNs.size());
235
                        progressDialog->setOverallProgress(0);
236
                        progressDialog->setProgress("EMP", 0);
237
                        progressDialog->setProgress("EP", 0);
238
                }
10018 fschmid 239
                for (int ap = 0; ap < doc.MasterPages.count() && !abortExport; ++ap)
4028 cbradney 240
                {
4264 craig 241
                        if (doc.MasterItems.count() != 0)
3133 fschmid 242
                        {
243
                                if (pageNsMpa.contains(ap))
244
                                {
5243 cbradney 245
                                        qApp->processEvents();
11060 jghali 246
                                        if (!PDF_TemplatePage(doc.MasterPages.at(ap)))
247
                                                error = abortExport = true;
4028 cbradney 248
                                        ++pc_exportmasterpages;
3133 fschmid 249
                                }
250
                        }
4546 subik 251
                        if (usingGUI)
252
                        {
4028 cbradney 253
                                progressDialog->setProgress("EMP", pc_exportmasterpages);
254
                                progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
255
                        }
3133 fschmid 256
                }
4028 cbradney 257
                for (uint a = 0; a < pageNs.size() && !abortExport; ++a)
3133 fschmid 258
                {
14925 cbradney 259
                        if (doc.pdfOptions().Thumbnails)
3133 fschmid 260
                                pm = thumbs[pageNs[a]];
5243 cbradney 261
                        qApp->processEvents();
4028 cbradney 262
                        if (abortExport) break;
11060 jghali 263
 
14653 jghali 264
                        PDF_Begin_Page(doc.DocPages.at(pageNs[a]-1), pm);
5243 cbradney 265
                        qApp->processEvents();
4028 cbradney 266
                        if (abortExport) break;
11060 jghali 267
 
14925 cbradney 268
                        if (!PDF_ProcessPage(doc.DocPages.at(pageNs[a]-1), pageNs[a]-1, doc.pdfOptions().doClip))
11060 jghali 269
                                error = abortExport = true;
5243 cbradney 270
                        qApp->processEvents();
4028 cbradney 271
                        if (abortExport) break;
11060 jghali 272
 
15444 craig 273
                        PDF_End_Page(a);
4028 cbradney 274
                        pc_exportpages++;
275
                        if (usingGUI)
276
                        {
277
                                progressDialog->setProgress("EP", pc_exportpages);
278
                                progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
279
                        }
3133 fschmid 280
                }
20681 craig 281
                ret = true;//Even when aborting we return true. Don't want that "couldnt write msg"
4028 cbradney 282
                if (!abortExport)
283
                {
19115 avox 284
                        if (PDF_IsPDFX(doc.pdfOptions().Version))
14925 cbradney 285
                                ret = PDF_End_Doc(ScCore->PrinterProfiles[doc.pdfOptions().PrintProf], nam, Components);
4028 cbradney 286
                        else
12387 jghali 287
                                ret = PDF_End_Doc();
4028 cbradney 288
                }
3133 fschmid 289
                else
4028 cbradney 290
                        closeAndCleanup();
3133 fschmid 291
        }
4029 cbradney 292
        if (usingGUI)
293
                progressDialog->close();
11060 jghali 294
        return (ret && !error);
3133 fschmid 295
}
296
 
11060 jghali 297
const QString& PDFLibCore::errorMessage(void) const
298
{
299
        return ErrorMessage;
300
}
301
 
11441 jghali 302
bool PDFLibCore::exportAborted(void) const
303
{
304
        return abortExport;
305
}
306
 
20103 avox 307
//#define StartObj(n) writer.startObj((n))
308
#define PutDoc(s) writer.write(s)
309
//#define newObject() writer.newObject()
3133 fschmid 310
 
311
 
20103 avox 312
//void PDFLibCore::StartObj(PdfId nr)
313
//{
314
//      for (int i=XRef.size(); i < nr; ++i)
315
//              XRef.append(0);
316
//      XRef[nr-1] = bytesWritten();
317
//      PutDoc(Pdf::toPdf(nr)+ " 0 obj\n");
318
//}
319
 
320
//// Encode a string for inclusion in a
321
//// PDF (literal) .
322
//static QByteArray PDFEncode(const QString & in)
323
//{
324
//      QByteArray tmp("");
325
//      for (int d = 0; d < in.length(); ++d)
326
//      {
327
//              QChar cc(in.at(d));
328
//              if ((cc == '(') || (cc == ')') || (cc == '\\'))
329
//                      tmp += '\\';
330
//              else if ((cc == '\r') || (cc == '\n'))
331
//              {
332
//                      tmp += (cc == '\r') ? "\\r" : "\\n";
333
//                      continue;
334
//              }
335
//              tmp += cc;
336
//      }
337
//      return tmp;
338
//}
339
 
340
static QByteArray blendMode(int code)
12080 avox 341
{
342
        switch (code)
343
        {
344
                case 0:
345
                        return("Normal");
346
                        break;
347
                case 1:
348
                        return("Darken");
349
                        break;
350
                case 2:
351
                        return("Lighten");
352
                        break;
353
                case 3:
354
                        return("Multiply");
355
                        break;
356
                case 4:
357
                        return("Screen");
358
                        break;
359
                case 5:
360
                        return("Overlay");
361
                        break;
362
                case 6:
363
                        return("HardLight");
364
                        break;
365
                case 7:
366
                        return("SoftLight");
367
                        break;
368
                case 8:
369
                        return("Difference");
370
                        break;
371
                case 9:
372
                        return("Exclusion");
373
                        break;
374
                case 10:
375
                        return("ColorDodge");
376
                        break;
377
                case 11:
378
                        return("ColorBurn");
379
                        break;
380
                case 12:
381
                        return("Hue");
382
                        break;
383
                case 13:
384
                        return("Saturation");
385
                        break;
386
                case 14:
387
                        return("Color");
388
                        break;
389
                case 15:
390
                        return("Luminosity");
391
                        break;
392
                default:
393
                        return "";
394
        }
14043 jghali 395
}
20103 avox 396
//
397
//QByteArray PDFLibCore::EncodeUTF16(const QString &in)
398
//{
399
//      QString tmp = in;
400
//      QByteArray cres = ucs2Codec->fromUnicode( tmp );
401
//#ifndef WORDS_BIGENDIAN
402
//      // on little endian systems we need to swap bytes:
403
//      uchar sw;
404
//      for(int d = 0; d < cres.size()-1; d += 2)
405
//      {
406
//              sw = cres[d];
407
//              cres[d] = cres[d+1];
408
//              cres[d+1] = sw;
409
//      }
410
//#endif
411
//      return cres;
412
//}
12080 avox 413
 
20103 avox 414
QByteArray PDFLibCore::EncStream(const QByteArray & in, PdfId ObjNum)
19114 avox 415
{
416
        if (in.length() < 1)
20103 avox 417
                return QByteArray();
19114 avox 418
        else if (!Options.Encrypt)
419
                return in;
20112 jghali 420
        else
421
                return writer.encryptBytes(in, ObjNum);
20103 avox 422
//      rc4_context_t rc4;
423
//      QByteArray tmp(in);
424
//      QByteArray us(tmp.length(), ' ');
425
//      QByteArray ou(tmp.length(), ' ');
426
//      for (int a = 0; a < tmp.length(); ++a)
20112 jghali 427
//              us[a] = (tmp.at(a));
428
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
20103 avox 429
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
430
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), tmp.length());
431
//      QString uk = "";
432
//      for (int cl = 0; cl < tmp.length(); ++cl)
433
//              uk += QChar(ou[cl]);
434
//      return ou;
19114 avox 435
}
436
 
20103 avox 437
QByteArray PDFLibCore::EncString(const QByteArray & in, PdfId ObjNum)
19114 avox 438
{
20103 avox 439
        QByteArray tmp;
19114 avox 440
        if (in.length() < 1)
441
                return "<>";
442
        if (!Options.Encrypt)
443
        {
20103 avox 444
                //tmp = "(" + PDFEncode(in) + ")";
20112 jghali 445
                return Pdf::toLiteralString(in);
19114 avox 446
        }
20112 jghali 447
 
20103 avox 448
//      rc4_context_t rc4;
449
//      QByteArray us(in.length(), ' ');
450
//      QByteArray ou(in.length(), ' ');
451
//      for (int a = 0; a < in.length(); ++a)
452
//              us[a] = static_cast<uchar>(QChar(in.at(a)).cell());
453
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
454
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
455
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), in.length());
456
//      QString uk = "";
457
//      for (int cl = 0; cl < in.length(); ++cl)
458
//              uk += QChar(ou[cl]);
20112 jghali 459
 
460
        return Pdf::toHexString(writer.encryptBytes(in, ObjNum));
19114 avox 461
}
462
 
20103 avox 463
QByteArray PDFLibCore::EncStringUTF16(const QString & in, PdfId ObjNum)
19114 avox 464
{
465
        if (in.length() < 1)
466
                return "<>";
467
        if (!Options.Encrypt)
468
        {
20112 jghali 469
                QByteArray us = Pdf::toUTF16(in);
20103 avox 470
//              QString uk = "";
471
//              for (int cl = 0; cl < us.size(); ++cl)
472
//                      uk += QChar(us[cl]);
473
                return Pdf::toHexString(us);
19114 avox 474
        }
20103 avox 475
//      rc4_context_t rc4;
20112 jghali 476
        QByteArray us = Pdf::toUTF16(in);
20103 avox 477
//      QByteArray ou(us.size(), ' ');
478
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
479
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
480
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), ou.size());
481
//      QString uk = "";
482
//      for (int cl = 0; cl < ou.size(); ++cl)
483
//              uk += QChar(ou[cl]);
484
        QByteArray tmp = Pdf::toHexString(writer.encryptBytes(us, ObjNum));
19114 avox 485
        return tmp;
486
}
487
 
20103 avox 488
bool PDFLibCore::EncodeArrayToStream(const QByteArray& in, PdfId ObjNum)
19114 avox 489
{
490
        if (in.size() < 1)
491
                return true;
492
        bool succeed = false;
493
        if (Options.Encrypt)
494
        {
20103 avox 495
                ScStreamFilter* rc4Encode = writer.openStreamFilter(true, ObjNum);
496
                if (rc4Encode->openFilter())
19114 avox 497
                {
20103 avox 498
                        succeed  = rc4Encode->writeData(in.data(), in.size());
499
                        succeed &= rc4Encode->closeFilter();
19114 avox 500
                }
20112 jghali 501
                delete rc4Encode;
19114 avox 502
        }
503
        else
20103 avox 504
                writer.write(in);
505
        return (writer.getOutStream().status() == QDataStream::Ok);
19114 avox 506
}
507
 
20103 avox 508
int PDFLibCore::WriteImageToStream(ScImage& image, PdfId ObjNum, ColorSpaceEnum format, bool precal)
11599 jghali 509
{
17758 jghali 510
        bool fromCmyk, succeed = false;
11599 jghali 511
        int  bytesWritten = 0;
20103 avox 512
 
20112 jghali 513
        ScStreamFilter* rc4Encode = writer.openStreamFilter(Options.Encrypt, ObjNum);
514
        if (rc4Encode->openFilter())
515
        {
516
                switch (format)
517
                {
518
                        case ColorSpaceMonochrome :
519
                                fromCmyk = !Options.UseRGB && !Options.isGrayscale && !(doc.HasCMS && Options.UseProfiles2);
520
                                succeed = image.writeMonochromeDataToFilter(rc4Encode, fromCmyk); break;
521
                        case ColorSpaceGray :
522
                                succeed = image.writeGrayDataToFilter(rc4Encode, precal); break;
523
                        case ColorSpaceCMYK :
524
                                succeed = image.writeCMYKDataToFilter(rc4Encode); break;
525
                        default :
526
                                succeed = image.writeRGBDataToFilter(rc4Encode); break;
527
                }
528
                succeed &= rc4Encode->closeFilter();
529
                bytesWritten = rc4Encode->writtenToStream();
530
                delete rc4Encode;
531
        }
11599 jghali 532
        return (succeed ? bytesWritten : 0);
533
}
534
 
20103 avox 535
int PDFLibCore::WriteJPEGImageToStream(ScImage& image, const QString& fn, PdfId ObjNum, int quality, ColorSpaceEnum format,
17758 jghali 536
                                                                                 bool sameFile, bool precal)
11599 jghali 537
{
538
        bool succeed = true;
539
        int  bytesWritten = 0;
540
        QFileInfo fInfo(fn);
541
        QString   ext = fInfo.suffix().toLower();
542
        QString   jpgFileName, tmpFile;
543
        if (extensionIndicatesJPEG(ext) && sameFile)
544
                jpgFileName = fn;
11445 jghali 545
        else
11599 jghali 546
        {
16577 craig 547
                tmpFile  = QDir::toNativeSeparators(ScPaths::getTempFileDir() + "sc.jpg");
17758 jghali 548
                if (format == ColorSpaceGray && (!precal))
11599 jghali 549
                        image.convertToGray();
17758 jghali 550
                if (image.convert2JPG(tmpFile, quality, format == ColorSpaceCMYK, format == ColorSpaceGray))
11599 jghali 551
                        jpgFileName = tmpFile;
552
        }
553
        if (jpgFileName.isEmpty())
11792 fschmid 554
                return 0;
11599 jghali 555
        if (Options.Encrypt)
556
        {
557
                succeed = false;
20112 jghali 558
                ScStreamFilter* rc4Encode = writer.openStreamFilter(true, ObjNum);
559
                if (rc4Encode->openFilter())
11599 jghali 560
                {
20103 avox 561
                        succeed  = copyFileToFilter(jpgFileName, *rc4Encode);
562
                        succeed &= rc4Encode->closeFilter();
563
                        bytesWritten = rc4Encode->writtenToStream();
11599 jghali 564
                }
20112 jghali 565
                delete rc4Encode;
11599 jghali 566
        }
567
        else
568
        {
20103 avox 569
                succeed &= copyFileToStream(jpgFileName, writer.getOutStream());
11599 jghali 570
                QFileInfo jpgInfo(jpgFileName);
571
                bytesWritten = jpgInfo.size();
572
        }
573
        if (!tmpFile.isEmpty() && QFile::exists(tmpFile))
574
                QFile::remove(tmpFile);
575
        return (succeed ? bytesWritten : 0);
11445 jghali 576
}
577
 
20103 avox 578
int PDFLibCore::WriteFlateImageToStream(ScImage& image, PdfId ObjNum, ColorSpaceEnum format, bool precal)
11599 jghali 579
{
20112 jghali 580
        bool fromCmyk, succeed = false;
581
        int  bytesWritten = 0;
582
        ScStreamFilter* rc4Encode = writer.openStreamFilter(Options.Encrypt, ObjNum);
583
        ScFlateEncodeFilter flateEncode(rc4Encode);
584
        if (flateEncode.openFilter())
585
        {
586
                switch (format)
587
                {
588
                        case ColorSpaceMonochrome :
589
                                fromCmyk = !Options.UseRGB && !Options.isGrayscale && !(doc.HasCMS && Options.UseProfiles2);
590
                                succeed = image.writeMonochromeDataToFilter(&flateEncode, fromCmyk); break;
591
                        case ColorSpaceGray :
592
                                succeed = image.writeGrayDataToFilter(&flateEncode, precal); break;
593
                        case ColorSpaceCMYK :
594
                                succeed = image.writeCMYKDataToFilter(&flateEncode); break;
595
                        default :
596
                                succeed = image.writeRGBDataToFilter(&flateEncode); break;
597
                }
598
                succeed &= flateEncode.closeFilter();
599
                bytesWritten = flateEncode.writtenToStream();
600
        }
601
        delete rc4Encode;
602
        return (succeed ? bytesWritten : 0);
11599 jghali 603
}
604
 
3133 fschmid 605
 
19114 avox 606
 
20103 avox 607
bool PDFLibCore::PDF_Begin_Doc(const QString& fn, SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& DocFonts, BookMView* vi)
19114 avox 608
{
20112 jghali 609
        if (!writer.open(fn))
610
                return false;
611
 
612
        QFileInfo fiBase(fn);
613
        QString baseDir = fiBase.absolutePath();
19114 avox 614
 
20103 avox 615
//      QString tmp;
616
//      QFileInfo fd;
617
//      QString fext;
6407 fschmid 618
        inPattern = 0;
3133 fschmid 619
        Bvie = vi;
620
        BookMinUse = false;
621
        UsedFontsP.clear();
8454 fschmid 622
        UsedFontsF.clear();
20112 jghali 623
 
624
        writer.writeHeader(Options.Version);
625
 
20103 avox 626
//      if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
627
//              ObjCounter = 10;
628
//      else
629
//              ObjCounter = 9;
630
//      switch (Options.Version)
631
//      {
632
//              case PDFOptions::PDFVersion_X1a:
633
//              case PDFOptions::PDFVersion_X3:
634
//              case PDFOptions::PDFVersion_13:
635
//                      PutDoc("%PDF-1.3\n");
636
//                      break;
637
//              case PDFOptions::PDFVersion_14:
638
//                      PutDoc("%PDF-1.4\n");
639
//                      break;
640
//              case PDFOptions::PDFVersion_X4:
641
//              case PDFOptions::PDFVersion_15:
642
//                      PutDoc("%PDF-1.5\n");
643
//                      break;
644
//      }
645
//      if (PDF_IsPDFX())
646
//              ObjCounter++;
647
//      PutDoc("%\xc7\xec\x8f\xa2\n");
648
 
20112 jghali 649
        PDF_Begin_Catalog();
650
        PDF_Begin_MetadataAndEncrypt();
651
        PDF_Begin_WriteUsedFonts(AllFonts, PDF_Begin_FindUsedFonts(AllFonts, DocFonts));
652
        PDF_Begin_Colors();
653
        PDF_Begin_Layers();
654
 
655
        return true;
20103 avox 656
}
657
 
658
void PDFLibCore::PDF_Begin_Catalog()
659
{
20112 jghali 660
        writer.startObj(writer.CatalogObj);
661
        PutDoc("<<\n/Type /Catalog");
662
        PutDoc("\n/Outlines " + Pdf::toObjRef(writer.OutlinesObj) +
663
                   "\n/Pages " + Pdf::toObjRef(writer.PagesObj) +
664
                   "\n/Dests " + Pdf::toObjRef(writer.DestsObj) +
665
                   "\n/AcroForm " + Pdf::toObjRef(writer.AcroFormObj) +
666
                   "\n/Names "+ Pdf::toObjRef(writer.NamesObj) +
667
                   "\n/Threads " +  Pdf::toObjRef(writer.ThreadsObj) +
668
                   "\n");
19114 avox 669
        if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
20112 jghali 670
        {
671
                writer.OCPropertiesObj = writer.newObject();
20103 avox 672
                PutDoc("/OCProperties " + Pdf::toObjRef(writer.OCPropertiesObj) + "\n");
20112 jghali 673
        }
674
        if (PDF_IsPDFX())
19114 avox 675
        {
20112 jghali 676
                writer.OutputIntentObj = writer.newObject();
677
                PutDoc("/OutputIntents [ " +  Pdf::toObjRef(writer.OutputIntentObj) + " ]\n");
678
        }
679
        if ((Options.Version == PDFOptions::PDFVersion_X4))
680
        {
681
                writer.MetaDataObj = writer.newObject();
20103 avox 682
                PutDoc("/Metadata "+ Pdf::toObjRef(writer.MetaDataObj) + "\n");
19114 avox 683
        }
684
        PutDoc("/PageLayout ");
685
        switch (Options.PageLayout)
686
        {
687
                case PDFOptions::SinglePage:
688
                        PutDoc("/SinglePage\n");
689
                        break;
690
                case PDFOptions::OneColumn:
691
                        PutDoc("/OneColumn\n");
692
                        break;
693
                case PDFOptions::TwoColumnLeft:
694
                        PutDoc("/TwoColumnLeft\n");
695
                        break;
696
                case PDFOptions::TwoColumnRight:
697
                        PutDoc("/TwoColumnRight\n");
698
                        break;
699
        }
700
        if (Options.displayBookmarks)
701
                PutDoc("/PageMode /UseOutlines\n");
702
        else if (Options.displayFullscreen)
703
                PutDoc("/PageMode /FullScreen\n");
704
        else if (Options.displayThumbs)
705
                PutDoc("/PageMode /UseThumbs\n");
706
        else if ((Options.Version == PDFOptions::PDFVersion_15) && (Options.displayLayers))
707
                        PutDoc("/PageMode /UseOC\n");
708
        if (!Options.openAction.isEmpty())
709
        {
20112 jghali 710
                PutDoc("/OpenAction << /S /JavaScript /JS (this."+Pdf::toPdfDocEncoding(Options.openAction)+"\\(\\)) >>\n");
19114 avox 711
        }
20112 jghali 712
        QString tmp;
19114 avox 713
        QDateTime dt = QDateTime::currentDateTime().toUTC();
20112 jghali 714
        Datum = Pdf::toDateString(dt);
20103 avox 715
//    "D:";
716
//      tmp.sprintf("%4d", d.year());
717
//      tmp.replace(QRegExp(" "), "0");
718
//      Datum += tmp;
719
//      tmp.sprintf("%2d", d.month());
720
//      tmp.replace(QRegExp(" "), "0");
721
//      Datum += tmp;
722
//      tmp.sprintf("%2d", d.day());
723
//      tmp.replace(QRegExp(" "), "0");
724
//      Datum += tmp;
725
//      tmp = dt.time().toString();
726
//      tmp.replace(QRegExp(":"), "");
727
//      Datum += tmp;
728
//      Datum += "Z";
12429 fschmid 729
 
19114 avox 730
        // only include XMP to PDF/X-4 at the moment, could easily be extended to include it to any PDF
731
        if (Options.Version == PDFOptions::PDFVersion_X4)
732
                generateXMP(dt.toString("yyyy-MM-ddThh:mm:ssZ"));
733
 
734
/* The following code makes the resulting PDF "Reader enabled" in Acrobat Reader 8
735
   but sadly it doesn't work with newer version, because its based on a bug in AR 8
736
        PutDoc("/Perms\n");
737
        PutDoc("<<\n");
738
        PutDoc("/UR3\n");
739
        PutDoc("<<\n");
740
        PutDoc("/M ("+Datum+")\n");
741
        PutDoc("/Name (Scribus "+QString(VERSION)+")\n");
742
        PutDoc("/Reference [\n");
743
        PutDoc("<<\n");
744
        PutDoc("/TransformParams\n");
745
        PutDoc("<<\n");
746
        PutDoc("/Type /TransformParams\n");
747
        PutDoc("/V /2.2\n");
748
        PutDoc("/Document [/FullSave]\n");
749
        PutDoc("/Annots [/Create/Delete/Modify/Copy/Import/Export]\n");
750
        PutDoc("/Form [/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate]\n");
751
        PutDoc("/Signature [/Modify]\n");
752
        PutDoc(">>\n");
753
        PutDoc("/TransformMethod /UR3\n");
754
        PutDoc("/Type /SigRef\n");
755
        PutDoc(">>\n");
756
        PutDoc("]\n");
757
        PutDoc("/Type /Sig\n");
758
        PutDoc(">>\n");
759
        PutDoc(">>\n");
760
*/
761
 
762
        PutDoc("/ViewerPreferences\n<<\n/PageDirection ");
763
        PutDoc( Options.Binding == 0 ? "/L2R\n" : "/R2L\n");
764
        if (Options.hideToolBar)
765
                PutDoc("/HideToolbar true\n");
766
        if (Options.hideMenuBar)
767
                PutDoc("/HideMenubar true\n");
768
        if (Options.fitWindow)
769
                PutDoc("/FitWindow true\n");
20112 jghali 770
        PutDoc(" >>\n>>");
771
        writer.endObj(writer.CatalogObj);
20103 avox 772
}
773
 
774
void PDFLibCore::PDF_Begin_MetadataAndEncrypt()
775
{
19114 avox 776
        QString IDg(Datum);
777
        IDg += Options.fileName;
778
        IDg += "Scribus "+QString(VERSION);
779
        IDg += "Scribus PDF Library "+QString(VERSION);
780
        IDg += doc.documentInfo().title();
781
        IDg += doc.documentInfo().author();
782
        IDg += "/False";
20112 jghali 783
        writer.setFileId(Pdf::toPdfDocEncoding(IDg));
19114 avox 784
        if (Options.Encrypt)
785
        {
20112 jghali 786
                writer.setEncryption((Options.Version == PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_15), Pdf::toPdfDocEncoding(Options.PassOwner), Pdf::toPdfDocEncoding(Options.PassUser), Options.Permissions);
19114 avox 787
        }
20103 avox 788
        writer.startObj(writer.InfoObj);
20112 jghali 789
        PutDoc("<<\n/Creator " + EncString(QByteArray("Scribus ") + VERSION, writer.InfoObj) + "\n");
20103 avox 790
        PutDoc("/Producer " + EncString(QByteArray("Scribus PDF Library ") + VERSION, writer.InfoObj) + "\n");
19114 avox 791
        QString docTitle = doc.documentInfo().title();
19115 avox 792
        if ((PDF_IsPDFX()) && (docTitle.isEmpty()))
20103 avox 793
                PutDoc("/Title " + EncStringUTF16(doc.DocName, writer.InfoObj) + "\n");
19114 avox 794
        else
20103 avox 795
                PutDoc("/Title " + EncStringUTF16(doc.documentInfo().title(), writer.InfoObj) + "\n");
796
        PutDoc("/Author " + EncStringUTF16(doc.documentInfo().author(), writer.InfoObj) + "\n");
797
        PutDoc("/Subject " + EncStringUTF16(doc.documentInfo().subject(), writer.InfoObj) + "\n");
798
        PutDoc("/Keywords " + EncStringUTF16(doc.documentInfo().keywords(), writer.InfoObj) + "\n");
799
        PutDoc("/CreationDate " + EncString(Datum, writer.InfoObj) + "\n");
800
        PutDoc("/ModDate " + EncString(Datum, writer.InfoObj) + "\n");
19114 avox 801
        if (Options.Version == PDFOptions::PDFVersion_X1a)
802
        {
803
                PutDoc("/GTS_PDFXVersion (PDF/X-1:2001)\n");
804
                PutDoc("/GTS_PDFXConformance (PDF/X-1a:2001)\n");
805
        }
19115 avox 806
        if (Options.Version == PDFOptions::PDFVersion_X3)
807
                PutDoc("/GTS_PDFXVersion (PDF/X-3:2002)\n");
19114 avox 808
        if (Options.Version == PDFOptions::PDFVersion_X4)
809
                PutDoc("/GTS_PDFXVersion (PDF/X-4)\n");
20112 jghali 810
        PutDoc("/Trapped /False\n>>");
811
        writer.endObj(writer.InfoObj);
20103 avox 812
 
20112 jghali 813
        // Encrypt
814
 
815
//      for (int t = 0; t < 6; ++t)
20103 avox 816
//              XRef.append(bytesWritten());
817
//      if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
818
//              XRef.append(bytesWritten());
819
//      if (PDF_IsPDFX())
820
//              XRef.append(bytesWritten());
821
//      if (Options.Version == PDFOptions::PDFVersion_X4)
822
//              XRef.append(bytesWritten());
19114 avox 823
        if (Options.Encrypt)
20103 avox 824
        { // now done in writer.setEncrption():
825
//              writer.EncryptObj = writer.newObject();
826
//              writer.startObj(writer.EncryptObj);
827
//              PutDoc("<<\n/Filter /Standard\n");
828
//              PutDoc( KeyLen > 5 ? "/R 3\n/V 2\n/Length 128\n" : "/R 2\n/V 1\n");
829
//              PutDoc("/O "+Pdf::toHexString(ok)+"\n");
830
//              PutDoc("/U "+Pdf::toHexString(uk)+"\n");
20112 jghali 831
//              PutDoc("/P "+Pdf::toPdf(Options.Permissions)+"\n>>");
832
//              writer.endObj(writer.EncryptObj);
19114 avox 833
        }
20103 avox 834
}
835
 
836
QMap<QString, QMap<uint, FPointArray> >
837
PDFLibCore::PDF_Begin_FindUsedFonts(SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& DocFonts)
838
{
5387 avox 839
        QMap<QString, QMap<uint, FPointArray> > ReallyUsed;
3133 fschmid 840
        ReallyUsed.clear();
841
        PageItem* pgit;
20103 avox 842
        QMap<int, QByteArray> ind2PDFabr;
843
        const QByteArray tmpf[] = {"/Courier", "/Courier-Bold", "/Courier-Oblique", "/Courier-BoldOblique",
4017 fschmid 844
                                                                                                "/Helvetica", "/Helvetica-Bold", "/Helvetica-Oblique", "/Helvetica-BoldOblique",
4546 subik 845
                                                                                                "/Times-Roman", "/Times-Bold", "/Times-Italic", "/Times-BoldItalic",
4017 fschmid 846
                                                                                                "/ZapfDingbats", "/Symbol"};
847
        size_t ar = sizeof(tmpf) / sizeof(*tmpf);
848
        for (uint ax = 0; ax < ar; ++ax)
849
                ind2PDFabr[ax] = tmpf[ax];
16953 fschmid 850
        QList<PageItem*> allItems;
17407 fschmid 851
        for (QHash<int, PageItem*>::iterator itf = doc.FrameItems.begin(); itf != doc.FrameItems.end(); ++itf)
3133 fschmid 852
        {
17407 fschmid 853
                pgit = itf.value();
16953 fschmid 854
                if (pgit->isGroup())
855
                        allItems = pgit->asGroupFrame()->getItemList();
856
                else
857
                        allItems.append(pgit);
858
                for (int ii = 0; ii < allItems.count(); ii++)
3133 fschmid 859
                {
16953 fschmid 860
                        pgit = allItems.at(ii);
17312 fschmid 861
                        if (pgit->isTable())
862
                        {
863
                                for (int row = 0; row < pgit->asTable()->rows(); ++row)
864
                                {
865
                                        for (int col = 0; col < pgit->asTable()->columns(); col ++)
866
                                        {
867
                                                TableCell cell = pgit->asTable()->cellAt(row, col);
868
                                                if (cell.row() == row && cell.column() == col)
869
                                                {
870
                                                        PageItem* textFrame = cell.textFrame();
871
                                                        for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
872
                                                        {
873
                                                                ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
874
                                                        }
875
                                                }
876
                                        }
877
                                }
878
                        }
16953 fschmid 879
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 880
                        {
16953 fschmid 881
                                if (pgit->isAnnotation())
12763 fschmid 882
                                {
16953 fschmid 883
                                        int annotType  = pgit->annotation().Type();
17911 fschmid 884
                                        bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
17952 fschmid 885
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 886
                                                StdFonts.insert("/ZapfDingbats", "");
887
                                        if (pgit->itemText.length() > 0 || mustEmbed)
888
                                        {
889
                                                if (Options.Version < PDFOptions::PDFVersion_14)
890
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
891
                                                ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
892
                                        }
12763 fschmid 893
                                }
17751 jghali 894
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
895
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
896
                                for (uint e = start; e < stop; ++e)
16953 fschmid 897
                                {
898
                                        ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
899
                                }
8092 fschmid 900
                        }
3133 fschmid 901
                }
902
        }
9856 fschmid 903
        for (int c = 0; c < doc.MasterItems.count(); ++c)
3133 fschmid 904
        {
4264 craig 905
                pgit = doc.MasterItems.at(c);
16953 fschmid 906
                if (pgit->isGroup())
907
                        allItems = pgit->asGroupFrame()->getItemList();
908
                else
909
                        allItems.append(pgit);
910
                for (int ii = 0; ii < allItems.count(); ii++)
3133 fschmid 911
                {
16953 fschmid 912
                        pgit = allItems.at(ii);
17312 fschmid 913
                        if (pgit->isTable())
914
                        {
915
                                for (int row = 0; row < pgit->asTable()->rows(); ++row)
916
                                {
917
                                        for (int col = 0; col < pgit->asTable()->columns(); col ++)
918
                                        {
919
                                                TableCell cell = pgit->asTable()->cellAt(row, col);
920
                                                if (cell.row() == row && cell.column() == col)
921
                                                {
922
                                                        PageItem* textFrame = cell.textFrame();
923
                                                        for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
924
                                                        {
925
                                                                ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
926
                                                        }
927
                                                }
928
                                        }
929
                                }
930
                        }
16953 fschmid 931
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 932
                        {
16953 fschmid 933
                                if (pgit->isAnnotation())
12763 fschmid 934
                                {
16953 fschmid 935
                                        int annotType  = pgit->annotation().Type();
17911 fschmid 936
                                        bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
17952 fschmid 937
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 938
                                                StdFonts.insert("/ZapfDingbats", "");
939
                                        if (pgit->itemText.length() > 0 || mustEmbed)
940
                                        {
941
                                                if (Options.Version < PDFOptions::PDFVersion_14)
942
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
943
                                                ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
944
                                        }
12763 fschmid 945
                                }
17751 jghali 946
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
947
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
948
                                for (uint e = start; e < stop; ++e)
16953 fschmid 949
                                {
950
                                        ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
951
                                }
8092 fschmid 952
                        }
3133 fschmid 953
                }
954
        }
9856 fschmid 955
        for (int d = 0; d < doc.Items->count(); ++d)
3133 fschmid 956
        {
4264 craig 957
                pgit = doc.Items->at(d);
16953 fschmid 958
                if (pgit->isGroup())
959
                        allItems = pgit->asGroupFrame()->getItemList();
960
                else
961
                        allItems.append(pgit);
962
                for (int ii = 0; ii < allItems.count(); ii++)
3133 fschmid 963
                {
16953 fschmid 964
                        pgit = allItems.at(ii);
17312 fschmid 965
                        if (pgit->isTable())
966
                        {
967
                                for (int row = 0; row < pgit->asTable()->rows(); ++row)
968
                                {
969
                                        for (int col = 0; col < pgit->asTable()->columns(); col ++)
970
                                        {
971
                                                TableCell cell = pgit->asTable()->cellAt(row, col);
972
                                                if (cell.row() == row && cell.column() == col)
973
                                                {
974
                                                        PageItem* textFrame = cell.textFrame();
975
                                                        for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
976
                                                        {
977
                                                                ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
978
                                                        }
979
                                                }
980
                                        }
981
                                }
982
                        }
16953 fschmid 983
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 984
                        {
16953 fschmid 985
                                if (pgit->isAnnotation())
12763 fschmid 986
                                {
16953 fschmid 987
                                        int annotType  = pgit->annotation().Type();
17911 fschmid 988
                                        bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
17952 fschmid 989
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 990
                                                StdFonts.insert("/ZapfDingbats", "");
991
                                        if (pgit->itemText.length() > 0 || mustEmbed)
992
                                        {
993
                                                if (Options.Version < PDFOptions::PDFVersion_14)
994
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
995
                                                ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
996
                                        }
12763 fschmid 997
                                }
17751 jghali 998
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
999
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1000
                                for (uint e = start; e < stop; ++e)
16953 fschmid 1001
                                {
1002
                                        ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
1003
                                }
8092 fschmid 1004
                        }
3133 fschmid 1005
                }
1006
        }
11453 fschmid 1007
/*      if (Options.docInfoMarks)
6943 fschmid 1008
        {
1009
                StdFonts.insert("/Helvetica", "");
11453 fschmid 1010
        } */
16052 fschmid 1011
        QStringList patterns = doc.getPatternDependencyList(doc.getUsedPatterns());
8559 subik 1012
        for (int c = 0; c < patterns.count(); ++c)
6407 fschmid 1013
        {
1014
                ScPattern pa = doc.docPatterns[patterns[c]];
9856 fschmid 1015
                for (int o = 0; o < pa.items.count(); o++)
6407 fschmid 1016
                {
1017
                        pgit = pa.items.at(o);
16953 fschmid 1018
                        if (pgit->isGroup())
1019
                                allItems = pgit->asGroupFrame()->getItemList();
1020
                        else
1021
                                allItems.append(pgit);
1022
                        for (int ii = 0; ii < allItems.count(); ii++)
6407 fschmid 1023
                        {
16953 fschmid 1024
                                pgit = allItems.at(ii);
17312 fschmid 1025
                                if (pgit->isTable())
1026
                                {
1027
                                        for (int row = 0; row < pgit->asTable()->rows(); ++row)
1028
                                        {
1029
                                                for (int col = 0; col < pgit->asTable()->columns(); col ++)
1030
                                                {
1031
                                                        TableCell cell = pgit->asTable()->cellAt(row, col);
1032
                                                        if (cell.row() == row && cell.column() == col)
1033
                                                        {
1034
                                                                PageItem* textFrame = cell.textFrame();
1035
                                                                for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
1036
                                                                {
1037
                                                                        ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
1038
                                                                }
1039
                                                        }
1040
                                                }
1041
                                        }
1042
                                }
16953 fschmid 1043
                                if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8351 fschmid 1044
                                {
16953 fschmid 1045
                                        if (pgit->isAnnotation())
12763 fschmid 1046
                                        {
17952 fschmid 1047
                                                if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 1048
                                                        StdFonts.insert("/ZapfDingbats", "");
1049
                                                if (pgit->itemText.length() > 0)
1050
                                                {
1051
                                                        if (Options.Version < PDFOptions::PDFVersion_14)
1052
                                                                StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
1053
                                                        ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
1054
                                                }
12763 fschmid 1055
                                        }
17751 jghali 1056
                                        uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
1057
                                        uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1058
                                        for (uint e = start; e < stop; ++e)
16953 fschmid 1059
                                        {
1060
                                                ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
1061
                                        }
8351 fschmid 1062
                                }
6407 fschmid 1063
                        }
1064
                }
1065
        }
20112 jghali 1066
        return ReallyUsed;
20103 avox 1067
}
17628 jghali 1068
 
20103 avox 1069
static QByteArray sanitizeFontName(QString fn)
1070
{
20112 jghali 1071
        return Pdf::toPdfDocEncoding(fn.replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" ));
20103 avox 1072
}
17628 jghali 1073
 
20103 avox 1074
static QList<Pdf::Resource> asColorSpace(QList<PdfICCD> iccCSlist)
1075
{
20112 jghali 1076
        QList<Pdf::Resource> result;
1077
        foreach (Pdf::Resource r, iccCSlist)
1078
        {
1079
                result.append(r);
1080
        }
1081
        return result;
20103 avox 1082
}
1083
 
1084
static QList<Pdf::Resource> asColorSpace(QList<PdfSpotC> spotMapValues)
1085
{
20112 jghali 1086
        QList<Pdf::Resource> result;
1087
        foreach (Pdf::Resource r, spotMapValues)
1088
        {
1089
                result.append(r);
1090
        }
1091
        return result;
20103 avox 1092
}
1093
 
1094
 
1095
void PDFLibCore::PDF_WriteStandardFonts()
1096
{
20112 jghali 1097
        int a = 0;
1098
        QMap<QString, QString>::Iterator itStd;
1099
        for (itStd = StdFonts.begin(); itStd != StdFonts.end(); ++itStd)
1100
        {
1101
                PdfId fontObject = writer.newObject();
1102
                writer.startObj(fontObject);
1103
                PutDoc("<<\n/Type /Font\n/Subtype /Type1\n");
1104
                PutDoc("/Name /FoStd"+Pdf::toPdf(a)+"\n");
1105
                PutDoc("/BaseFont "+Pdf::toPdfDocEncoding(itStd.key())+"\n");
1106
                if (itStd.key() != "/ZapfDingbats")
1107
                {
1108
                        PutDoc("/Encoding << \n");
1109
                        PutDoc("/Differences [ \n");
1110
                        PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
1111
                        PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
1112
                        PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
1113
                        PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
1114
                        PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
1115
                        PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
1116
                        PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
1117
                        PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
1118
                        PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
1119
                        PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
1120
                        PutDoc("] >>\n");
1121
                }
1122
                PutDoc(">>");
1123
                writer.endObj(fontObject);
1124
                pageData.FObjects["FoStd"+Pdf::toPdf(a)] = fontObject;
1125
                itStd.value() = "FoStd"+Pdf::toPdf(a);
1126
                a++;
1127
        }
20103 avox 1128
}
1129
 
1130
 
1131
PdfFont PDFLibCore::PDF_WriteType3Font(const QByteArray& name, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1132
{
20112 jghali 1133
        PdfFont result;
1134
        result.name = Pdf::toName(name);
1135
        result.method = Use_Type3;
1136
        result.encoding = Encode_256;
20103 avox 1137
 
20112 jghali 1138
        uint SubFonts = 0;
1139
        int glyphCount = 0;
1140
        double minx =  std::numeric_limits<double>::max();
1141
        double miny =  std::numeric_limits<double>::max();
1142
        double maxx = -std::numeric_limits<double>::max();
1143
        double maxy = -std::numeric_limits<double>::max();
1144
        QList<uint> glyphWidths;
1145
        QList<QByteArray> charProcs;
1146
        QByteArray encoding = "<< /Type /Encoding\n/Differences [ 0\n";
1147
        QByteArray fon;
1148
        QMap<uint, uint> glyphMapping;
1149
        ScFace::FaceEncoding gl;
1150
        face.glyphNames(gl);
1151
        QMap<uint,FPointArray>::ConstIterator ig;
1152
        for (ig = RealGlyphs.cbegin(); ig != RealGlyphs.cend(); ++ig)
1153
        {
1154
                FPoint np, np1, np2;
1155
                bool nPath = true;
1156
                fon.resize(0);
1157
                if (ig.value().size() > 3)
1158
                {
1159
                        FPointArray gly = ig.value();
1160
                        QTransform mat;
1161
                        mat.scale(100.0, -100.0);
1162
                        gly.map(mat);
1163
                        gly.translate(0, 1000);
1164
                        for (int poi = 0; poi < gly.size()-3; poi += 4)
1165
                        {
1166
                                if (gly.isMarker(poi))
1167
                                {
1168
                                        fon += "h\n";
1169
                                        nPath = true;
1170
                                        continue;
1171
                                }
1172
                                if (nPath)
1173
                                {
1174
                                        np = gly.point(poi);
1175
                                        fon += FToStr(np.x())+" "+FToStr(np.y())+" m\n";
1176
                                        nPath = false;
1177
                                }
1178
                                np = gly.point(poi+1);
1179
                                np1 = gly.point(poi+3);
1180
                                np2 = gly.point(poi+2);
1181
                                fon += FToStr(np.x()) + " " + FToStr(np.y()) + " " + FToStr(np1.x()) + " " + FToStr(np1.y()) + " " + FToStr(np2.x()) + " " + FToStr(np2.y()) + " c\n";
1182
                        }
1183
                        fon += "h f*\n";
1184
                        np = getMinClipF(&gly);
1185
                        np1 = getMaxClipF(&gly);
1186
                }
1187
                else
1188
                {
20684 jghali 1189
                        // 13654: make evince emit warning about "Syntax Error: No current point in closepath"
1190
                        // PDF specification is not quite clear about that, but a single "h" operator might not
1191
                        // be a valid way to make an empty path
1192
                        // fon = "h";
20112 jghali 1193
                        np = FPoint(0, 0);
1194
                        np1 = FPoint(0, 0);
1195
                }
1196
                fon.prepend(Pdf::toPdf(qRound(np1.x())) + " 0 "+Pdf::toPdf(qRound(np.x()))+" "+Pdf::toPdf(qRound(np.y()))+" "+Pdf::toPdf(qRound(np1.x()))+ " "+Pdf::toPdf(qRound(np1.y()))+" d1\n");
1197
                minx = qMin(minx, np.x());
1198
                miny = qMin(miny, np.y());
1199
                maxx = qMax(maxx, np1.x());
1200
                maxy = qMax(maxy, np1.y());
1201
                glyphWidths.append(qRound(np1.x()));
1202
                PdfId charProcObject = writer.newObject();
1203
                charProcs.append(Pdf::toName(gl[ig.key()].second)+" "+Pdf::toPdf(charProcObject)+" 0 R\n");
1204
                encoding += Pdf::toName(gl[ig.key()].second)+" ";
1205
                glyphMapping.insert(ig.key(), glyphCount + SubFonts * 256);
1206
                writer.startObj(charProcObject);
1207
                if (Options.Compress)
1208
                        fon = CompressArray(fon);
1209
                PutDoc("<< /Length "+Pdf::toPdf(fon.length()+1));
1210
                if (Options.Compress)
1211
                        PutDoc("\n/Filter /FlateDecode");
1212
                PutDoc("\n>>\nstream\n"+EncStream(fon, charProcObject)+"\nendstream");
1213
                writer.endObj(charProcObject);
1214
                glyphCount++;
1215
                int glyphsLeft = RealGlyphs.count() - SubFonts * 256;
1216
                if ((glyphCount > 255) || (glyphCount == glyphsLeft))
1217
                {
1218
                        PdfId fontWidths = writer.newObject();
1219
                        writer.startObj(fontWidths);
1220
                        PutDoc("[ ");
1221
                        for (int ww = 0; ww < glyphWidths.count(); ++ww)
1222
                        {
1223
                                PutDoc(Pdf::toPdf(glyphWidths[ww])+" ");
1224
                        }
1225
                        PutDoc("]");
1226
                        writer.endObj(fontWidths);
1227
                        PdfId fontCharProcs = writer.newObject();
1228
                        writer.startObj(fontCharProcs);
1229
                        PutDoc("<<\n");
1230
                        for (int ww = 0; ww < charProcs.count(); ++ww)
1231
                        {
1232
                                PutDoc(charProcs[ww]);
1233
                        }
1234
                        PutDoc(">>");
1235
                        writer.endObj(fontCharProcs);
1236
                        PdfId fontEncoding = writer.newObject();
1237
                        writer.startObj(fontEncoding);
1238
                        PutDoc(encoding);
1239
                        PutDoc("]\n");
1240
                        PutDoc(">>");
1241
                        writer.endObj(fontEncoding);
1242
                        PdfId font3Object = writer.newObject();
1243
                        writer.startObj(font3Object);
1244
                        PutDoc("<<\n/Type /Font\n/Subtype /Type3\n");
1245
                        PutDoc("/Name /"+name+"S"+Pdf::toPdf(SubFonts)+"\n");
1246
                        PutDoc("/FirstChar 0\n");
1247
                        PutDoc("/LastChar "+Pdf::toPdf(glyphCount-1)+"\n");
1248
                        PutDoc("/Widths "+Pdf::toPdf(fontWidths)+" 0 R\n");
1249
                        PutDoc("/CharProcs "+Pdf::toPdf(fontCharProcs)+" 0 R\n");
1250
                        PutDoc("/FontBBox ["+Pdf::toPdf(qRound(minx))+" "+Pdf::toPdf(qRound(miny))+" "+Pdf::toPdf(qRound(maxx))+ " "+Pdf::toPdf(qRound(maxy))+"]\n");
1251
                        PutDoc("/FontMatrix [0.001 0 0 0.001 0 0]\n");
1252
                        PutDoc("/Encoding "+Pdf::toPdf(fontEncoding)+" 0 R\n");
1253
                        PutDoc(">>");
1254
                        writer.endObj(font3Object);
1255
                        pageData.FObjects[name+"S"+Pdf::toPdf(SubFonts)] = font3Object;
1256
                        charProcs.clear();
1257
                        glyphWidths.clear();
1258
                        //                                              glyphMapping.clear();
1259
                        glyphCount = 0;
1260
                        ++SubFonts;
1261
                        minx =  std::numeric_limits<double>::max();
1262
                        miny =  std::numeric_limits<double>::max();
1263
                        maxx = -std::numeric_limits<double>::max();
1264
                        maxy = -std::numeric_limits<double>::max();
1265
                        encoding = "<< /Type /Encoding\n/Differences [ 0\n";
1266
                }
1267
        }
1268
        result.glyphmap = glyphMapping;
1269
        return result;
20103 avox 1270
}
1271
 
1272
 
1273
PdfFont PDFLibCore::PDF_WriteGlyphsAsXForms(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1274
{
20112 jghali 1275
        PdfFont result;
1276
        result.name = Pdf::toName(fontName);
1277
        result.method = Use_XForm;
1278
        result.encoding = Encode_224;
20103 avox 1279
 
20112 jghali 1280
        QByteArray fon;
1281
        QMap<uint,FPointArray>::ConstIterator ig;
1282
        for (ig = RealGlyphs.cbegin(); ig != RealGlyphs.cend(); ++ig)
1283
        {
1284
                FPoint np, np1, np2;
1285
                bool nPath = true;
1286
                fon.resize(0);
1287
                if (ig.value().size() > 3)
1288
                {
1289
                        FPointArray gly = ig.value();
1290
                        QTransform mat;
1291
                        mat.scale(0.1, 0.1);
1292
                        gly.map(mat);
1293
                        for (int poi = 0; poi < gly.size()-3; poi += 4)
1294
                        {
1295
                                if (gly.isMarker(poi))
1296
                                {
1297
                                        fon += "h\n";
1298
                                        nPath = true;
1299
                                        continue;
1300
                                }
1301
                                if (nPath)
1302
                                {
1303
                                        np = gly.point(poi);
1304
                                        fon += FToStr(np.x())+" "+FToStr(-np.y())+" m\n";
1305
                                        nPath = false;
1306
                                }
1307
                                np = gly.point(poi+1);
1308
                                np1 = gly.point(poi+3);
1309
                                np2 = gly.point(poi+2);
1310
                                fon += FToStr(np.x()) + " " + FToStr(-np.y()) + " " +
1311
                                FToStr(np1.x()) + " " + FToStr(-np1.y()) + " " +
1312
                                FToStr(np2.x()) + " " + FToStr(-np2.y()) + " c\n";
1313
                        }
1314
                        fon += "h f*\n";
1315
                        np = getMinClipF(&gly);
1316
                        np1 = getMaxClipF(&gly);
1317
                }
1318
                else
1319
                {
20684 jghali 1320
                        // 13654: make evince emit warning about "Syntax Error: No current point in closepath"
1321
                        // PDF specification is not quite clear about that, but a single "h" operator might not
1322
                        // be a valid way to make an empty path
1323
                        fon = " " /*"h"*/;
20112 jghali 1324
                        np = FPoint(0, 0);
1325
                        np1 = FPoint(0, 0);
1326
                }
1327
                PdfId fontGlyphXForm = writer.newObject();
1328
                writer.startObj(fontGlyphXForm);
1329
                PutDoc("<<\n/Type /XObject\n/Subtype /Form\n/FormType 1\n");
1330
                PutDoc("/BBox [ "+FToStr(np.x())+" "+FToStr(-np.y())+" "+FToStr(np1.x())+ " "+FToStr(-np1.y())+" ]\n");
1331
                PutDoc("/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n");
1332
                PutDoc(">>\n");
1333
                if (Options.Compress)
1334
                        fon = CompressArray(fon);
1335
                PutDoc("/Length "+Pdf::toPdf(fon.length()+1));
1336
                if (Options.Compress)
1337
                        PutDoc("\n/Filter /FlateDecode");
1338
                PutDoc(" >>\nstream\n"+EncStream(fon, fontGlyphXForm)+"\nendstream");
1339
                writer.endObj(fontGlyphXForm);
1340
                pageData.XObjects[fontName + Pdf::toPdf(ig.key())] = fontGlyphXForm;
1341
        }
1342
        return result;
20103 avox 1343
}
1344
 
1345
PdfId PDFLibCore::PDF_EmbedFontObject(const QByteArray& font, const QByteArray& subtype)
1346
 
1347
{
20112 jghali 1348
        PdfId embeddedFontObject = writer.newObject();
1349
        writer.startObj(embeddedFontObject);
1350
        int len = font.length();
1351
        QByteArray ttf = (Options.Compress? CompressArray(font) : font);
1352
        //qDebug() << QString("sfnt data: size=%1 compressed=%2").arg(len).arg(bb.length());
1353
        PutDoc("<<\n/Length " + Pdf::toPdf(ttf.length() + 1) + "\n");
1354
        PutDoc("/Length1 " + Pdf::toPdf(len) + "\n");
1355
        if (subtype.size() > 0)
1356
                PutDoc("/Subtype " + subtype);
1357
        if (Options.Compress)
1358
                PutDoc("/Filter /FlateDecode\n");
1359
        PutDoc(">>\nstream\n");
1360
        EncodeArrayToStream(ttf, embeddedFontObject);
1361
        PutDoc("\nendstream");
1362
        writer.endObj(embeddedFontObject);
1363
        return embeddedFontObject;
20103 avox 1364
}
1365
 
1366
PdfId PDFLibCore::PDF_WriteFontDescriptor(const QByteArray& fontName, ScFace& face, ScFace::FontFormat fformat, PdfId embeddedFontObject)
1367
{
20112 jghali 1368
        PdfId fontDescriptor = writer.newObject();
1369
        writer.startObj(fontDescriptor);
1370
        // TODO: think about QByteArray ScFace::getFontDescriptor() -- AV
1371
        PutDoc("<<\n/Type /FontDescriptor\n");
1372
        PutDoc("/FontName "  + Pdf::toName(fontName) + "\n");
1373
        PutDoc("/FontBBox [ " + Pdf::toAscii(face.pdfFontBBoxAsString()) + " ]\n");
1374
        PutDoc("/Flags ");
1375
        //FIXME: isItalic() should be queried from ScFace, not from Qt -- AV
1376
        //QFontInfo fo = QFontInfo(it.data());
1377
        int pfl = 0;
1378
        if (face.isFixedPitch())
1379
                pfl = pfl ^ 1;
1380
        //if (fo.italic())
1381
        if (face.italicAngleAsString() != "0")
1382
                pfl = pfl ^ 64;
1383
        //                      pfl = pfl ^ 4;
1384
        pfl = pfl ^ 32;
1385
        PutDoc(Pdf::toPdf(pfl)+"\n");
1386
        PutDoc("/Ascent "      + Pdf::toAscii(face.pdfAscentAsString())+"\n");
1387
        PutDoc("/Descent "     + Pdf::toAscii(face.pdfDescentAsString())+"\n");
1388
        PutDoc("/CapHeight "   + Pdf::toAscii(face.pdfCapHeightAsString())+"\n");
1389
        PutDoc("/ItalicAngle " + Pdf::toAscii(face.italicAngleAsString())+"\n");
1390
        PutDoc("/StemV 1\n");
1391
        if (embeddedFontObject != 0)
1392
        {
1393
                if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1394
                {
1395
                        if (face.type() == ScFace::OTF)
1396
                        {
1397
                                PutDoc("/FontFile3 "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1398
                        }
1399
                        else
1400
                        {
1401
                                PutDoc("/FontFile2 "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1402
                        }
1403
                }
1404
                else if (fformat == ScFace::PFB)
1405
                        PutDoc("/FontFile "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1406
                else if (fformat == ScFace::PFA)
1407
                        PutDoc("/FontFile "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1408
        }
1409
        PutDoc(">>");
1410
        writer.endObj(fontDescriptor);
1411
        return fontDescriptor;
20103 avox 1412
}
1413
 
1414
PdfFont PDFLibCore::PDF_EncodeCidFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, PdfId fontDes, const ScFace::FaceEncoding& gl, const QMap<uint,uint> glyphmap  )
1415
{
20112 jghali 1416
        PdfFont result;
1417
        result.name = Pdf::toName(fontName);
1418
        result.method = glyphmap.isEmpty()? Use_Embedded : Use_Subset;
1419
        result.encoding = glyphmap.isEmpty()? Encode_IdentityH : Encode_Subset;
1420
        result.glyphmap = glyphmap;
1421
 
1422
        PdfId fontWidths2 = writer.newObject();
1423
        writer.startObj(fontWidths2);
1424
        QList<QByteArray> toUnicodeMaps;
1425
        QList<int> toUnicodeMapsCount;
1426
        QByteArray toUnicodeMap = "";
1427
        int toUnicodeMapCounter = 0;
1428
 
1429
        PutDoc("[ ");
1430
        QList<uint> keys = gl.uniqueKeys();
1431
        QList<uint>::iterator git;
1432
        bool seenNotDef = false;
1433
        for (git = keys.begin(); git != keys.end(); ++git)
1434
        {
1435
                uint gid = result.encoding == Encode_Subset? glyphmap[*git] : *git;
1436
                if (gid > 0 || !seenNotDef)
1437
                {
1438
                        seenNotDef |= (gid == 0);
1439
                        PutDoc(Pdf::toPdf(gid)+" ["+Pdf::toPdf(static_cast<int>(face.glyphWidth(*git)* 1000))+"] " );
1440
                        QString tmp, tmp2;
1441
                        tmp.sprintf("%04X", gid);
1442
                        tmp2.sprintf("%04X", gl.value(*git).first);
1443
                        toUnicodeMap += "<" + Pdf::toAscii(tmp)+ "> <" + Pdf::toAscii(tmp2) + ">\n";
1444
                        toUnicodeMapCounter++;
1445
                        if (toUnicodeMapCounter == 100)
1446
                        {
1447
                                toUnicodeMaps.append(toUnicodeMap);
1448
                                toUnicodeMapsCount.append(toUnicodeMapCounter);
1449
                                toUnicodeMap = "";
1450
                                toUnicodeMapCounter = 0;
1451
                        }
1452
                }
1453
        }
1454
        PutDoc("]");
1455
        writer.endObj(fontWidths2);
1456
        if (toUnicodeMapCounter != 0)
1457
        {
1458
                toUnicodeMaps.append(toUnicodeMap);
1459
                toUnicodeMapsCount.append(toUnicodeMapCounter);
1460
        }
1461
        QByteArray toUnicodeMapStream = "";
1462
        toUnicodeMapStream += "/CIDInit /ProcSet findresource begin\n";
1463
        toUnicodeMapStream += "12 dict begin\n";
1464
        toUnicodeMapStream += "begincmap\n";
1465
        toUnicodeMapStream += "/CIDSystemInfo <<\n";
1466
        toUnicodeMapStream += "/Registry (Adobe)\n";
1467
        toUnicodeMapStream += "/Ordering (UCS)\n";
1468
        toUnicodeMapStream += "/Supplement 0\n";
1469
        toUnicodeMapStream += ">> def\n";
1470
        toUnicodeMapStream += "/CMapName /Adobe-Identity-UCS def\n";
1471
        toUnicodeMapStream += "/CMapType 2 def\n";
1472
        toUnicodeMapStream += "1 begincodespacerange\n";
1473
        toUnicodeMapStream += "<0000> <FFFF>\n";
1474
        toUnicodeMapStream += "endcodespacerange\n";
1475
        for (int uniC = 0; uniC < toUnicodeMaps.count(); uniC++)
1476
        {
1477
                toUnicodeMapStream += Pdf::toPdf(toUnicodeMapsCount[uniC]);
1478
                toUnicodeMapStream += " beginbfchar\n";
1479
                toUnicodeMapStream += toUnicodeMaps[uniC];
1480
                toUnicodeMapStream += "endbfchar\n";
1481
        }
1482
        toUnicodeMapStream += "endcmap\n";
1483
        toUnicodeMapStream += "CMapName currentdict /CMap defineresource pop\n";
1484
        toUnicodeMapStream += "end\n";
1485
        toUnicodeMapStream += "end\n";
1486
        PdfId fontToUnicode2 = WritePDFStream(toUnicodeMapStream);
1487
        PdfId fontObject2 = writer.newObject();
1488
        writer.startObj(fontObject2);
1489
        PutDoc("<<\n/Type /Font\n/Subtype /Type0\n");
1490
        PutDoc("/Name " + Pdf::toName(fontName) + "\n");
1491
        PutDoc("/BaseFont "+ baseFont +"\n");
1492
        PutDoc("/Encoding /Identity-H\n");
1493
        PutDoc("/ToUnicode "+Pdf::toPdf(fontToUnicode2)+" 0 R\n");
1494
        PutDoc("/DescendantFonts [");
1495
        PutDoc("<</Type /Font");
1496
        if (face.type() == ScFace::OTF)
1497
                PutDoc("/Subtype /CIDFontType0");
1498
        else
1499
                PutDoc("/Subtype /CIDFontType2");
1500
        PutDoc("/BaseFont " + baseFont);
1501
        PutDoc("/FontDescriptor " + Pdf::toPdf(fontDes)+ " 0 R");
1502
        PutDoc("/CIDSystemInfo <</Ordering(Identity)/Registry(Adobe)/Supplement 0>>");
1503
        PutDoc("/DW 1000");
1504
        PutDoc("/W "+Pdf::toPdf(fontWidths2)+" 0 R");
1505
        PutDoc("/CIDToGIDMap /Identity");
1506
        PutDoc(">>"); // close CIDFont dictionary
1507
        PutDoc("]\n"); // close DescendantFonts array
1508
        PutDoc(">>");
1509
        writer.endObj(fontObject2);
1510
        pageData.FObjects[fontName] = fontObject2;
1511
        return result;
20103 avox 1512
}
1513
 
1514
 
1515
PdfFont PDFLibCore::PDF_EncodeSimpleFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, const QByteArray& subtype, bool isEmbedded, PdfId fontDes, const ScFace::FaceEncoding& gl)
1516
{
20112 jghali 1517
        PdfFont result;
1518
        result.name = Pdf::toName(fontName);
1519
        result.method = isEmbedded? Use_Embedded : Use_System;
1520
        result.encoding = Encode_224;
1521
 
1522
        int nglyphs = 0;
1523
        ScFace::FaceEncoding::ConstIterator gli;
1524
        for (gli = gl.cbegin(); gli != gl.cend(); ++gli)
1525
        {
1526
                if (gli.key() > static_cast<uint>(nglyphs))
1527
                        nglyphs = gli.key();
1528
        }
1529
        ++nglyphs;
1530
        //                      qDebug() << QString("pdflib: nglyphs %1 max %2").arg(nglyphs).arg(face.maxGlyph());
1531
 
1532
        uint Fcc = nglyphs / 224;
1533
        if ((nglyphs % 224) != 0)
1534
                Fcc += 1;
1535
        for (uint Fc = 0; Fc < Fcc; ++Fc)
1536
        {
1537
                PdfId fontWidths2 = writer.newObject();
1538
                writer.startObj(fontWidths2);
1539
                int chCount = 32;
1540
                PutDoc("[ 0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 ");
1541
                for (int ww = 32; ww < 256; ++ww)
1542
                {
1543
                        uint glyph = 224 * Fc + ww - 32;
1544
                        if (gl.contains(glyph))
1545
                                PutDoc(Pdf::toPdf(static_cast<int>(face.glyphWidth(glyph)* 1000))+" ");
1546
                        else
1547
                                PutDoc("0 ");
1548
                        chCount++;
1549
                        if (signed(glyph) == nglyphs-1)
1550
                                break;
1551
                }
1552
                PutDoc("]");
1553
                writer.endObj(fontWidths2);
1554
                PdfId fontEncoding2 = writer.newObject();
1555
                writer.startObj(fontEncoding2);
1556
                QStringList toUnicodeMaps;
1557
                QList<int> toUnicodeMapsCount;
1558
                QString toUnicodeMap = "";
1559
                int toUnicodeMapCounter = 0;
1560
                PutDoc("<< /Type /Encoding\n");
1561
                PutDoc("/Differences [ \n");
1562
                int crc = 0;
1563
                bool startOfSeq = true;
1564
                for (int ww2 = 32; ww2 < 256; ++ww2)
1565
                {
1566
                        uint glyph = 224 * Fc + ww2 - 32;
1567
                        ScFace::FaceEncoding::ConstIterator glIt = gl.find(glyph);
1568
                        if (glIt != gl.cend() && !glIt.value().second.isEmpty())
1569
                        {
1570
                                if (startOfSeq)
1571
                                {
1572
                                        PutDoc(Pdf::toPdf(ww2)+" ");
1573
                                        startOfSeq = false;
1574
                                }
1575
                                PutDoc(Pdf::toName(glIt.value().second)+" ");
1576
                                QString tmp, tmp2;
1577
                                tmp.sprintf("%02X", ww2);
1578
                                tmp2.sprintf("%04X", glIt.value().first);
1579
                                toUnicodeMap += "<" + Pdf::toAscii(tmp) + "> <" + Pdf::toAscii(tmp2) + ">\n";
1580
                                //QString("<%1> <%2>\n").arg(tmp).arg((tmp2));
1581
                                toUnicodeMapCounter++;
1582
                                if (toUnicodeMapCounter == 100)
1583
                                {
1584
                                        toUnicodeMaps.append(toUnicodeMap);
1585
                                        toUnicodeMapsCount.append(toUnicodeMapCounter);
1586
                                        toUnicodeMap = "";
1587
                                        toUnicodeMapCounter = 0;
1588
                                }
1589
                                crc++;
1590
                        }
1591
                        else
1592
                        {
1593
                                startOfSeq = true;
1594
                        }
1595
                        if (signed(glyph) == nglyphs-1)
1596
                                break;
1597
                        if (crc > 8)
1598
                        {
1599
                                PutDoc("\n");
1600
                                crc = 0;
1601
                        }
1602
                }
1603
                if (toUnicodeMapCounter != 0)
1604
                {
1605
                        toUnicodeMaps.append(toUnicodeMap);
1606
                        toUnicodeMapsCount.append(toUnicodeMapCounter);
1607
                }
1608
                PutDoc("]\n");
1609
                PutDoc(">>");
1610
                writer.endObj(fontEncoding2);
1611
                QByteArray toUnicodeMapStream = "";
1612
                toUnicodeMapStream += "/CIDInit /ProcSet findresource begin\n";
1613
                toUnicodeMapStream += "12 dict begin\n";
1614
                toUnicodeMapStream += "begincmap\n";
1615
                toUnicodeMapStream += "/CIDSystemInfo <<\n";
1616
                toUnicodeMapStream += "/Registry (Adobe)\n";
1617
                toUnicodeMapStream += "/Ordering (UCS)\n";
1618
                toUnicodeMapStream += "/Supplement 0\n";
1619
                toUnicodeMapStream += ">> def\n";
1620
                toUnicodeMapStream += "/CMapName /Adobe-Identity-UCS def\n";
1621
                toUnicodeMapStream += "/CMapType 2 def\n";
1622
                toUnicodeMapStream += "1 begincodespacerange\n";
1623
                toUnicodeMapStream += "<0000> <FFFF>\n";
1624
                toUnicodeMapStream += "endcodespacerange\n";
1625
                for (int uniC = 0; uniC < toUnicodeMaps.count(); uniC++)
1626
                {
1627
                        toUnicodeMapStream += Pdf::toPdf(toUnicodeMapsCount[uniC]);
1628
                        toUnicodeMapStream += " beginbfchar\n";
1629
                        toUnicodeMapStream += toUnicodeMaps[uniC];
1630
                        toUnicodeMapStream += "endbfchar\n";
1631
                }
1632
                toUnicodeMapStream += "endcmap\n";
1633
                toUnicodeMapStream += "CMapName currentdict /CMap defineresource pop\n";
1634
                toUnicodeMapStream += "end\n";
1635
                toUnicodeMapStream += "end\n";
1636
                PdfId fontToUnicode2 = WritePDFStream(toUnicodeMapStream);
1637
                PdfId fontObject2 = writer.newObject();
1638
                writer.startObj(fontObject2);
1639
                PutDoc("<<\n/Type /Font\n/Subtype ");
1640
                PutDoc(subtype + "\n");
1641
                PutDoc("/Name "+Pdf::toName(fontName)+"S"+Pdf::toPdf(Fc)+"\n");
1642
                PutDoc("/BaseFont "+baseFont+"\n");
1643
                PutDoc("/FirstChar 0\n");
1644
                PutDoc("/LastChar "+Pdf::toPdf(chCount-1)+"\n");
1645
                PutDoc("/Widths "+Pdf::toPdf(fontWidths2)+" 0 R\n");
1646
                PutDoc("/Encoding "+Pdf::toPdf(fontEncoding2)+" 0 R\n");
1647
                PutDoc("/ToUnicode "+Pdf::toPdf(fontToUnicode2)+" 0 R\n");
1648
                PutDoc("/FontDescriptor "+Pdf::toPdf(fontDes)+" 0 R\n");
1649
                PutDoc(">>");
1650
                writer.endObj(fontObject2);
1651
                pageData.FObjects[fontName + "S"+Pdf::toPdf(Fc)] = fontObject2;
1652
        } // for(Fc)
1653
        PdfId fontWidthsForm = writer.newObject();
1654
        writer.startObj(fontWidthsForm);
1655
        PutDoc("[ 0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 ");
1656
        for (int ww = 32; ww < 256; ++ww)
1657
        {
1658
                uint glyph = face.char2CMap(QChar(ww));
1659
                if (gl.contains(glyph))
1660
                        PutDoc(Pdf::toPdf(static_cast<int>(face.glyphWidth(glyph)* 1000))+" ");
1661
                else
1662
                        PutDoc("0 ");
1663
        }
1664
        PutDoc("]");
1665
        writer.endObj(fontWidthsForm);
1666
        PdfId fontObjectForm = writer.newObject();
1667
        PdfFont formFont;
1668
        formFont.name = Pdf::toName(fontName) + "Form";
1669
        formFont.usage = Used_in_Forms;
1670
        writer.startObj(fontObjectForm);
1671
        PutDoc("<<\n/Type /Font\n/Subtype ");
1672
        PutDoc(subtype + "\n");
1673
        //                              if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1674
        //                              {
1675
        //                                      PutDoc("/TrueType\n");
1676
        PutDoc("/Name " + formFont.name+ "\n");
1677
        pageData.FObjects[formFont.name] = fontObjectForm;
20564 jghali 1678
        UsedFontsF.insert(face.replacementName(), formFont);
20112 jghali 1679
        /*                              }
1680
         else
1681
         {
1682
         PutDoc("/Type1\n");
1683
         PutDoc("/Name /"+face.psName().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )+"\n");
1684
         pageData.FObjects[face.psName().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )] = ObjCounter;
1685
         UsedFontsF.insert(it.key(), "/"+face.psName().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" ));
1686
         } */
1687
        PutDoc("/BaseFont "+Pdf::toName(sanitizeFontName(face.psName()))+"\n");
1688
        PutDoc("/Encoding << \n");
1689
        PutDoc("/Differences [ \n");
1690
        PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
1691
        PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
1692
        PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
1693
        PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
1694
        PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
1695
        PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
1696
        PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
1697
        PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
1698
        PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
1699
        PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
1700
        PutDoc("] >>\n");
1701
        PutDoc("/FirstChar 0\n");
1702
        PutDoc("/LastChar 255\n");
1703
        PutDoc("/Widths "+Pdf::toPdf(fontWidthsForm)+" 0 R\n");
1704
        PutDoc("/FontDescriptor "+Pdf::toPdf(fontDes)+" 0 R\n");
1705
        PutDoc(">>");
1706
        writer.endObj(fontObjectForm);
20103 avox 1707
 
20112 jghali 1708
        return result;
20103 avox 1709
}
1710
 
1711
 
1712
static void dumpFont(QString name, QByteArray data)
1713
{
20112 jghali 1714
        QFile file(name);
1715
        file.open(QIODevice::WriteOnly);
1716
        QDataStream out(&file);
1717
        out.writeRawData(data.data(), data.length());
20103 avox 1718
}
1719
 
1720
static void dumpCFF(QString name, cff::CFF font)
1721
{
20112 jghali 1722
        QFile file(name);
1723
        file.open(QIODevice::WriteOnly);
1724
        QDataStream out(&file);
1725
        font.dump(out);
20103 avox 1726
}
1727
 
1728
 
1729
PdfFont PDFLibCore::PDF_WriteTtfSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1730
{
20112 jghali 1731
        QByteArray font;
1732
        face.RawData(font);
20103 avox 1733
dumpFont(face.psName() + ".ttf", font);
20112 jghali 1734
        QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
1735
        glyphs.removeAll(0);
1736
        glyphs.prepend(0);
1737
        QByteArray subset = sfnt::subsetFace(font, glyphs);
20103 avox 1738
dumpFont(face.psName()+"subs.ttf", subset);
20112 jghali 1739
        PdfId embeddedFontObj = PDF_EmbedFontObject(subset, QByteArray());
1740
        PdfId fontDes = PDF_WriteFontDescriptor(fontName, face, face.format(), embeddedFontObj);
1741
        QByteArray baseFont = Pdf::toName(sanitizeFontName(face.psName()));
1742
        ScFace::FaceEncoding fullEncoding, subEncoding;
1743
        QMap<uint,uint> glyphmap;
1744
        face.glyphNames(fullEncoding);
1745
        for (int i = 0; i < glyphs.length(); ++i)
1746
        {
1747
                glyphmap[glyphs[i]] = i;
1748
                qDebug() << glyphs[i] << " --> " << i << QChar(fullEncoding[glyphs[i]].first);
1749
        }
1750
 
1751
        PdfFont result = PDF_EncodeCidFont(fontName, face, baseFont, fontDes, fullEncoding, glyphmap);
1752
        return result;
20103 avox 1753
}
1754
 
1755
 
1756
PdfFont PDFLibCore::PDF_WriteCffSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1757
{
20112 jghali 1758
//      QByteArray sfnt; //TEST
1759
//      face.RawData(sfnt);
1760
//      QByteArray cff = sfnt::getTable(sfnt, "CFF ");
1761
//      dumpFont(fontName, cff);
1762
//      cff::CFF cfffont(cff);
1763
//      cfffont.dump();
1764
//      QByteArray subsetfont = cff::subsetFace(cff, it.value().keys());
1765
//      dumpFont(it.key() + "subs.cff", subsetfont);
1766
//      cff::CFF subset(subsetfont);
1767
//      subset.dump();
1768
//      PDF_WriteFontDescriptor(fontName, face, fformat, 0);
1769
//      // END
1770
 
20136 avox 1771
        QByteArray font, data;
1772
        face.RawData(data);
1773
        font = sfnt::getTable(data, "CFF ");
20112 jghali 1774
        dumpFont(face.psName() + ".cff", font);
1775
        QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
1776
        glyphs.removeAll(0);
1777
        glyphs.prepend(0);
1778
        QByteArray subset = cff::subsetFace(font, glyphs);
1779
        dumpFont(face.psName()+"subs.cff", subset);
1780
        PdfId embeddedFontObj = PDF_EmbedFontObject(subset, "/CIDFontType0C");
1781
        PdfId fontDes = PDF_WriteFontDescriptor(fontName, face, face.format(), embeddedFontObj);
1782
        QByteArray baseFont = Pdf::toName(sanitizeFontName(face.psName()));
1783
        ScFace::FaceEncoding fullEncoding, subEncoding;
1784
        QMap<uint,uint> glyphmap;
1785
        face.glyphNames(fullEncoding);
1786
        for (int i = 0; i < glyphs.length(); ++i)
1787
        {
1788
                glyphmap[glyphs[i]] = i;
1789
                qDebug() << glyphs[i] << " --> " << i << QChar(fullEncoding[glyphs[i]].first);
1790
        }
1791
 
1792
        PdfFont result = PDF_EncodeCidFont(fontName, face, baseFont, fontDes, fullEncoding, glyphmap);
1793
        return result;
20103 avox 1794
}
1795
 
1796
 
1797
PdfId PDFLibCore::PDF_EmbedType1AsciiFontObject(const QByteArray& fon)
1798
{
20112 jghali 1799
        QByteArray fon2;
1800
        PdfId embeddedFontObject = writer.newObject();
1801
        writer.startObj(embeddedFontObject);
1802
        int len1 = fon.indexOf("eexec")+5;
1803
        fon2 = fon.left(len1) + "\n";
1804
        int len2 = fon.indexOf("0000000000000000000000000");
1805
        if (len2 == -1)
1806
                len2 = fon.length()+1;
1807
        //                        QString tm;
1808
        //                        uint value;
1809
        //                        bool ok = true;
1810
        //                              int count = 0;
1811
        //                              for (int xx = len1; xx < len2-1; ++xx)
1812
        //                              {
1813
        //                                      tm = fon.at(xx);
1814
        //                                      if ((tm == QChar(13)) || (tm == QChar(10)))
1815
        //                                              continue;
1816
        //                                      xx++;
1817
        //                                      count++;
1818
        //                                      tm += fon.at(xx);
1819
        //                                      value = tm.toUInt(&ok, 16);
1820
        //                                      fon2 += char(value);
1821
        //                              }
1822
        QByteArray hexData = QByteArray::fromHex(fon.mid(len1, len2-len1));
1823
        fon2 += hexData;
1824
        fon2 += fon.mid(len2);
1825
        if (Options.Compress)
1826
                fon2 = CompressArray(fon2);
1827
        PutDoc("<<\n/Length "+Pdf::toPdf(fon2.length()+1)+"\n");
1828
        PutDoc("/Length1 "+Pdf::toPdf(len1+1)+"\n");
1829
        PutDoc("/Length2 "+Pdf::toPdf(hexData.length())+"\n");
1830
        if(static_cast<int>(fon.length()-len2) == -1)
1831
                PutDoc("/Length3 0\n");
1832
        else
1833
                PutDoc("/Length3 "+Pdf::toPdf(fon.length()-len2)+"\n");
1834
        if (Options.Compress)
1835
                PutDoc("/Filter /FlateDecode\n");
1836
        PutDoc(">>\nstream\n"+EncStream(fon2, embeddedFontObject)+"\nendstream");
1837
        writer.endObj(embeddedFontObject);
1838
        return embeddedFontObject;
20103 avox 1839
}
1840
 
1841
 
1842
PdfId PDFLibCore::PDF_EmbedType1BinaryFontObject(const QByteArray& bb)
1843
{
20112 jghali 1844
        PdfId embeddedFontObject = writer.newObject();
1845
        QByteArray fon;
1846
        writer.startObj(embeddedFontObject);
1847
        int posi;
1848
        for (posi = 6; posi < bb.size(); ++posi)
1849
        {
1850
                if ((bb[posi] == static_cast<char>(0x80)) && (static_cast<int>(bb[posi+1]) == 2))
1851
                        break;
1852
                fon += bb[posi];
1853
        }
1854
        int len1 = fon.length();
1855
        int ulen;
1856
        ulen = bb[posi+2] & 0xff;
1857
        ulen |= (bb[posi+3] << 8) & 0xff00;
1858
        ulen |= (bb[posi+4] << 16) & 0xff0000;
1859
        ulen |= (bb[posi+5] << 24) & 0xff000000;
1860
        if (ulen > bb.size())
1861
                ulen = bb.size()-7;
1862
        posi += 6;
1863
        for (int j = 0; j < ulen; ++j)
1864
                fon += bb[posi++];
1865
        posi += 6;
1866
        int len2 = fon.length()-len1;
1867
        for (int j = posi; j < bb.size(); ++j)
1868
        {
1869
                if ((bb[j] == static_cast<char>(0x80)) && (static_cast<int>(bb[j+1]) == 3))
1870
                        break;
1871
                if (bb[j] == '\r')
1872
                        fon += "\n";
1873
                else
1874
                        fon += bb[j];
1875
        }
1876
        int len3 = fon.length()-len2-len1;
1877
        if (Options.Compress)
1878
                fon = CompressArray(fon);
1879
        PutDoc("<<\n/Length "+Pdf::toPdf(fon.length()+1)+"\n");
1880
        PutDoc("/Length1 "+Pdf::toPdf(len1)+"\n");
1881
        PutDoc("/Length2 "+Pdf::toPdf(len2)+"\n");
1882
        PutDoc("/Length3 "+Pdf::toPdf(len3)+"\n");
1883
        if (Options.Compress)
1884
                PutDoc("/Filter /FlateDecode\n");
1885
        PutDoc(">>\nstream\n"+EncStream(fon,embeddedFontObject)+"\nendstream");
1886
        writer.endObj(embeddedFontObject);
1887
        return embeddedFontObject;
20103 avox 1888
}
1889
 
1890
 
1891
PdfId PDFLibCore::PDF_EmbedFontObject(const QString& name, ScFace& face)
1892
{
20112 jghali 1893
        PdfId embeddedFontObject = 0;
1894
        if (Options.EmbedList.contains(name))
1895
        {
1896
                ScFace::FontFormat fformat = face.format();
1897
                QByteArray bb;
1898
                face.RawData(bb);
20350 jghali 1899
                if (fformat == ScFace::PFB)
20112 jghali 1900
                {
1901
                        embeddedFontObject = PDF_EmbedType1BinaryFontObject(bb);
1902
                }
1903
                if (fformat == ScFace::PFA)
1904
                {
1905
                        embeddedFontObject = PDF_EmbedType1AsciiFontObject(bb);
1906
                }
1907
                if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1908
                {
1909
                        QByteArray subtype;
1910
                        if (face.type() == ScFace::OTF)
1911
                        {
1912
                                subtype = "/CIDFontType0C";
20350 jghali 1913
                                QByteArray cff_bb = sfnt::getTable(bb, "CFF ");
1914
                                dumpCFF(face.psName() + ".cff", cff::CFF(cff_bb));
1915
                                bb = cff::extractFace(cff_bb, 0);
20112 jghali 1916
                                dumpCFF(face.psName() + "full.cff", cff::CFF(bb));
1917
                        }
1918
                        embeddedFontObject = PDF_EmbedFontObject(bb, subtype);
1919
                }
1920
        }
1921
        return embeddedFontObject;
20103 avox 1922
}
1923
 
1924
 
1925
void PDFLibCore::PDF_Begin_WriteUsedFonts(SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& ReallyUsed)
1926
{
20112 jghali 1927
        qDebug() << "embed list:" << QStringList(Options.EmbedList).join(", ");
1928
        qDebug() << "subset list:" << QStringList(Options.SubsetList).join(", ");
1929
        qDebug() << "outline list:" << QStringList(Options.OutlineList).join(", ");
1930
        QMap<QString,QMap<uint, FPointArray> >::ConstIterator it;
1931
        int a = 0;
1932
        for (it = ReallyUsed.cbegin(); it != ReallyUsed.cend(); ++it)
1933
        {
1934
                ScFace& face(AllFonts[it.key()]);
1935
                ScFace::FontFormat fformat = face.format();
1936
                PdfFont pdfFont;
1937
                QByteArray fontName = QByteArray("Fo") + Pdf::toPdf(a);
1938
 
20274 jghali 1939
                QMap<uint, FPointArray> usedGlyphs = it.value();
1940
 
1941
                // Check for control glyphs
1942
                QList<uint> glyphIDs = usedGlyphs.keys();
1943
                for (int i = 0; i < glyphIDs.count(); ++i)
1944
                {
1945
                        uint glyph = glyphIDs.at(i);
1946
                        if (glyph < ScFace::CONTROL_GLYPHS)
1947
                                continue;
1948
                        FPointArray glyphPath = usedGlyphs[glyph];
1949
 
1950
                        uint realGlyph = 0;
1951
                        if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode()) ||
1952
                                glyph == (ScFace::CONTROL_GLYPHS + 32))
1953
                        {
1954
                                realGlyph = face.char2CMap(QChar(' '));
1955
                        }
1956
                        else if (glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode()))
1957
                        {
1958
                                realGlyph = face.char2CMap(QChar('-'));
1959
                        }
1960
 
1961
                        usedGlyphs.remove(glyph);
1962
                        if (realGlyph <= 0 || realGlyph >= ScFace::CONTROL_GLYPHS)
1963
                                continue;
1964
                        usedGlyphs.insert(glyph, glyphPath);
1965
                }
1966
 
1967
                if (usedGlyphs.count() <= 0)
1968
                        continue;
1969
 
20112 jghali 1970
                qDebug() << "pdf font" << it.key();
1971
                if (Options.OutlineList.contains(it.key()))
1972
                {
20274 jghali 1973
                        pdfFont = PDF_WriteGlyphsAsXForms(fontName, face, usedGlyphs);
20112 jghali 1974
                }
1975
                else
1976
                {
1977
                        if (Options.SubsetList.contains(it.key()))
1978
                        {
1979
                                if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1980
                                {
1981
                                        if (face.type() == ScFace::TTF)
1982
                                        {
20274 jghali 1983
                                                pdfFont = PDF_WriteTtfSubsetFont(fontName, face, usedGlyphs);
20112 jghali 1984
                                        }
1985
                                        else
1986
                                        {
20274 jghali 1987
                                                pdfFont = PDF_WriteCffSubsetFont(fontName, face, usedGlyphs);
20112 jghali 1988
                                        }
1989
                                }
1990
                                else
1991
                                {
20274 jghali 1992
                                        pdfFont = PDF_WriteType3Font(fontName, face, usedGlyphs);
20112 jghali 1993
                                }
1994
                        }
1995
                        else
1996
                        {
1997
                                PdfId embeddedFontObject = PDF_EmbedFontObject(it.key(), face);
1998
 
1999
                                PdfId fontDescriptor = PDF_WriteFontDescriptor(fontName, face, fformat, embeddedFontObject);
2000
 
2001
                                ScFace::FaceEncoding gl;
2002
                                face.glyphNames(gl);
2003
 
2004
                                QByteArray baseFont = Pdf::toName(sanitizeFontName(face.psName()));
2005
 
2006
                                if ((face.isSymbolic() || !face.hasNames() || Options.Version == PDFOptions::PDFVersion_X4 || face.type() == ScFace::OTF) &&
2007
                                        (fformat == ScFace::SFNT || fformat == ScFace::TTCF))
2008
                                {
2009
                                        pdfFont = PDF_EncodeCidFont(fontName, face, baseFont, fontDescriptor, gl, QMap<uint,uint>());
2010
                                }
2011
                                else
2012
                                {
2013
                                        QByteArray subtype = (fformat == ScFace::SFNT || fformat == ScFace::TTCF) ? "/TrueType" : "/Type1";
2014
                                        pdfFont = PDF_EncodeSimpleFont(fontName, face, baseFont, subtype, embeddedFontObject != 0, fontDescriptor, gl);
2015
                                }
2016
                        }
2017
                        pdfFont.usage = Used_in_Content;
2018
                }
20121 jghali 2019
                a++;
2020
                QString meth;
2021
                switch (pdfFont.method)
2022
                {
2023
                        case Use_System:
2024
                                meth = "Systemfont (no embedding)"; break;
2025
                        case Use_Embedded:
2026
                                meth = "Embed"; break;
2027
                        case Use_Subset:
2028
                                meth = "Subset"; break;
2029
                        case Use_Type3:
2030
                                meth = "Subset as Type3 font"; break;
2031
                        case Use_XForm:
2032
                                meth = "Outline (PDF XForm)"; break;
2033
                        default:
2034
                                meth = "?"; break;
2035
                }
2036
                qDebug() << pdfFont.name << "uses method" << meth << "and encoding" << pdfFont.encoding;
2037
                UsedFontsP.insert(it.key(), pdfFont);
20112 jghali 2038
        }
20103 avox 2039
}
2040
 
2041
void PDFLibCore::PDF_Begin_Colors()
2042
{
4264 craig 2043
        if (Options.UseLPI)
3133 fschmid 2044
        {
20103 avox 2045
                uint halftones = writer.newObject();
2046
                writer.startObj(halftones);
3133 fschmid 2047
                PutDoc("<<\n/Type /Halftone\n/HalftoneType 5\n");
4264 craig 2048
                QMap<QString,LPIData>::const_iterator itlp;
2049
                for (itlp = Options.LPISettings.constBegin(); itlp != Options.LPISettings.constEnd(); ++itlp)
3133 fschmid 2050
                {
20112 jghali 2051
                        PutDoc(Pdf::toName(itlp.key()) + "\n<<\n/Type /Halftone\n/HalftoneType 1\n/Frequency ");
20103 avox 2052
                        PutDoc(Pdf::toPdf(itlp.value().Frequency)+"\n/Angle "+Pdf::toPdf(itlp.value().Angle)+"\n/SpotFunction ");
2053
                        QByteArray func ("");
10469 cbradney 2054
                        switch (itlp.value().SpotFunc)
3133 fschmid 2055
                        {
2056
                                case 0:
2057
                                        func = "/SimpleDot";
2058
                                        break;
2059
                                case 1:
2060
                                        func = "/Line";
2061
                                        break;
2062
                                case 2:
2063
                                        func = "/Round";
2064
                                        break;
2065
                                case 3:
2066
                                        func = "/Ellipse";
2067
                                        break;
2068
                                default:
2069
                                        func = "/SimpleDot";
2070
                                        break;
2071
                        }
20103 avox 2072
                        PutDoc(func + "\n>>\n");
3133 fschmid 2073
                }
2074
                PutDoc("/Default\n<<\n/Type /Halftone\n/HalftoneType 1\n/Frequency 50\n/Angle 45\n/SpotFunction /Round\n>>\n");
20112 jghali 2075
                PutDoc(">>");
2076
                writer.endObj(halftones);
20103 avox 2077
                HTName = ResNam+Pdf::toPdf(ResCount);
2078
                Transpar[HTName] = writeGState("/HT "+Pdf::toPdf(halftones)+" 0 R\n");
3133 fschmid 2079
                ResCount++;
2080
        }
19115 avox 2081
        if ((doc.HasCMS) && (Options.UseProfiles) && (Options.Version != PDFOptions::PDFVersion_X1a))
3133 fschmid 2082
        {
20103 avox 2083
                PdfId iccProfileObject = writer.newObject();
2084
                writer.startObj(iccProfileObject);
7144 jghali 2085
                QByteArray dataP;
20103 avox 2086
                PdfICCD dataD;
7144 jghali 2087
                loadRawBytes(ScCore->InputProfiles[Options.SolidProf], dataP);
3133 fschmid 2088
                PutDoc("<<\n");
11317 jghali 2089
                if (Options.Compress)
3133 fschmid 2090
                {
11317 jghali 2091
                        QByteArray compData = CompressArray(dataP);
2092
                        if (compData.size() > 0)
2093
                        {
2094
                                PutDoc("/Filter /FlateDecode\n");
2095
                                dataP = compData;
2096
                        }
3133 fschmid 2097
                }
20103 avox 2098
                PutDoc("/Length "+Pdf::toPdf(dataP.size()+1)+"\n");
2099
                PutDoc("/N "+Pdf::toPdf(Options.SComp)+"\n");
7144 jghali 2100
                PutDoc(">>\nstream\n");
12080 avox 2101
                EncodeArrayToStream(dataP, iccProfileObject);
20112 jghali 2102
                PutDoc("\nendstream");
2103
                writer.endObj(iccProfileObject);
20103 avox 2104
                PdfId iccColorspace = writer.newObject();
2105
                writer.startObj(iccColorspace);
2106
                dataD.ResName = ResNam+Pdf::toPdf(ResCount);
2107
                dataD.ICCArray = "[ /ICCBased "+Pdf::toPdf(iccProfileObject)+" 0 R ]";
12080 avox 2108
                dataD.ResNum = iccColorspace;
12732 fschmid 2109
                dataD.components = Options.SComp;
4264 craig 2110
                ICCProfiles[Options.SolidProf] = dataD;
20103 avox 2111
                PutDoc("[ /ICCBased "+Pdf::toPdf(iccProfileObject)+" 0 R ]");
2112
                writer.endObj(iccColorspace);
3133 fschmid 2113
                ResCount++;
2114
        }
4264 craig 2115
        if (((Options.isGrayscale == false) && (Options.UseRGB == false)) && (Options.UseSpotColors))
3133 fschmid 2116
        {
4264 craig 2117
                doc.getUsedColors(colorsToUse);
3133 fschmid 2118
                ColorList::Iterator itf;
2119
                for (itf = colorsToUse.begin(); itf != colorsToUse.end(); ++itf)
2120
                {
2121
                        if ((colorsToUse[itf.key()].isSpotColor()) || (colorsToUse[itf.key()].isRegistrationColor()))
2122
                        {
9619 jghali 2123
                                CMYKColor cmykValues;
3133 fschmid 2124
                                int cc, cm, cy, ck;
20103 avox 2125
                                PdfSpotC spotD;
9619 jghali 2126
                                ScColorEngine::getCMYKValues(colorsToUse[itf.key()], &doc, cmykValues);
2127
                                cmykValues.getValues(cc, cm, cy, ck);
20103 avox 2128
                                QByteArray colorDesc = "{\ndup "+FToStr(static_cast<double>(cc) / 255)+"\nmul exch dup ";
3133 fschmid 2129
                                colorDesc += FToStr(static_cast<double>(cm) / 255)+"\nmul exch dup ";
2130
                                colorDesc += FToStr(static_cast<double>(cy) / 255)+"\nmul exch ";
2131
                                colorDesc += FToStr(static_cast<double>(ck) / 255)+" mul }";
20103 avox 2132
                                PdfId separationFunction = writer.newObject();
2133
                                writer.startObj(separationFunction);
3133 fschmid 2134
                                PutDoc("<<\n/FunctionType 4\n");
2135
                                PutDoc("/Domain [0.0 1.0]\n");
2136
                                PutDoc