Subversion Repositories Scribus

Rev

Rev 20091 | Rev 20104 | 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;
20103 avox 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
                }
4028 cbradney 281
                ret = true;//Even when aborting we return true. Dont want that "couldnt write msg"
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;
20103 avox 420
    else
421
        return writer.encryptBytes(in, ObjNum);
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)
427
//        us[a] = (tmp.at(a));
428
//    QByteArray step1 = writer.ComputeRC4Key(ObjNum);
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) + ")";
445
        return Pdf::toLiteralString(in);
19114 avox 446
        }
20103 avox 447
 
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]);
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
        {
20103 avox 469
        QByteArray us = Pdf::toUTF16(in);
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;
476
    QByteArray us = Pdf::toUTF16(in);
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
                }
20103 avox 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
 
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;
20103 avox 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
                }
20103 avox 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
{
20103 avox 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
{
20103 avox 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();
20103 avox 623
 
624
    writer.writeHeader(Options.Version);
625
 
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
 
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;
656
}
657
 
658
void PDFLibCore::PDF_Begin_Catalog()
659
{
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))
20103 avox 670
    {
671
        writer.OCPropertiesObj = writer.newObject();
672
                PutDoc("/OCProperties " + Pdf::toObjRef(writer.OCPropertiesObj) + "\n");
673
    }
674
    if (PDF_IsPDFX())
675
    {
676
        writer.OutputIntentObj = writer.newObject();
677
        PutDoc("/OutputIntents [ " +  Pdf::toObjRef(writer.OutputIntentObj) + " ]\n");
678
    }
679
    if ((Options.Version == PDFOptions::PDFVersion_X4))
19114 avox 680
        {
20103 avox 681
        writer.MetaDataObj = writer.newObject();
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
        {
20103 avox 710
        PutDoc("/OpenAction << /S /JavaScript /JS (this."+Pdf::toPdfDocEncoding(Options.openAction)+"\\(\\)) >>\n");
19114 avox 711
        }
20103 avox 712
    QString tmp;
19114 avox 713
        QDateTime dt = QDateTime::currentDateTime().toUTC();
20103 avox 714
    Datum = Pdf::toDateString(dt);
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");
20103 avox 770
    PutDoc(" >>\n>>");
771
    writer.endObj(writer.CatalogObj);
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";
20103 avox 783
    writer.setFileId(Pdf::toPdfDocEncoding(IDg));
19114 avox 784
        if (Options.Encrypt)
785
        {
20103 avox 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);
789
    PutDoc("<<\n/Creator " + EncString(QByteArray("Scribus ") + VERSION, writer.InfoObj) + "\n");
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");
20103 avox 810
    PutDoc("/Trapped /False\n>>");
811
    writer.endObj(writer.InfoObj);
812
 
813
    // Encrypt
814
 
815
//    for (int t = 0; t < 6; ++t)
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");
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
        }
20103 avox 1066
    return ReallyUsed;
1067
}
17628 jghali 1068
 
20103 avox 1069
static QByteArray sanitizeFontName(QString fn)
1070
{
1071
    return Pdf::toPdfDocEncoding(fn.replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" ));
1072
}
17628 jghali 1073
 
20103 avox 1074
static QList<Pdf::Resource> asColorSpace(QList<PdfICCD> iccCSlist)
1075
{
1076
    QList<Pdf::Resource> result;
1077
    foreach (Pdf::Resource r, iccCSlist)
1078
    {
1079
        result.append(r);
1080
    }
1081
    return result;
1082
}
1083
 
1084
static QList<Pdf::Resource> asColorSpace(QList<PdfSpotC> spotMapValues)
1085
{
1086
    QList<Pdf::Resource> result;
1087
    foreach (Pdf::Resource r, spotMapValues)
1088
    {
1089
        result.append(r);
1090
    }
1091
    return result;
1092
}
1093
 
1094
 
1095
void PDFLibCore::PDF_WriteStandardFonts()
1096
{
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
    }
1128
}
1129
 
1130
 
1131
PdfFont PDFLibCore::PDF_WriteType3Font(const QByteArray& name, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1132
{
1133
    PdfFont result;
1134
    result.name = Pdf::toName(name);
1135
    result.method = Use_Type3;
1136
    result.encoding = Encode_256;
1137
 
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
        {
1189
            fon = "h";
1190
            np = FPoint(0, 0);
1191
            np1 = FPoint(0, 0);
1192
        }
1193
        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");
1194
        minx = qMin(minx, np.x());
1195
        miny = qMin(miny, np.y());
1196
        maxx = qMax(maxx, np1.x());
1197
        maxy = qMax(maxy, np1.y());
1198
        glyphWidths.append(qRound(np1.x()));
1199
        PdfId charProcObject = writer.newObject();
1200
        charProcs.append(Pdf::toName(gl[ig.key()].second)+" "+Pdf::toPdf(charProcObject)+" 0 R\n");
1201
        encoding += Pdf::toName(gl[ig.key()].second)+" ";
1202
        glyphMapping.insert(ig.key(), glyphCount + SubFonts * 256);
1203
        writer.startObj(charProcObject);
1204
        if (Options.Compress)
1205
            fon = CompressArray(fon);
1206
        PutDoc("<< /Length "+Pdf::toPdf(fon.length()+1));
1207
        if (Options.Compress)
1208
            PutDoc("\n/Filter /FlateDecode");
1209
        PutDoc("\n>>\nstream\n"+EncStream(fon, charProcObject)+"\nendstream");
1210
        writer.endObj(charProcObject);
1211
        glyphCount++;
1212
        int glyphsLeft = RealGlyphs.count() - SubFonts * 256;
1213
        if ((glyphCount > 255) || (glyphCount == glyphsLeft))
1214
        {
1215
            PdfId fontWidths = writer.newObject();
1216
            writer.startObj(fontWidths);
1217
            PutDoc("[ ");
1218
            for (int ww = 0; ww < glyphWidths.count(); ++ww)
1219
            {
1220
                PutDoc(Pdf::toPdf(glyphWidths[ww])+" ");
1221
            }
1222
            PutDoc("]");
1223
            writer.endObj(fontWidths);
1224
            PdfId fontCharProcs = writer.newObject();
1225
            writer.startObj(fontCharProcs);
1226
            PutDoc("<<\n");
1227
            for (int ww = 0; ww < charProcs.count(); ++ww)
1228
            {
1229
                PutDoc(charProcs[ww]);
1230
            }
1231
            PutDoc(">>");
1232
            writer.endObj(fontCharProcs);
1233
            PdfId fontEncoding = writer.newObject();
1234
            writer.startObj(fontEncoding);
1235
            PutDoc(encoding);
1236
            PutDoc("]\n");
1237
            PutDoc(">>");
1238
            writer.endObj(fontEncoding);
1239
            PdfId font3Object = writer.newObject();
1240
            writer.startObj(font3Object);
1241
            PutDoc("<<\n/Type /Font\n/Subtype /Type3\n");
1242
            PutDoc("/Name /"+name+"S"+Pdf::toPdf(SubFonts)+"\n");
1243
            PutDoc("/FirstChar 0\n");
1244
            PutDoc("/LastChar "+Pdf::toPdf(glyphCount-1)+"\n");
1245
            PutDoc("/Widths "+Pdf::toPdf(fontWidths)+" 0 R\n");
1246
            PutDoc("/CharProcs "+Pdf::toPdf(fontCharProcs)+" 0 R\n");
1247
            PutDoc("/FontBBox ["+Pdf::toPdf(qRound(minx))+" "+Pdf::toPdf(qRound(miny))+" "+Pdf::toPdf(qRound(maxx))+ " "+Pdf::toPdf(qRound(maxy))+"]\n");
1248
            PutDoc("/FontMatrix [0.001 0 0 0.001 0 0]\n");
1249
            PutDoc("/Encoding "+Pdf::toPdf(fontEncoding)+" 0 R\n");
1250
            PutDoc(">>");
1251
            writer.endObj(font3Object);
1252
            pageData.FObjects[name+"S"+Pdf::toPdf(SubFonts)] = font3Object;
1253
            charProcs.clear();
1254
            glyphWidths.clear();
1255
            //                                          glyphMapping.clear();
1256
            glyphCount = 0;
1257
            ++SubFonts;
1258
            minx =  std::numeric_limits<double>::max();
1259
            miny =  std::numeric_limits<double>::max();
1260
            maxx = -std::numeric_limits<double>::max();
1261
            maxy = -std::numeric_limits<double>::max();
1262
            encoding = "<< /Type /Encoding\n/Differences [ 0\n";
1263
        }
1264
    }
1265
    result.glyphmap = glyphMapping;
1266
    return result;
1267
}
1268
 
1269
 
1270
PdfFont PDFLibCore::PDF_WriteGlyphsAsXForms(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1271
{
1272
    PdfFont result;
1273
    result.name = Pdf::toName(fontName);
1274
    result.method = Use_XForm;
1275
    result.encoding = Encode_224;
1276
 
1277
    QByteArray fon;
1278
    QMap<uint,FPointArray>::ConstIterator ig;
1279
    for (ig = RealGlyphs.cbegin(); ig != RealGlyphs.cend(); ++ig)
1280
    {
1281
        FPoint np, np1, np2;
1282
        bool nPath = true;
1283
        fon.resize(0);
1284
        if (ig.value().size() > 3)
1285
        {
1286
            FPointArray gly = ig.value();
1287
            QTransform mat;
1288
            mat.scale(0.1, 0.1);
1289
            gly.map(mat);
1290
            for (int poi = 0; poi < gly.size()-3; poi += 4)
1291
            {
1292
                if (gly.isMarker(poi))
1293
                {
1294
                    fon += "h\n";
1295
                    nPath = true;
1296
                    continue;
1297
                }
1298
                if (nPath)
1299
                {
1300
                    np = gly.point(poi);
1301
                    fon += FToStr(np.x())+" "+FToStr(-np.y())+" m\n";
1302
                    nPath = false;
1303
                }
1304
                np = gly.point(poi+1);
1305
                np1 = gly.point(poi+3);
1306
                np2 = gly.point(poi+2);
1307
                fon += FToStr(np.x()) + " " + FToStr(-np.y()) + " " +
1308
                FToStr(np1.x()) + " " + FToStr(-np1.y()) + " " +
1309
                FToStr(np2.x()) + " " + FToStr(-np2.y()) + " c\n";
1310
            }
1311
            fon += "h f*\n";
1312
            np = getMinClipF(&gly);
1313
            np1 = getMaxClipF(&gly);
1314
        }
1315
        else
1316
        {
1317
            fon = "h";
1318
            np = FPoint(0, 0);
1319
            np1 = FPoint(0, 0);
1320
        }
1321
        PdfId fontGlyphXForm = writer.newObject();
1322
        writer.startObj(fontGlyphXForm);
1323
        PutDoc("<<\n/Type /XObject\n/Subtype /Form\n/FormType 1\n");
1324
        PutDoc("/BBox [ "+FToStr(np.x())+" "+FToStr(-np.y())+" "+FToStr(np1.x())+ " "+FToStr(-np1.y())+" ]\n");
1325
        PutDoc("/Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n");
1326
        PutDoc(">>\n");
1327
        if (Options.Compress)
1328
            fon = CompressArray(fon);
1329
        PutDoc("/Length "+Pdf::toPdf(fon.length()+1));
1330
        if (Options.Compress)
1331
            PutDoc("\n/Filter /FlateDecode");
1332
        PutDoc(" >>\nstream\n"+EncStream(fon, fontGlyphXForm)+"\nendstream");
1333
        writer.endObj(fontGlyphXForm);
1334
        pageData.XObjects[fontName + Pdf::toPdf(ig.key())] = fontGlyphXForm;
1335
    }
1336
    return result;
1337
}
1338
 
1339
PdfId PDFLibCore::PDF_EmbedFontObject(const QByteArray& font, const QByteArray& subtype)
1340
 
1341
{
1342
    PdfId embeddedFontObject = writer.newObject();
1343
    writer.startObj(embeddedFontObject);
1344
    int len = font.length();
1345
    QByteArray ttf = (Options.Compress? CompressArray(font) : font);
1346
    //qDebug() << QString("sfnt data: size=%1 compressed=%2").arg(len).arg(bb.length());
1347
    PutDoc("<<\n/Length " + Pdf::toPdf(ttf.length() + 1) + "\n");
1348
    PutDoc("/Length1 " + Pdf::toPdf(len) + "\n");
1349
    if (subtype.size() > 0)
1350
        PutDoc("/Subtype " + subtype);
1351
    if (Options.Compress)
1352
        PutDoc("/Filter /FlateDecode\n");
1353
    PutDoc(">>\nstream\n");
1354
    EncodeArrayToStream(ttf, embeddedFontObject);
1355
    PutDoc("\nendstream");
1356
    writer.endObj(embeddedFontObject);
1357
    return embeddedFontObject;
1358
}
1359
 
1360
PdfId PDFLibCore::PDF_WriteFontDescriptor(const QByteArray& fontName, ScFace& face, ScFace::FontFormat fformat, PdfId embeddedFontObject)
1361
{
1362
    PdfId fontDescriptor = writer.newObject();
1363
    writer.startObj(fontDescriptor);
1364
    // TODO: think about QByteArray ScFace::getFontDescriptor() -- AV
1365
    PutDoc("<<\n/Type /FontDescriptor\n");
1366
    PutDoc("/FontName "  + Pdf::toName(fontName) + "\n");
1367
    PutDoc("/FontBBox [ " + Pdf::toAscii(face.pdfFontBBoxAsString()) + " ]\n");
1368
    PutDoc("/Flags ");
1369
    //FIXME: isItalic() should be queried from ScFace, not from Qt -- AV
1370
    //QFontInfo fo = QFontInfo(it.data());
1371
    int pfl = 0;
1372
    if (face.isFixedPitch())
1373
        pfl = pfl ^ 1;
1374
    //if (fo.italic())
1375
    if (face.italicAngleAsString() != "0")
1376
        pfl = pfl ^ 64;
1377
    //                  pfl = pfl ^ 4;
1378
    pfl = pfl ^ 32;
1379
    PutDoc(Pdf::toPdf(pfl)+"\n");
1380
    PutDoc("/Ascent "      + Pdf::toAscii(face.pdfAscentAsString())+"\n");
1381
    PutDoc("/Descent "     + Pdf::toAscii(face.pdfDescentAsString())+"\n");
1382
    PutDoc("/CapHeight "   + Pdf::toAscii(face.pdfCapHeightAsString())+"\n");
1383
    PutDoc("/ItalicAngle " + Pdf::toAscii(face.italicAngleAsString())+"\n");
1384
    PutDoc("/StemV 1\n");
1385
    if (embeddedFontObject != 0)
1386
    {
1387
        if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1388
        {
1389
            if (face.type() == ScFace::OTF)
1390
            {
1391
                PutDoc("/FontFile3 "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1392
            }
1393
            else
1394
            {
1395
                PutDoc("/FontFile2 "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1396
            }
1397
        }
1398
        else if (fformat == ScFace::PFB)
1399
            PutDoc("/FontFile "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1400
        else if (fformat == ScFace::PFA)
1401
            PutDoc("/FontFile "+Pdf::toPdf(embeddedFontObject)+" 0 R\n");
1402
    }
1403
    PutDoc(">>");
1404
    writer.endObj(fontDescriptor);
1405
    return fontDescriptor;
1406
}
1407
 
1408
PdfFont PDFLibCore::PDF_EncodeCidFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, PdfId fontDes, const ScFace::FaceEncoding& gl, const QMap<uint,uint> glyphmap  )
1409
{
1410
    PdfFont result;
1411
    result.name = Pdf::toName(fontName);
1412
    result.method = glyphmap.isEmpty()? Use_Embedded : Use_Subset;
1413
    result.encoding = glyphmap.isEmpty()? Encode_IdentityH : Encode_Subset;
1414
    result.glyphmap = glyphmap;
1415
 
1416
    PdfId fontWidths2 = writer.newObject();
1417
    writer.startObj(fontWidths2);
1418
    QList<QByteArray> toUnicodeMaps;
1419
    QList<int> toUnicodeMapsCount;
1420
    QByteArray toUnicodeMap = "";
1421
    int toUnicodeMapCounter = 0;
1422
 
1423
    PutDoc("[ ");
1424
    QList<uint> keys = gl.uniqueKeys();
1425
    QList<uint>::iterator git;
1426
    bool seenNotDef = false;
1427
    for (git = keys.begin(); git != keys.end(); ++git)
1428
    {
1429
        uint gid = result.encoding == Encode_Subset? glyphmap[*git] : *git;
1430
        if (gid > 0 || !seenNotDef)
1431
        {
1432
            seenNotDef |= (gid == 0);
1433
            PutDoc(Pdf::toPdf(gid)+" ["+Pdf::toPdf(static_cast<int>(face.glyphWidth(*git)* 1000))+"] " );
1434
            QString tmp, tmp2;
1435
            tmp.sprintf("%04X", gid);
1436
            tmp2.sprintf("%04X", gl.value(*git).first);
1437
            toUnicodeMap += "<" + Pdf::toAscii(tmp)+ "> <" + Pdf::toAscii(tmp2) + ">\n";
1438
            toUnicodeMapCounter++;
1439
            if (toUnicodeMapCounter == 100)
1440
            {
1441
                toUnicodeMaps.append(toUnicodeMap);
1442
                toUnicodeMapsCount.append(toUnicodeMapCounter);
1443
                toUnicodeMap = "";
1444
                toUnicodeMapCounter = 0;
1445
            }
1446
        }
1447
    }
1448
    PutDoc("]");
1449
    writer.endObj(fontWidths2);
1450
    if (toUnicodeMapCounter != 0)
1451
    {
1452
        toUnicodeMaps.append(toUnicodeMap);
1453
        toUnicodeMapsCount.append(toUnicodeMapCounter);
1454
    }
1455
    QByteArray toUnicodeMapStream = "";
1456
    toUnicodeMapStream += "/CIDInit /ProcSet findresource begin\n";
1457
    toUnicodeMapStream += "12 dict begin\n";
1458
    toUnicodeMapStream += "begincmap\n";
1459
    toUnicodeMapStream += "/CIDSystemInfo <<\n";
1460
    toUnicodeMapStream += "/Registry (Adobe)\n";
1461
    toUnicodeMapStream += "/Ordering (UCS)\n";
1462
    toUnicodeMapStream += "/Supplement 0\n";
1463
    toUnicodeMapStream += ">> def\n";
1464
    toUnicodeMapStream += "/CMapName /Adobe-Identity-UCS def\n";
1465
    toUnicodeMapStream += "/CMapType 2 def\n";
1466
    toUnicodeMapStream += "1 begincodespacerange\n";
1467
    toUnicodeMapStream += "<0000> <FFFF>\n";
1468
    toUnicodeMapStream += "endcodespacerange\n";
1469
    for (int uniC = 0; uniC < toUnicodeMaps.count(); uniC++)
1470
    {
1471
        toUnicodeMapStream += Pdf::toPdf(toUnicodeMapsCount[uniC]);
1472
        toUnicodeMapStream += " beginbfchar\n";
1473
        toUnicodeMapStream += toUnicodeMaps[uniC];
1474
        toUnicodeMapStream += "endbfchar\n";
1475
    }
1476
    toUnicodeMapStream += "endcmap\n";
1477
    toUnicodeMapStream += "CMapName currentdict /CMap defineresource pop\n";
1478
    toUnicodeMapStream += "end\n";
1479
    toUnicodeMapStream += "end\n";
1480
    PdfId fontToUnicode2 = WritePDFStream(toUnicodeMapStream);
1481
    PdfId fontObject2 = writer.newObject();
1482
    writer.startObj(fontObject2);
1483
    PutDoc("<<\n/Type /Font\n/Subtype /Type0\n");
1484
    PutDoc("/Name " + Pdf::toName(fontName) + "\n");
1485
    PutDoc("/BaseFont "+ baseFont +"\n");
1486
    PutDoc("/Encoding /Identity-H\n");
1487
    PutDoc("/ToUnicode "+Pdf::toPdf(fontToUnicode2)+" 0 R\n");
1488
    PutDoc("/DescendantFonts [");
1489
    PutDoc("<</Type /Font");
1490
    if (face.type() == ScFace::OTF)
1491
        PutDoc("/Subtype /CIDFontType0");
1492
    else
1493
        PutDoc("/Subtype /CIDFontType2");
1494
    PutDoc("/BaseFont " + baseFont);
1495
    PutDoc("/FontDescriptor " + Pdf::toPdf(fontDes)+ " 0 R");
1496
    PutDoc("/CIDSystemInfo <</Ordering(Identity)/Registry(Adobe)/Supplement 0>>");
1497
    PutDoc("/DW 1000");
1498
    PutDoc("/W "+Pdf::toPdf(fontWidths2)+" 0 R");
1499
    PutDoc("/CIDToGIDMap /Identity");
1500
    PutDoc(">>"); // close CIDFont dictionary
1501
    PutDoc("]\n"); // close DescendantFonts array
1502
    PutDoc(">>");
1503
    writer.endObj(fontObject2);
1504
    pageData.FObjects[fontName] = fontObject2;
1505
    return result;
1506
}
1507
 
1508
 
1509
PdfFont PDFLibCore::PDF_EncodeSimpleFont(const QByteArray& fontName, ScFace& face, const QByteArray& baseFont, const QByteArray& subtype, bool isEmbedded, PdfId fontDes, const ScFace::FaceEncoding& gl)
1510
{
1511
    PdfFont result;
1512
    result.name = Pdf::toName(fontName);
1513
    result.method = isEmbedded? Use_Embedded : Use_System;
1514
    result.encoding = Encode_224;
1515
 
1516
    int nglyphs = 0;
1517
    ScFace::FaceEncoding::ConstIterator gli;
1518
    for (gli = gl.cbegin(); gli != gl.cend(); ++gli)
1519
    {
1520
        if (gli.key() > static_cast<uint>(nglyphs))
1521
            nglyphs = gli.key();
1522
    }
1523
    ++nglyphs;
1524
    //                  qDebug() << QString("pdflib: nglyphs %1 max %2").arg(nglyphs).arg(face.maxGlyph());
1525
 
1526
    uint Fcc = nglyphs / 224;
1527
    if ((nglyphs % 224) != 0)
1528
        Fcc += 1;
1529
    for (uint Fc = 0; Fc < Fcc; ++Fc)
1530
    {
1531
        PdfId fontWidths2 = writer.newObject();
1532
        writer.startObj(fontWidths2);
1533
        int chCount = 32;
1534
        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 ");
1535
        for (int ww = 32; ww < 256; ++ww)
1536
        {
1537
            uint glyph = 224 * Fc + ww - 32;
1538
            if (gl.contains(glyph))
1539
                PutDoc(Pdf::toPdf(static_cast<int>(face.glyphWidth(glyph)* 1000))+" ");
1540
            else
1541
                PutDoc("0 ");
1542
            chCount++;
1543
            if (signed(glyph) == nglyphs-1)
1544
                break;
1545
        }
1546
        PutDoc("]");
1547
        writer.endObj(fontWidths2);
1548
        PdfId fontEncoding2 = writer.newObject();
1549
        writer.startObj(fontEncoding2);
1550
        QStringList toUnicodeMaps;
1551
        QList<int> toUnicodeMapsCount;
1552
        QString toUnicodeMap = "";
1553
        int toUnicodeMapCounter = 0;
1554
        PutDoc("<< /Type /Encoding\n");
1555
        PutDoc("/Differences [ \n");
1556
        int crc = 0;
1557
        bool startOfSeq = true;
1558
        for (int ww2 = 32; ww2 < 256; ++ww2)
1559
        {
1560
            uint glyph = 224 * Fc + ww2 - 32;
1561
            ScFace::FaceEncoding::ConstIterator glIt = gl.find(glyph);
1562
            if (glIt != gl.cend() && !glIt.value().second.isEmpty())
1563
            {
1564
                if (startOfSeq)
1565
                {
1566
                    PutDoc(Pdf::toPdf(ww2)+" ");
1567
                    startOfSeq = false;
1568
                }
1569
                PutDoc(Pdf::toName(glIt.value().second)+" ");
1570
                QString tmp, tmp2;
1571
                tmp.sprintf("%02X", ww2);
1572
                tmp2.sprintf("%04X", glIt.value().first);
1573
                toUnicodeMap += "<" + Pdf::toAscii(tmp) + "> <" + Pdf::toAscii(tmp2) + ">\n";
1574
                //QString("<%1> <%2>\n").arg(tmp).arg((tmp2));
1575
                toUnicodeMapCounter++;
1576
                if (toUnicodeMapCounter == 100)
1577
                {
1578
                    toUnicodeMaps.append(toUnicodeMap);
1579
                    toUnicodeMapsCount.append(toUnicodeMapCounter);
1580
                    toUnicodeMap = "";
1581
                    toUnicodeMapCounter = 0;
1582
                }
1583
                crc++;
1584
            }
1585
            else
1586
            {
1587
                startOfSeq = true;
1588
            }
1589
            if (signed(glyph) == nglyphs-1)
1590
                break;
1591
            if (crc > 8)
1592
            {
1593
                PutDoc("\n");
1594
                crc = 0;
1595
            }
1596
        }
1597
        if (toUnicodeMapCounter != 0)
1598
        {
1599
            toUnicodeMaps.append(toUnicodeMap);
1600
            toUnicodeMapsCount.append(toUnicodeMapCounter);
1601
        }
1602
        PutDoc("]\n");
1603
        PutDoc(">>");
1604
        writer.endObj(fontEncoding2);
1605
        QByteArray toUnicodeMapStream = "";
1606
        toUnicodeMapStream += "/CIDInit /ProcSet findresource begin\n";
1607
        toUnicodeMapStream += "12 dict begin\n";
1608
        toUnicodeMapStream += "begincmap\n";
1609
        toUnicodeMapStream += "/CIDSystemInfo <<\n";
1610
        toUnicodeMapStream += "/Registry (Adobe)\n";
1611
        toUnicodeMapStream += "/Ordering (UCS)\n";
1612
        toUnicodeMapStream += "/Supplement 0\n";
1613
        toUnicodeMapStream += ">> def\n";
1614
        toUnicodeMapStream += "/CMapName /Adobe-Identity-UCS def\n";
1615
        toUnicodeMapStream += "/CMapType 2 def\n";
1616
        toUnicodeMapStream += "1 begincodespacerange\n";
1617
        toUnicodeMapStream += "<0000> <FFFF>\n";
1618
        toUnicodeMapStream += "endcodespacerange\n";
1619
        for (int uniC = 0; uniC < toUnicodeMaps.count(); uniC++)
1620
        {
1621
            toUnicodeMapStream += Pdf::toPdf(toUnicodeMapsCount[uniC]);
1622
            toUnicodeMapStream += " beginbfchar\n";
1623
            toUnicodeMapStream += toUnicodeMaps[uniC];
1624
            toUnicodeMapStream += "endbfchar\n";
1625
        }
1626
        toUnicodeMapStream += "endcmap\n";
1627
        toUnicodeMapStream += "CMapName currentdict /CMap defineresource pop\n";
1628
        toUnicodeMapStream += "end\n";
1629
        toUnicodeMapStream += "end\n";
1630
        PdfId fontToUnicode2 = WritePDFStream(toUnicodeMapStream);
1631
        PdfId fontObject2 = writer.newObject();
1632
        writer.startObj(fontObject2);
1633
        PutDoc("<<\n/Type /Font\n/Subtype ");
1634
        PutDoc(subtype + "\n");
1635
        PutDoc("/Name "+Pdf::toName(fontName)+"S"+Pdf::toPdf(Fc)+"\n");
1636
        PutDoc("/BaseFont "+baseFont+"\n");
1637
        PutDoc("/FirstChar 0\n");
1638
        PutDoc("/LastChar "+Pdf::toPdf(chCount-1)+"\n");
1639
        PutDoc("/Widths "+Pdf::toPdf(fontWidths2)+" 0 R\n");
1640
        PutDoc("/Encoding "+Pdf::toPdf(fontEncoding2)+" 0 R\n");
1641
        PutDoc("/ToUnicode "+Pdf::toPdf(fontToUnicode2)+" 0 R\n");
1642
        PutDoc("/FontDescriptor "+Pdf::toPdf(fontDes)+" 0 R\n");
1643
        PutDoc(">>");
1644
        writer.endObj(fontObject2);
1645
        pageData.FObjects[fontName + "S"+Pdf::toPdf(Fc)] = fontObject2;
1646
    } // for(Fc)
1647
    PdfId fontWidthsForm = writer.newObject();
1648
    writer.startObj(fontWidthsForm);
1649
    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 ");
1650
    for (int ww = 32; ww < 256; ++ww)
1651
    {
1652
        uint glyph = face.char2CMap(QChar(ww));
1653
        if (gl.contains(glyph))
1654
            PutDoc(Pdf::toPdf(static_cast<int>(face.glyphWidth(glyph)* 1000))+" ");
1655
        else
1656
            PutDoc("0 ");
1657
    }
1658
    PutDoc("]");
1659
    writer.endObj(fontWidthsForm);
1660
    PdfId fontObjectForm = writer.newObject();
1661
    PdfFont formFont;
1662
    formFont.name = Pdf::toName(fontName) + "Form";
1663
    formFont.usage = Used_in_Forms;
1664
    writer.startObj(fontObjectForm);
1665
    PutDoc("<<\n/Type /Font\n/Subtype ");
1666
    PutDoc(subtype + "\n");
1667
    //                          if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1668
    //                          {
1669
    //                                  PutDoc("/TrueType\n");
1670
    PutDoc("/Name " + formFont.name+ "\n");
1671
    pageData.FObjects[formFont.name] = fontObjectForm;
1672
    UsedFontsF.insert(fontName, formFont);
1673
    /*                          }
1674
     else
1675
     {
1676
     PutDoc("/Type1\n");
1677
     PutDoc("/Name /"+face.psName().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )+"\n");
1678
     pageData.FObjects[face.psName().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" )] = ObjCounter;
1679
     UsedFontsF.insert(it.key(), "/"+face.psName().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" ));
1680
     } */
1681
    PutDoc("/BaseFont "+Pdf::toName(sanitizeFontName(face.psName()))+"\n");
1682
    PutDoc("/Encoding << \n");
1683
    PutDoc("/Differences [ \n");
1684
    PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
1685
    PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
1686
    PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
1687
    PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
1688
    PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
1689
    PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
1690
    PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
1691
    PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
1692
    PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
1693
    PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
1694
    PutDoc("] >>\n");
1695
    PutDoc("/FirstChar 0\n");
1696
    PutDoc("/LastChar 255\n");
1697
    PutDoc("/Widths "+Pdf::toPdf(fontWidthsForm)+" 0 R\n");
1698
    PutDoc("/FontDescriptor "+Pdf::toPdf(fontDes)+" 0 R\n");
1699
    PutDoc(">>");
1700
    writer.endObj(fontObjectForm);
1701
 
1702
    return result;
1703
}
1704
 
1705
 
1706
static void dumpFont(QString name, QByteArray data)
1707
{
1708
    QFile file(name);
1709
    file.open(QIODevice::WriteOnly);
1710
    QDataStream out(&file);
1711
    out.writeRawData(data.data(), data.length());
1712
}
1713
 
1714
static void dumpCFF(QString name, cff::CFF font)
1715
{
1716
    QFile file(name);
1717
    file.open(QIODevice::WriteOnly);
1718
    QDataStream out(&file);
1719
    font.dump(out);
1720
}
1721
 
1722
 
1723
PdfFont PDFLibCore::PDF_WriteTtfSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1724
{
1725
    QByteArray font;
1726
    face.RawData(font);
1727
dumpFont(face.psName() + ".ttf", font);
1728
    QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
1729
    glyphs.removeAll(0);
1730
    glyphs.prepend(0);
1731
    QByteArray subset = sfnt::subsetFace(font, glyphs);
1732
dumpFont(face.psName()+"subs.ttf", subset);
1733
    PdfId embeddedFontObj = PDF_EmbedFontObject(subset, QByteArray());
1734
    PdfId fontDes = PDF_WriteFontDescriptor(fontName, face, face.format(), embeddedFontObj);
1735
    QByteArray baseFont = Pdf::toName(sanitizeFontName(face.psName()));
1736
    ScFace::FaceEncoding fullEncoding, subEncoding;
1737
    QMap<uint,uint> glyphmap;
1738
    face.glyphNames(fullEncoding);
1739
    for (int i = 0; i < glyphs.length(); ++i)
1740
    {
1741
        glyphmap[glyphs[i]] = i;
1742
        qDebug() << glyphs[i] << " --> " << i << QChar(fullEncoding[glyphs[i]].first);
1743
    }
1744
 
1745
    PdfFont result = PDF_EncodeCidFont(fontName, face, baseFont, fontDes, fullEncoding, glyphmap);
1746
    return result;
1747
}
1748
 
1749
 
1750
PdfFont PDFLibCore::PDF_WriteCffSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1751
{
1752
//    QByteArray sfnt; //TEST
1753
//    face.RawData(sfnt);
1754
//    QByteArray cff = sfnt::getTable(sfnt, "CFF ");
1755
//    dumpFont(fontName, cff);
1756
//    cff::CFF cfffont(cff);
1757
//    cfffont.dump();
1758
//    QByteArray subsetfont = cff::subsetFace(cff, it.value().keys());
1759
//    dumpFont(it.key() + "subs.cff", subsetfont);
1760
//    cff::CFF subset(subsetfont);
1761
//    subset.dump();
1762
//    PDF_WriteFontDescriptor(fontName, face, fformat, 0);
1763
//    // END
1764
 
1765
    QByteArray font;
1766
    face.RawData(font);
1767
    font = sfnt::getTable(font, "CFF ");
1768
    dumpFont(face.psName() + ".cff", font);
1769
    QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
1770
    glyphs.removeAll(0);
1771
    glyphs.prepend(0);
1772
    QByteArray subset = cff::subsetFace(font, glyphs);
1773
    dumpFont(face.psName()+"subs.cff", subset);
1774
    PdfId embeddedFontObj = PDF_EmbedFontObject(subset, "/CIDFontType0C");
1775
    PdfId fontDes = PDF_WriteFontDescriptor(fontName, face, face.format(), embeddedFontObj);
1776
    QByteArray baseFont = Pdf::toName(sanitizeFontName(face.psName()));
1777
    ScFace::FaceEncoding fullEncoding, subEncoding;
1778
    QMap<uint,uint> glyphmap;
1779
    face.glyphNames(fullEncoding);
1780
    for (int i = 0; i < glyphs.length(); ++i)
1781
    {
1782
        glyphmap[glyphs[i]] = i;
1783
        qDebug() << glyphs[i] << " --> " << i << QChar(fullEncoding[glyphs[i]].first);
1784
    }
1785
 
1786
    PdfFont result = PDF_EncodeCidFont(fontName, face, baseFont, fontDes, fullEncoding, glyphmap);
1787
    return result;
1788
}
1789
 
1790
 
1791
PdfId PDFLibCore::PDF_EmbedType1AsciiFontObject(const QByteArray& fon)
1792
{
1793
    QByteArray fon2;
1794
    PdfId embeddedFontObject = writer.newObject();
1795
    writer.startObj(embeddedFontObject);
1796
    int len1 = fon.indexOf("eexec")+5;
1797
    fon2 = fon.left(len1) + "\n";
1798
    int len2 = fon.indexOf("0000000000000000000000000");
1799
    if (len2 == -1)
1800
        len2 = fon.length()+1;
1801
    //              QString tm;
1802
    //              uint value;
1803
    //              bool ok = true;
1804
    //                          int count = 0;
1805
    //                          for (int xx = len1; xx < len2-1; ++xx)
1806
    //                          {
1807
    //                                  tm = fon.at(xx);
1808
    //                                  if ((tm == QChar(13)) || (tm == QChar(10)))
1809
    //                                          continue;
1810
    //                                  xx++;
1811
    //                                  count++;
1812
    //                                  tm += fon.at(xx);
1813
    //                                  value = tm.toUInt(&ok, 16);
1814
    //                                  fon2 += char(value);
1815
    //                          }
1816
    QByteArray hexData = QByteArray::fromHex(fon.mid(len1, len2-len1));
1817
    fon2 += hexData;
1818
    fon2 += fon.mid(len2);
1819
    if (Options.Compress)
1820
        fon2 = CompressArray(fon2);
1821
    PutDoc("<<\n/Length "+Pdf::toPdf(fon2.length()+1)+"\n");
1822
    PutDoc("/Length1 "+Pdf::toPdf(len1+1)+"\n");
1823
    PutDoc("/Length2 "+Pdf::toPdf(hexData.length())+"\n");
1824
    if(static_cast<int>(fon.length()-len2) == -1)
1825
        PutDoc("/Length3 0\n");
1826
    else
1827
        PutDoc("/Length3 "+Pdf::toPdf(fon.length()-len2)+"\n");
1828
    if (Options.Compress)
1829
        PutDoc("/Filter /FlateDecode\n");
1830
    PutDoc(">>\nstream\n"+EncStream(fon2, embeddedFontObject)+"\nendstream");
1831
    writer.endObj(embeddedFontObject);
1832
    return embeddedFontObject;
1833
}
1834
 
1835
 
1836
PdfId PDFLibCore::PDF_EmbedType1BinaryFontObject(const QByteArray& bb)
1837
{
1838
    PdfId embeddedFontObject = writer.newObject();
1839
    QByteArray fon;
1840
    writer.startObj(embeddedFontObject);
1841
    int posi;
1842
    for (posi = 6; posi < bb.size(); ++posi)
1843
    {
1844
        if ((bb[posi] == static_cast<char>(0x80)) && (static_cast<int>(bb[posi+1]) == 2))
1845
            break;
1846
        fon += bb[posi];
1847
    }
1848
    int len1 = fon.length();
1849
    int ulen;
1850
    ulen = bb[posi+2] & 0xff;
1851
    ulen |= (bb[posi+3] << 8) & 0xff00;
1852
    ulen |= (bb[posi+4] << 16) & 0xff0000;
1853
    ulen |= (bb[posi+5] << 24) & 0xff000000;
1854
    if (ulen > bb.size())
1855
        ulen = bb.size()-7;
1856
    posi += 6;
1857
    for (int j = 0; j < ulen; ++j)
1858
        fon += bb[posi++];
1859
    posi += 6;
1860
    int len2 = fon.length()-len1;
1861
    for (int j = posi; j < bb.size(); ++j)
1862
    {
1863
        if ((bb[j] == static_cast<char>(0x80)) && (static_cast<int>(bb[j+1]) == 3))
1864
            break;
1865
        if (bb[j] == '\r')
1866
            fon += "\n";
1867
        else
1868
            fon += bb[j];
1869
    }
1870
    int len3 = fon.length()-len2-len1;
1871
    if (Options.Compress)
1872
        fon = CompressArray(fon);
1873
    PutDoc("<<\n/Length "+Pdf::toPdf(fon.length()+1)+"\n");
1874
    PutDoc("/Length1 "+Pdf::toPdf(len1)+"\n");
1875
    PutDoc("/Length2 "+Pdf::toPdf(len2)+"\n");
1876
    PutDoc("/Length3 "+Pdf::toPdf(len3)+"\n");
1877
    if (Options.Compress)
1878
        PutDoc("/Filter /FlateDecode\n");
1879
    PutDoc(">>\nstream\n"+EncStream(fon,embeddedFontObject)+"\nendstream");
1880
    writer.endObj(embeddedFontObject);
1881
    return embeddedFontObject;
1882
}
1883
 
1884
 
1885
PdfId PDFLibCore::PDF_EmbedFontObject(const QString& name, ScFace& face)
1886
{
1887
    PdfId embeddedFontObject = 0;
1888
    if (Options.EmbedList.contains(name))
1889
    {
1890
        ScFace::FontFormat fformat = face.format();
1891
        QByteArray bb;
1892
        face.RawData(bb);
1893
       if (fformat == ScFace::PFB)
1894
        {
1895
            embeddedFontObject = PDF_EmbedType1BinaryFontObject(bb);
1896
        }
1897
        if (fformat == ScFace::PFA)
1898
        {
1899
            embeddedFontObject = PDF_EmbedType1AsciiFontObject(bb);
1900
        }
1901
        if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1902
        {
1903
            QByteArray subtype;
1904
            if (face.type() == ScFace::OTF)
1905
            {
1906
                subtype = "/CIDFontType0C";
1907
                bb = sfnt::getTable(bb, "CFF ");
1908
                dumpCFF(face.psName() + ".cff", cff::CFF(bb));
1909
                bb = cff::extractFace(bb, 0);
1910
                dumpCFF(face.psName() + "full.cff", cff::CFF(bb));
1911
            }
1912
            embeddedFontObject = PDF_EmbedFontObject(bb, subtype);
1913
        }
1914
    }
1915
    return embeddedFontObject;
1916
}
1917
 
1918
 
1919
void PDFLibCore::PDF_Begin_WriteUsedFonts(SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& ReallyUsed)
1920
{
1921
    qDebug() << "embed list:" << QStringList(Options.EmbedList).join(", ");
1922
    qDebug() << "subset list:" << QStringList(Options.SubsetList).join(", ");
1923
    qDebug() << "outline list:" << QStringList(Options.OutlineList).join(", ");
1924
    QMap<QString,QMap<uint, FPointArray> >::ConstIterator it;
1925
    int a = 0;
1926
    for (it = ReallyUsed.cbegin(); it != ReallyUsed.cend(); ++it)
1927
    {
1928
        ScFace& face(AllFonts[it.key()]);
1929
        ScFace::FontFormat fformat = face.format();
1930
        PdfFont pdfFont;
1931
        QByteArray fontName = QByteArray("Fo") + Pdf::toPdf(a);
1932
 
1933
        qDebug() << "pdf font" << it.key();
1934
        if (Options.OutlineList.contains(it.key()))
1935
        {
1936
            pdfFont = PDF_WriteGlyphsAsXForms(fontName, face, it.value());
1937
        }
1938
        else
1939
        {
1940
            if (Options.SubsetList.contains(it.key()))
1941
            {
1942
                if (fformat == ScFace::SFNT || fformat == ScFace::TTCF)
1943
                {
1944
                    if (face.type() == ScFace::TTF)
1945
                    {
1946
                        pdfFont = PDF_WriteTtfSubsetFont(fontName, face, it.value());
1947
                    }
1948
                    else
1949
                    {
1950
                        pdfFont = PDF_WriteCffSubsetFont(fontName, face, it.value());
1951
                    }
1952
                }
1953
                else
1954
                {
1955
                    pdfFont = PDF_WriteType3Font(fontName, face, it.value());
1956
                }
1957
            }
1958
            else
1959
            {
1960
                PdfId embeddedFontObject = PDF_EmbedFontObject(it.key(), face);
1961
 
1962
                PdfId fontDescriptor = PDF_WriteFontDescriptor(fontName, face, fformat, embeddedFontObject);
1963
 
1964
                ScFace::FaceEncoding gl;
1965
                face.glyphNames(gl);
1966
 
1967
                QByteArray baseFont = Pdf::toName(sanitizeFontName(face.psName()));
1968
 
1969
                if ((face.isSymbolic() || !face.hasNames() || Options.Version == PDFOptions::PDFVersion_X4 || face.type() == ScFace::OTF) &&
1970
                    (fformat == ScFace::SFNT || fformat == ScFace::TTCF))
1971
                {
1972
                    pdfFont = PDF_EncodeCidFont(fontName, face, baseFont, fontDescriptor, gl, QMap<uint,uint>());
1973
                }
1974
                else
1975
                {
1976
                    QByteArray subtype = (fformat == ScFace::SFNT || fformat == ScFace::TTCF) ? "/TrueType" : "/Type1";
1977
                    pdfFont = PDF_EncodeSimpleFont(fontName, face, baseFont, subtype, embeddedFontObject != 0, fontDescriptor, gl);
1978
                }
1979
            }
1980
            pdfFont.usage = Used_in_Content;
1981
            QString meth;
1982
            switch (pdfFont.method)
1983
            {
1984
                case Use_System:
1985
                    meth = "Systemfont (no embedding)"; break;
1986
                case Use_Embedded:
1987
                    meth = "Embed"; break;
1988
                case Use_Subset:
1989
                    meth = "Subset"; break;
1990
                case Use_Type3:
1991
                    meth = "Subset as Type3 font"; break;
1992
                case Use_XForm:
1993
                    meth = "Outline (PDF XForm)"; break;
1994
                default:
1995
                    meth = "?"; break;
1996
            }
1997
            qDebug() << pdfFont.name << "uses method" << meth << "and encoding" << pdfFont.encoding;
1998
            UsedFontsP.insert(it.key(), pdfFont);
1999
            a++;
2000
        }
2001
    }
2002
}
2003
 
2004
void PDFLibCore::PDF_Begin_Colors()
2005
{
4264 craig 2006
        if (Options.UseLPI)
3133 fschmid 2007
        {
20103 avox 2008
                uint halftones = writer.newObject();
2009
                writer.startObj(halftones);
3133 fschmid 2010
                PutDoc("<<\n/Type /Halftone\n/HalftoneType 5\n");
4264 craig 2011
                QMap<QString,LPIData>::const_iterator itlp;
2012
                for (itlp = Options.LPISettings.constBegin(); itlp != Options.LPISettings.constEnd(); ++itlp)
3133 fschmid 2013
                {
20103 avox 2014
            PutDoc(Pdf::toName(itlp.key()) + "\n<<\n/Type /Halftone\n/HalftoneType 1\n/Frequency ");
2015
                        PutDoc(Pdf::toPdf(itlp.value().Frequency)+"\n/Angle "+Pdf::toPdf(itlp.value().Angle)+"\n/SpotFunction ");
2016
                        QByteArray func ("");
10469 cbradney 2017
                        switch (itlp.value().SpotFunc)
3133 fschmid 2018
                        {
2019
                                case 0:
2020
                                        func = "/SimpleDot";
2021
                                        break;
2022
                                case 1:
2023
                                        func = "/Line";
2024
                                        break;
2025
                                case 2:
2026
                                        func = "/Round";
2027
                                        break;
2028
                                case 3:
2029
                                        func = "/Ellipse";
2030
                                        break;
2031
                                default:
2032
                                        func = "/SimpleDot";
2033
                                        break;
2034
                        }
20103 avox 2035
                        PutDoc(func + "\n>>\n");
3133 fschmid 2036
                }
2037
                PutDoc("/Default\n<<\n/Type /Halftone\n/HalftoneType 1\n/Frequency 50\n/Angle 45\n/SpotFunction /Round\n>>\n");
20103 avox 2038
        PutDoc(">>");
2039
        writer.endObj(halftones);
2040
                HTName = ResNam+Pdf::toPdf(ResCount);
2041
                Transpar[HTName] = writeGState("/HT "+Pdf::toPdf(halftones)+" 0 R\n");
3133 fschmid 2042
                ResCount++;
2043
        }
19115 avox 2044
        if ((doc.HasCMS) && (Options.UseProfiles) && (Options.Version != PDFOptions::PDFVersion_X1a))
3133 fschmid 2045
        {
20103 avox 2046
                PdfId iccProfileObject = writer.newObject();
2047
                writer.startObj(iccProfileObject);
7144 jghali 2048
                QByteArray dataP;
20103 avox 2049
                PdfICCD dataD;
7144 jghali 2050
                loadRawBytes(ScCore->InputProfiles[Options.SolidProf], dataP);
3133 fschmid 2051
                PutDoc("<<\n");
11317 jghali 2052
                if (Options.Compress)
3133 fschmid 2053
                {
11317 jghali 2054
                        QByteArray compData = CompressArray(dataP);
2055
                        if (compData.size() > 0)
2056
                        {
2057
                                PutDoc("/Filter /FlateDecode\n");
2058
                                dataP = compData;
2059
                        }
3133 fschmid 2060
                }
20103 avox 2061
                PutDoc("/Length "+Pdf::toPdf(dataP.size()+1)+"\n");
2062
                PutDoc("/N "+Pdf::toPdf(Options.SComp)+"\n");
7144 jghali 2063
                PutDoc(">>\nstream\n");
12080 avox 2064
                EncodeArrayToStream(dataP, iccProfileObject);
20103 avox 2065
        PutDoc("\nendstream");
2066
        writer.endObj(iccProfileObject);
2067
                PdfId iccColorspace = writer.newObject();
2068
                writer.startObj(iccColorspace);
2069
                dataD.ResName = ResNam+Pdf::toPdf(ResCount);
2070
                dataD.ICCArray = "[ /ICCBased "+Pdf::toPdf(iccProfileObject)+" 0 R ]";
12080 avox 2071
                dataD.ResNum = iccColorspace;
12732 fschmid 2072
                dataD.components = Options.SComp;
4264 craig 2073
                ICCProfiles[Options.SolidProf] = dataD;
20103 avox 2074
                PutDoc("[ /ICCBased "+Pdf::toPdf(iccProfileObject)+" 0 R ]");
2075
                writer.endObj(iccColorspace);
3133 fschmid 2076
                ResCount++;
2077
        }
4264 craig 2078
        if (((Options.isGrayscale == false) && (Options.UseRGB == false)) && (Options.UseSpotColors))
3133 fschmid 2079
        {
4264 craig 2080
                doc.getUsedColors(colorsToUse);
3133 fschmid 2081
                ColorList::Iterator itf;
2082
                for (itf = colorsToUse.begin(); itf != colorsToUse.end(); ++itf)
2083
                {
2084
                        if ((colorsToUse[itf.key()].isSpotColor()) || (colorsToUse[itf.key()].isRegistrationColor()))
2085
                        {
9619 jghali 2086
                                CMYKColor cmykValues;
3133 fschmid 2087
                                int cc, cm, cy, ck;
20103 avox 2088
                                PdfSpotC spotD;
9619 jghali 2089
                                ScColorEngine::getCMYKValues(colorsToUse[itf.key()], &doc, cmykValues);
2090
                                cmykValues.getValues(cc, cm, cy, ck);
20103 avox 2091
                                QByteArray colorDesc = "{\ndup "+FToStr(static_cast<double>(cc) / 255)+"\nmul exch dup ";
3133 fschmid 2092
                                colorDesc += FToStr(static_cast<double>(cm) / 255)+"\nmul exch dup ";
2093
                                colorDesc += FToStr(static_cast<double>(cy) / 255)+"\nmul exch ";
2094
                                colorDesc += FToStr(static_cast<double>(ck) / 255)+" mul }";
20103 avox 2095
                                PdfId separationFunction = writer.newObject();
2096
                                writer.startObj(separationFunction);
3133 fschmid 2097
                                PutDoc("<<\n/FunctionType 4\n");
2098
                                PutDoc("/Domain [0.0 1.0]\n");
2099
                                PutDoc("/Range [0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]\n");
20103 avox 2100
                                PutDoc("/Length "+Pdf::toPdf(colorDesc.length()+1)+"\n");
2101
                PutDoc(">>\nstream\n"+EncStream(colorDesc, separationFunction)+"\nendstream");
2102
                writer.endObj(separationFunction);
2103
                                PdfId separationColorspace= writer.newObject();
2104
                                writer.startObj(separationColorspace);
2105
                                PutDoc("[ /Separation ");
3133 fschmid 2106
                                if (colorsToUse[itf.key()].isRegistrationColor())
20103 avox 2107
                                        PutDoc("/All");
3133 fschmid 2108
                                else
20103 avox 2109
                    PutDoc(Pdf::toName(itf.key().simplified().replace("#", "#23").replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "#20" )));
2110
                PutDoc(" /DeviceCMYK "+Pdf::toObjRef(separationFunction)+" ]");
2111
                writer.endObj(separationColorspace);
2112
                                spotD.ResName = spotNam+Pdf::toPdf(spotCount);
12080 avox 2113
                                spotD.ResNum = separationColorspace;
3133 fschmid 2114
                                spotMap.insert(itf.key(), spotD);
2115
                                spotCount++;
2116
                        }
2117
                }
2118
        }
6925 fschmid 2119
        if ((Options.cropMarks) || (Options.bleedMarks) || (Options.registrationMarks) || (Options.colorMarks) || (Options.docInfoMarks))
2120
        {
20103 avox 2121
                PdfSpotC spotD;
2122
                PdfId registrationColorspace = writer.newObject();
2123
                writer.startObj(registrationColorspace);
6925 fschmid 2124
                PutDoc("[ /Separation /All /DeviceCMYK\n");
2125
                PutDoc("<<\n/FunctionType 2\n");
2126
                PutDoc("/Domain [0.0 1.0]\n");
2127
                PutDoc("/Range [0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]\n");
2128
                PutDoc("/C0 [0 0 0 0] \n");
2129
                PutDoc("/C1 [1 1 1 1] \n");
2130
                PutDoc("/N 1\n");
20103 avox 2131
        PutDoc(">>\n]");
2132
        writer.endObj(registrationColorspace);
2133
                spotD.ResName = spotNam+Pdf::toPdf(spotCount);
12080 avox 2134
                spotD.ResNum = registrationColorspace;
6925 fschmid 2135
                spotMapReg.insert("Register", spotD);
2136
                spotCount++;
2137
        }
20103 avox 2138
}
14043 jghali 2139
 
20103 avox 2140
void PDFLibCore::PDF_Begin_Layers()
2141
{
14043 jghali 2142
        if ( ((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
3133 fschmid 2143
        {
10140 jghali 2144
                ScLayer ll;
20103 avox 2145
                PdfOCGInfo ocg;
3133 fschmid 2146
                ll.isPrintable = false;
13875 jghali 2147
                ll.ID = 0;
3133 fschmid 2148
                int Lnr = 0;
20103 avox 2149
                QByteArray ocgNam("oc");
4264 craig 2150
                uint docLayersCount=doc.Layers.count();
3829 cbradney 2151
                for (uint la = 0; la < docLayersCount; ++la)
3133 fschmid 2152
                {
20103 avox 2153
                        PdfId optionalContent = writer.newObject();
10140 jghali 2154
                        doc.Layers.levelToLayer(ll, Lnr);
20103 avox 2155
            ocg.Name = ocgNam + Pdf::toPdf(ll.ID);
12080 avox 2156
                        ocg.ObjNum = optionalContent;
3133 fschmid 2157
                        ocg.visible = ll.isViewable;
2158
                        OCGEntries.insert(ll.Name, ocg);
20103 avox 2159
                        writer.startObj(optionalContent);
3133 fschmid 2160
                        PutDoc("<<\n");
2161
                        PutDoc("/Type /OCG\n");
7328 fschmid 2162
                        PutDoc("/Name ");
17378 jghali 2163
                        PutDoc(EncStringUTF16(ll.Name, optionalContent));
7328 fschmid 2164
                        PutDoc("\n");
11908 fschmid 2165
                        PutDoc("/Usage <</Print <</PrintState ");
2166
                        if (ll.isPrintable)
2167
                                PutDoc("/ON");
2168
                        else
2169
                                PutDoc("/OFF");
2170
                        PutDoc(">> /View <</ViewState ");
2171
                        if (ll.isViewable)
2172
                                PutDoc("/ON");
2173
                        else
2174
                                PutDoc("/OFF");
19210 jghali 2175
                        PutDoc(">>>>");
11908 fschmid 2176
                        PutDoc("\n");
20103 avox 2177
            PutDoc(">>");
2178
            writer.endObj(optionalContent);
3133 fschmid 2179
                        Lnr++;
2180
                }
2181
        }
2182
}
2183
 
16729 fschmid 2184
bool PDFLibCore::PDF_TemplatePage(const ScPage* pag, bool )
3133 fschmid 2185
{
20103 avox 2186
        QByteArray tmp, tmpOut;
3133 fschmid 2187
        ActPageP = pag;
2188
        PageItem* ite;
9856 fschmid 2189
        QList<PageItem*> PItems;
3133 fschmid 2190
        int Lnr = 0;
10140 jghali 2191
        ScLayer ll;
3133 fschmid 2192
        ll.isPrintable = false;
13875 jghali 2193
        ll.ID = 0;
11060 jghali 2194
        Content = "";
20089 jghali 2195
 
2196
        double bLeft, bRight, bBottom, bTop;
2197
        getBleeds(pag, bLeft, bRight, bBottom, bTop);
2198
 
20103 avox 2199
        pageData.AObjects.clear();
2200
 
2201
    for (int la = 0; la < doc.Layers.count(); ++la)
3133 fschmid 2202
        {
10140 jghali 2203
                doc.Layers.levelToLayer(ll, Lnr);
4264 craig 2204
                PItems = doc.MasterItems;
14043 jghali 2205
                if ((ll.isPrintable) || (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers)))
3133 fschmid 2206
                {
14043 jghali 2207
                        if (((Opt