Subversion Repositories Scribus

Rev

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

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
3133 fschmid 7
/***************************************************************************
14043 jghali 8
                                                  pdflib_core.cpp  -  description
9
                                                         -------------------
10
        begin                : Sat Jan 19 2002
11
        copyright            : (C) 2002 by Franz Schmid
12
        email                : Franz.Schmid@altmuehlnet.de
3133 fschmid 13
 ***************************************************************************/
14
 
15
/***************************************************************************
16
 *                                                                         *
17
 *   This program is free software; you can redistribute it and/or modify  *
18
 *   it under the terms of the GNU General Public License as published by  *
19
 *   the Free Software Foundation; either version 2 of the License, or     *
20
 *   (at your option) any later version.                                   *
21
 *                                                                         *
22
 ***************************************************************************/
23
 
10054 craig 24
#include "pdflib_core.h"
3133 fschmid 25
 
26
#include "scconfig.h"
27
 
17539 jghali 28
#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
14170 jghali 29
#define _USE_MATH_DEFINES
30
#endif
12080 avox 31
#include <cmath>
32
#include <cstdlib>
4229 craig 33
#include <string>
12080 avox 34
#ifdef HAVE_UNISTD_H
35
#include <unistd.h>
36
#endif
37
 
38
#include "rc4.h"
39
 
40
#include <QByteArray>
19914 craig 41
#include <QCryptographicHash>
10223 cbradney 42
#include <QDateTime>
10004 fschmid 43
#include <QDataStream>
12080 avox 44
#include <QDebug>
10223 cbradney 45
#include <QDir>
12080 avox 46
#include <QFileInfo>
47
#include <QImage>
9803 fschmid 48
#include <QList>
11453 fschmid 49
#include <QPainterPath>
8501 cbradney 50
#include <QPixmap>
12080 avox 51
#include <QRect>
52
#include <QRegExp>
19671 jghali 53
#include <QScopedPointer>
12080 avox 54
#include <QStack>
55
#include <QString>
13839 fschmid 56
#include <QTemporaryFile>
10614 cbradney 57
#include <QTextCodec>
14043 jghali 58
#include <QtXml>
59
#include <QUuid>
3133 fschmid 60
 
10601 mrdocs 61
#include "cmsettings.h"
4028 cbradney 62
#include "commonstrings.h"
3133 fschmid 63
#include "pageitem.h"
10601 mrdocs 64
#include "pageitem_textframe.h"
16258 fschmid 65
#include "pageitem_group.h"
17023 fschmid 66
#include "pageitem_pathtext.h"
17312 fschmid 67
#include "pageitem_table.h"
10212 cbradney 68
#include "pdfoptions.h"
69
#include "prefscontext.h"
70
#include "prefsmanager.h"
71
#include "sccolor.h"
72
#include "sccolorengine.h"
73
#include "scfonts.h"
20103 avox 74
#include "fonts/cff.h"
75
#include "fonts/sfnt.h"
16736 jghali 76
#include "scpage.h"
5917 jghali 77
#include "scpaths.h"
10212 cbradney 78
#include "scpattern.h"
19115 avox 79
 
5243 cbradney 80
#include "scribuscore.h"
3699 cbradney 81
#include "scribusdoc.h"
11599 jghali 82
#include "scstreamfilter_flate.h"
83
#include "scstreamfilter_rc4.h"
17312 fschmid 84
#include "tableutils.h"
3133 fschmid 85
#include "util.h"
11605 jghali 86
#include "util_file.h"
10212 cbradney 87
#include "util_formats.h"
10203 cbradney 88
#include "util_math.h"
12517 fschmid 89
#include "util_ghostscript.h"
16736 jghali 90
 
13839 fschmid 91
#ifdef HAVE_OSG
14930 fschmid 92
        #include "third_party/prc/exportPRC.h"
13839 fschmid 93
#endif
3133 fschmid 94
 
16736 jghali 95
#include "ui/bookmwin.h"
96
#include "ui/bookmarkpalette.h"
97
#include "ui/multiprogressdialog.h"
98
 
3133 fschmid 99
using namespace std;
17312 fschmid 100
using namespace TableUtils;
3133 fschmid 101
 
12096 jghali 102
#if defined(_WIN32)
103
#undef GetObject
104
#endif
3133 fschmid 105
 
6562 fschmid 106
 
10054 craig 107
PDFLibCore::PDFLibCore(ScribusDoc & docu)
4264 craig 108
        : QObject(&docu),
4223 craig 109
        doc(docu),
110
        ActPageP(0),
14925 cbradney 111
        Options(doc.pdfOptions()),
4223 craig 112
        Bvie(0),
19114 avox 113
        ucs2Codec(0),
20103 avox 114
//      ObjCounter(7),
4223 craig 115
        ResNam("RE"),
116
        ResCount(0),
117
        NDnam("LI"),
118
        NDnum(0),
20103 avox 119
//      KeyGen(""),
120
//      OwnerKey(""),
121
//      UserKey(""),
122
//      FileID(""),
123
//      EncryKey(""),
124
//      Encrypt(0),
125
//      KeyLen(5),
4223 craig 126
        colorsToUse(),
127
        spotNam("Spot"),
128
        spotCount(0),
4225 craig 129
        progressDialog(0),
4223 craig 130
        abortExport(false),
20089 jghali 131
        usingGUI(ScCore->usingGUI()),
132
        bleedDisplacementX(0),
133
        bleedDisplacementY(0)
3133 fschmid 134
{
20103 avox 135
//      KeyGen.resize(32);
136
//      OwnerKey.resize(32);
137
//      UserKey.resize(32);
138
//      FileID.resize(16);
139
//      EncryKey.resize(5);
3133 fschmid 140
        Catalog.Outlines = 2;
141
        Catalog.PageTree = 3;
142
        Catalog.Dest = 4;
143
        PageTree.Count = 0;
144
        Outlines.First = 0;
145
        Outlines.Last = 0;
146
        Outlines.Count = 0;
20103 avox 147
        pageData.ObjNum = 0;
148
        pageData.Thumb = 0;
149
//      int kg_array[] = {0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa,
150
//                        0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe,
151
//                        0x64, 0x53, 0x69, 0x7a};
152
//      for (int a = 0; a < 32; ++a)
153
//              KeyGen[a] = kg_array[a];
4028 cbradney 154
        if (usingGUI)
155
        {
10508 cbradney 156
                progressDialog = new MultiProgressDialog( tr("Saving PDF"), CommonStrings::tr_Cancel, doc.scMW());
4224 craig 157
                Q_CHECK_PTR(progressDialog);
158
                QStringList barNames, barTexts;
159
                barNames << "EMP" << "EP" << "ECPI";
5370 cbradney 160
                barTexts << tr("Exporting Master Page:") << tr("Exporting Page:") << tr("Exporting Items on Current Page:");
9803 fschmid 161
                QList<bool> barsNumeric;
5370 cbradney 162
                barsNumeric << true << true << false;
163
                progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
8559 subik 164
                connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
4028 cbradney 165
        }
3133 fschmid 166
}
167
 
10054 craig 168
PDFLibCore::~PDFLibCore()
4224 craig 169
{
170
        delete progressDialog;
171
}
172
 
20103 avox 173
static inline QByteArray FToStr(double c)
4229 craig 174
{
15283 fschmid 175
        double v = c;
176
        if (fabs(c) < 0.0000001)
177
                v = 0.0;
20112 jghali 178
        return QByteArray::number(v, 'f', 5);
4229 craig 179
};
180
 
19115 avox 181
bool PDFLibCore::PDF_IsPDFX()
182
{
183
        if (Options.Version == PDFOptions::PDFVersion_X1a)
184
                return true;
185
        if (Options.Version == PDFOptions::PDFVersion_X3)
186
                return true;
187
        if (Options.Version == PDFOptions::PDFVersion_X4)
188
                return true;
189
        return false;
190
}
191
 
192
bool PDFLibCore::PDF_IsPDFX(PDFOptions::PDFVersion ver)
193
{
194
        if (ver == PDFOptions::PDFVersion_X1a)
195
                return true;
196
        if (ver == PDFOptions::PDFVersion_X3)
197
                return true;
198
        if (ver == PDFOptions::PDFVersion_X4)
199
                return true;
200
        return false;
201
}
202
 
10054 craig 203
bool PDFLibCore::doExport(const QString& fn, const QString& nam, int Components,
4264 craig 204
                                          const std::vector<int> & pageNs, const QMap<int,QPixmap> & thumbs)
3133 fschmid 205
{
206
        QPixmap pm;
11060 jghali 207
        bool ret = false, error = false;
208
        int  pc_exportpages=0;
209
        int  pc_exportmasterpages=0;
4224 craig 210
        if (usingGUI)
211
                progressDialog->show();
5387 avox 212
        QMap<QString, QMap<uint, FPointArray> > usedFonts;
213
        usedFonts.clear();
214
        doc.getUsedFonts(usedFonts);
19114 avox 215
        ucs2Codec = QTextCodec::codecForName("ISO-10646-UCS-2");
17758 jghali 216
        if (!ucs2Codec)
19114 avox 217
                ucs2Codec = QTextCodec::codecForName("UTF-16");
218
        if (!ucs2Codec)
13764 jghali 219
        {
13791 pierre 220
                PDF_Error( tr("Qt build miss both \"UTF-16\" and \"ISO-10646-UCS-2\" text codecs, pdf export is not possible") );
13764 jghali 221
                return false;
222
        }
13955 cbradney 223
        if (PDF_Begin_Doc(fn, PrefsManager::instance()->appPrefs.fontPrefs.AvailFonts, usedFonts, doc.scMW()->bookmarkPalette->BView))
3133 fschmid 224
        {
225
                QMap<int, int> pageNsMpa;
226
                for (uint a = 0; a < pageNs.size(); ++a)
227
                {
14653 jghali 228
                        pageNsMpa.insert(doc.MasterNames[doc.DocPages.at(pageNs[a]-1)->MPageNam], 0);
3133 fschmid 229
                }
4028 cbradney 230
                if (usingGUI)
3133 fschmid 231
                {
4028 cbradney 232
                        progressDialog->setOverallTotalSteps(pageNsMpa.count()+pageNs.size());
233
                        progressDialog->setTotalSteps("EMP", pageNsMpa.count());
234
                        progressDialog->setTotalSteps("EP", pageNs.size());
235
                        progressDialog->setOverallProgress(0);
236
                        progressDialog->setProgress("EMP", 0);
237
                        progressDialog->setProgress("EP", 0);
238
                }
10018 fschmid 239
                for (int ap = 0; ap < doc.MasterPages.count() && !abortExport; ++ap)
4028 cbradney 240
                {
4264 craig 241
                        if (doc.MasterItems.count() != 0)
3133 fschmid 242
                        {
243
                                if (pageNsMpa.contains(ap))
244
                                {
5243 cbradney 245
                                        qApp->processEvents();
11060 jghali 246
                                        if (!PDF_TemplatePage(doc.MasterPages.at(ap)))
247
                                                error = abortExport = true;
4028 cbradney 248
                                        ++pc_exportmasterpages;
3133 fschmid 249
                                }
250
                        }
4546 subik 251
                        if (usingGUI)
252
                        {
4028 cbradney 253
                                progressDialog->setProgress("EMP", pc_exportmasterpages);
254
                                progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
255
                        }
3133 fschmid 256
                }
4028 cbradney 257
                for (uint a = 0; a < pageNs.size() && !abortExport; ++a)
3133 fschmid 258
                {
14925 cbradney 259
                        if (doc.pdfOptions().Thumbnails)
3133 fschmid 260
                                pm = thumbs[pageNs[a]];
5243 cbradney 261
                        qApp->processEvents();
4028 cbradney 262
                        if (abortExport) break;
11060 jghali 263
 
14653 jghali 264
                        PDF_Begin_Page(doc.DocPages.at(pageNs[a]-1), pm);
5243 cbradney 265
                        qApp->processEvents();
4028 cbradney 266
                        if (abortExport) break;
11060 jghali 267
 
14925 cbradney 268
                        if (!PDF_ProcessPage(doc.DocPages.at(pageNs[a]-1), pageNs[a]-1, doc.pdfOptions().doClip))
11060 jghali 269
                                error = abortExport = true;
5243 cbradney 270
                        qApp->processEvents();
4028 cbradney 271
                        if (abortExport) break;
11060 jghali 272
 
15444 craig 273
                        PDF_End_Page(a);
4028 cbradney 274
                        pc_exportpages++;
275
                        if (usingGUI)
276
                        {
277
                                progressDialog->setProgress("EP", pc_exportpages);
278
                                progressDialog->setOverallProgress(pc_exportmasterpages+pc_exportpages);
279
                        }
3133 fschmid 280
                }
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;
20112 jghali 420
        else
421
                return writer.encryptBytes(in, ObjNum);
20103 avox 422
//      rc4_context_t rc4;
423
//      QByteArray tmp(in);
424
//      QByteArray us(tmp.length(), ' ');
425
//      QByteArray ou(tmp.length(), ' ');
426
//      for (int a = 0; a < tmp.length(); ++a)
20112 jghali 427
//              us[a] = (tmp.at(a));
428
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
20103 avox 429
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
430
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), tmp.length());
431
//      QString uk = "";
432
//      for (int cl = 0; cl < tmp.length(); ++cl)
433
//              uk += QChar(ou[cl]);
434
//      return ou;
19114 avox 435
}
436
 
20103 avox 437
QByteArray PDFLibCore::EncString(const QByteArray & in, PdfId ObjNum)
19114 avox 438
{
20103 avox 439
        QByteArray tmp;
19114 avox 440
        if (in.length() < 1)
441
                return "<>";
442
        if (!Options.Encrypt)
443
        {
20103 avox 444
                //tmp = "(" + PDFEncode(in) + ")";
20112 jghali 445
                return Pdf::toLiteralString(in);
19114 avox 446
        }
20112 jghali 447
 
20103 avox 448
//      rc4_context_t rc4;
449
//      QByteArray us(in.length(), ' ');
450
//      QByteArray ou(in.length(), ' ');
451
//      for (int a = 0; a < in.length(); ++a)
452
//              us[a] = static_cast<uchar>(QChar(in.at(a)).cell());
453
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
454
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
455
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), in.length());
456
//      QString uk = "";
457
//      for (int cl = 0; cl < in.length(); ++cl)
458
//              uk += QChar(ou[cl]);
20112 jghali 459
 
460
        return Pdf::toHexString(writer.encryptBytes(in, ObjNum));
19114 avox 461
}
462
 
20103 avox 463
QByteArray PDFLibCore::EncStringUTF16(const QString & in, PdfId ObjNum)
19114 avox 464
{
465
        if (in.length() < 1)
466
                return "<>";
467
        if (!Options.Encrypt)
468
        {
20112 jghali 469
                QByteArray us = Pdf::toUTF16(in);
20103 avox 470
//              QString uk = "";
471
//              for (int cl = 0; cl < us.size(); ++cl)
472
//                      uk += QChar(us[cl]);
473
                return Pdf::toHexString(us);
19114 avox 474
        }
20103 avox 475
//      rc4_context_t rc4;
20112 jghali 476
        QByteArray us = Pdf::toUTF16(in);
20103 avox 477
//      QByteArray ou(us.size(), ' ');
478
//      QByteArray step1 = writer.ComputeRC4Key(ObjNum);
479
//      rc4_init(&rc4, reinterpret_cast<uchar*>(step1.data()), qMin(KeyLen+5, 16));
480
//      rc4_encrypt(&rc4, reinterpret_cast<uchar*>(us.data()), reinterpret_cast<uchar*>(ou.data()), ou.size());
481
//      QString uk = "";
482
//      for (int cl = 0; cl < ou.size(); ++cl)
483
//              uk += QChar(ou[cl]);
484
        QByteArray tmp = Pdf::toHexString(writer.encryptBytes(us, ObjNum));
19114 avox 485
        return tmp;
486
}
487
 
20103 avox 488
bool PDFLibCore::EncodeArrayToStream(const QByteArray& in, PdfId ObjNum)
19114 avox 489
{
490
        if (in.size() < 1)
491
                return true;
492
        bool succeed = false;
493
        if (Options.Encrypt)
494
        {
20103 avox 495
                ScStreamFilter* rc4Encode = writer.openStreamFilter(true, ObjNum);
496
                if (rc4Encode->openFilter())
19114 avox 497
                {
20103 avox 498
                        succeed  = rc4Encode->writeData(in.data(), in.size());
499
                        succeed &= rc4Encode->closeFilter();
19114 avox 500
                }
20112 jghali 501
                delete rc4Encode;
19114 avox 502
        }
503
        else
20103 avox 504
                writer.write(in);
505
        return (writer.getOutStream().status() == QDataStream::Ok);
19114 avox 506
}
507
 
20103 avox 508
int PDFLibCore::WriteImageToStream(ScImage& image, PdfId ObjNum, ColorSpaceEnum format, bool precal)
11599 jghali 509
{
17758 jghali 510
        bool fromCmyk, succeed = false;
11599 jghali 511
        int  bytesWritten = 0;
20103 avox 512
 
20112 jghali 513
        ScStreamFilter* rc4Encode = writer.openStreamFilter(Options.Encrypt, ObjNum);
514
        if (rc4Encode->openFilter())
515
        {
516
                switch (format)
517
                {
518
                        case ColorSpaceMonochrome :
519
                                fromCmyk = !Options.UseRGB && !Options.isGrayscale && !(doc.HasCMS && Options.UseProfiles2);
520
                                succeed = image.writeMonochromeDataToFilter(rc4Encode, fromCmyk); break;
521
                        case ColorSpaceGray :
522
                                succeed = image.writeGrayDataToFilter(rc4Encode, precal); break;
523
                        case ColorSpaceCMYK :
524
                                succeed = image.writeCMYKDataToFilter(rc4Encode); break;
525
                        default :
526
                                succeed = image.writeRGBDataToFilter(rc4Encode); break;
527
                }
528
                succeed &= rc4Encode->closeFilter();
529
                bytesWritten = rc4Encode->writtenToStream();
530
                delete rc4Encode;
531
        }
11599 jghali 532
        return (succeed ? bytesWritten : 0);
533
}
534
 
20103 avox 535
int PDFLibCore::WriteJPEGImageToStream(ScImage& image, const QString& fn, PdfId ObjNum, int quality, ColorSpaceEnum format,
17758 jghali 536
                                                                                 bool sameFile, bool precal)
11599 jghali 537
{
538
        bool succeed = true;
539
        int  bytesWritten = 0;
540
        QFileInfo fInfo(fn);
541
        QString   ext = fInfo.suffix().toLower();
542
        QString   jpgFileName, tmpFile;
543
        if (extensionIndicatesJPEG(ext) && sameFile)
544
                jpgFileName = fn;
11445 jghali 545
        else
11599 jghali 546
        {
16577 craig 547
                tmpFile  = QDir::toNativeSeparators(ScPaths::getTempFileDir() + "sc.jpg");
17758 jghali 548
                if (format == ColorSpaceGray && (!precal))
11599 jghali 549
                        image.convertToGray();
17758 jghali 550
                if (image.convert2JPG(tmpFile, quality, format == ColorSpaceCMYK, format == ColorSpaceGray))
11599 jghali 551
                        jpgFileName = tmpFile;
552
        }
553
        if (jpgFileName.isEmpty())
11792 fschmid 554
                return 0;
11599 jghali 555
        if (Options.Encrypt)
556
        {
557
                succeed = false;
20112 jghali 558
                ScStreamFilter* rc4Encode = writer.openStreamFilter(true, ObjNum);
559
                if (rc4Encode->openFilter())
11599 jghali 560
                {
20103 avox 561
                        succeed  = copyFileToFilter(jpgFileName, *rc4Encode);
562
                        succeed &= rc4Encode->closeFilter();
563
                        bytesWritten = rc4Encode->writtenToStream();
11599 jghali 564
                }
20112 jghali 565
                delete rc4Encode;
11599 jghali 566
        }
567
        else
568
        {
20103 avox 569
                succeed &= copyFileToStream(jpgFileName, writer.getOutStream());
11599 jghali 570
                QFileInfo jpgInfo(jpgFileName);
571
                bytesWritten = jpgInfo.size();
572
        }
573
        if (!tmpFile.isEmpty() && QFile::exists(tmpFile))
574
                QFile::remove(tmpFile);
575
        return (succeed ? bytesWritten : 0);
11445 jghali 576
}
577
 
20103 avox 578
int PDFLibCore::WriteFlateImageToStream(ScImage& image, PdfId ObjNum, ColorSpaceEnum format, bool precal)
11599 jghali 579
{
20112 jghali 580
        bool fromCmyk, succeed = false;
581
        int  bytesWritten = 0;
582
        ScStreamFilter* rc4Encode = writer.openStreamFilter(Options.Encrypt, ObjNum);
583
        ScFlateEncodeFilter flateEncode(rc4Encode);
584
        if (flateEncode.openFilter())
585
        {
586
                switch (format)
587
                {
588
                        case ColorSpaceMonochrome :
589
                                fromCmyk = !Options.UseRGB && !Options.isGrayscale && !(doc.HasCMS && Options.UseProfiles2);
590
                                succeed = image.writeMonochromeDataToFilter(&flateEncode, fromCmyk); break;
591
                        case ColorSpaceGray :
592
                                succeed = image.writeGrayDataToFilter(&flateEncode, precal); break;
593
                        case ColorSpaceCMYK :
594
                                succeed = image.writeCMYKDataToFilter(&flateEncode); break;
595
                        default :
596
                                succeed = image.writeRGBDataToFilter(&flateEncode); break;
597
                }
598
                succeed &= flateEncode.closeFilter();
599
                bytesWritten = flateEncode.writtenToStream();
600
        }
601
        delete rc4Encode;
602
        return (succeed ? bytesWritten : 0);
11599 jghali 603
}
604
 
3133 fschmid 605
 
19114 avox 606
 
20103 avox 607
bool PDFLibCore::PDF_Begin_Doc(const QString& fn, SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& DocFonts, BookMView* vi)
19114 avox 608
{
20112 jghali 609
        if (!writer.open(fn))
610
                return false;
611
 
612
        QFileInfo fiBase(fn);
613
        QString baseDir = fiBase.absolutePath();
19114 avox 614
 
20103 avox 615
//      QString tmp;
616
//      QFileInfo fd;
617
//      QString fext;
6407 fschmid 618
        inPattern = 0;
3133 fschmid 619
        Bvie = vi;
620
        BookMinUse = false;
621
        UsedFontsP.clear();
8454 fschmid 622
        UsedFontsF.clear();
20112 jghali 623
 
624
        writer.writeHeader(Options.Version);
625
 
20103 avox 626
//      if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
627
//              ObjCounter = 10;
628
//      else
629
//              ObjCounter = 9;
630
//      switch (Options.Version)
631
//      {
632
//              case PDFOptions::PDFVersion_X1a:
633
//              case PDFOptions::PDFVersion_X3:
634
//              case PDFOptions::PDFVersion_13:
635
//                      PutDoc("%PDF-1.3\n");
636
//                      break;
637
//              case PDFOptions::PDFVersion_14:
638
//                      PutDoc("%PDF-1.4\n");
639
//                      break;
640
//              case PDFOptions::PDFVersion_X4:
641
//              case PDFOptions::PDFVersion_15:
642
//                      PutDoc("%PDF-1.5\n");
643
//                      break;
644
//      }
645
//      if (PDF_IsPDFX())
646
//              ObjCounter++;
647
//      PutDoc("%\xc7\xec\x8f\xa2\n");
648
 
20112 jghali 649
        PDF_Begin_Catalog();
650
        PDF_Begin_MetadataAndEncrypt();
651
        PDF_Begin_WriteUsedFonts(AllFonts, PDF_Begin_FindUsedFonts(AllFonts, DocFonts));
652
        PDF_Begin_Colors();
653
        PDF_Begin_Layers();
654
 
655
        return true;
20103 avox 656
}
657
 
658
void PDFLibCore::PDF_Begin_Catalog()
659
{
20112 jghali 660
        writer.startObj(writer.CatalogObj);
661
        PutDoc("<<\n/Type /Catalog");
662
        PutDoc("\n/Outlines " + Pdf::toObjRef(writer.OutlinesObj) +
663
                   "\n/Pages " + Pdf::toObjRef(writer.PagesObj) +
664
                   "\n/Dests " + Pdf::toObjRef(writer.DestsObj) +
665
                   "\n/AcroForm " + Pdf::toObjRef(writer.AcroFormObj) +
666
                   "\n/Names "+ Pdf::toObjRef(writer.NamesObj) +
667
                   "\n/Threads " +  Pdf::toObjRef(writer.ThreadsObj) +
668
                   "\n");
19114 avox 669
        if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
20112 jghali 670
        {
671
                writer.OCPropertiesObj = writer.newObject();
20103 avox 672
                PutDoc("/OCProperties " + Pdf::toObjRef(writer.OCPropertiesObj) + "\n");
20112 jghali 673
        }
674
        if (PDF_IsPDFX())
19114 avox 675
        {
20112 jghali 676
                writer.OutputIntentObj = writer.newObject();
677
                PutDoc("/OutputIntents [ " +  Pdf::toObjRef(writer.OutputIntentObj) + " ]\n");
678
        }
679
        if ((Options.Version == PDFOptions::PDFVersion_X4))
680
        {
681
                writer.MetaDataObj = writer.newObject();
20103 avox 682
                PutDoc("/Metadata "+ Pdf::toObjRef(writer.MetaDataObj) + "\n");
19114 avox 683
        }
684
        PutDoc("/PageLayout ");
685
        switch (Options.PageLayout)
686
        {
687
                case PDFOptions::SinglePage:
688
                        PutDoc("/SinglePage\n");
689
                        break;
690
                case PDFOptions::OneColumn:
691
                        PutDoc("/OneColumn\n");
692
                        break;
693
                case PDFOptions::TwoColumnLeft:
694
                        PutDoc("/TwoColumnLeft\n");
695
                        break;
696
                case PDFOptions::TwoColumnRight:
697
                        PutDoc("/TwoColumnRight\n");
698
                        break;
699
        }
700
        if (Options.displayBookmarks)
701
                PutDoc("/PageMode /UseOutlines\n");
702
        else if (Options.displayFullscreen)
703
                PutDoc("/PageMode /FullScreen\n");
704
        else if (Options.displayThumbs)
705
                PutDoc("/PageMode /UseThumbs\n");
706
        else if ((Options.Version == PDFOptions::PDFVersion_15) && (Options.displayLayers))
707
                        PutDoc("/PageMode /UseOC\n");
708
        if (!Options.openAction.isEmpty())
709
        {
20112 jghali 710
                PutDoc("/OpenAction << /S /JavaScript /JS (this."+Pdf::toPdfDocEncoding(Options.openAction)+"\\(\\)) >>\n");
19114 avox 711
        }
20112 jghali 712
        QString tmp;
19114 avox 713
        QDateTime dt = QDateTime::currentDateTime().toUTC();
20112 jghali 714
        Datum = Pdf::toDateString(dt);
20103 avox 715
//    "D:";
716
//      tmp.sprintf("%4d", d.year());
717
//      tmp.replace(QRegExp(" "), "0");
718
//      Datum += tmp;
719
//      tmp.sprintf("%2d", d.month());
720
//      tmp.replace(QRegExp(" "), "0");
721
//      Datum += tmp;
722
//      tmp.sprintf("%2d", d.day());
723
//      tmp.replace(QRegExp(" "), "0");
724
//      Datum += tmp;
725
//      tmp = dt.time().toString();
726
//      tmp.replace(QRegExp(":"), "");
727
//      Datum += tmp;
728
//      Datum += "Z";
12429 fschmid 729
 
19114 avox 730
        // only include XMP to PDF/X-4 at the moment, could easily be extended to include it to any PDF
731
        if (Options.Version == PDFOptions::PDFVersion_X4)
732
                generateXMP(dt.toString("yyyy-MM-ddThh:mm:ssZ"));
733
 
734
/* The following code makes the resulting PDF "Reader enabled" in Acrobat Reader 8
735
   but sadly it doesn't work with newer version, because its based on a bug in AR 8
736
        PutDoc("/Perms\n");
737
        PutDoc("<<\n");
738
        PutDoc("/UR3\n");
739
        PutDoc("<<\n");
740
        PutDoc("/M ("+Datum+")\n");
741
        PutDoc("/Name (Scribus "+QString(VERSION)+")\n");
742
        PutDoc("/Reference [\n");
743
        PutDoc("<<\n");
744
        PutDoc("/TransformParams\n");
745
        PutDoc("<<\n");
746
        PutDoc("/Type /TransformParams\n");
747
        PutDoc("/V /2.2\n");
748
        PutDoc("/Document [/FullSave]\n");
749
        PutDoc("/Annots [/Create/Delete/Modify/Copy/Import/Export]\n");
750
        PutDoc("/Form [/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate]\n");
751
        PutDoc("/Signature [/Modify]\n");
752
        PutDoc(">>\n");
753
        PutDoc("/TransformMethod /UR3\n");
754
        PutDoc("/Type /SigRef\n");
755
        PutDoc(">>\n");
756
        PutDoc("]\n");
757
        PutDoc("/Type /Sig\n");
758
        PutDoc(">>\n");
759
        PutDoc(">>\n");
760
*/
761
 
762
        PutDoc("/ViewerPreferences\n<<\n/PageDirection ");
763
        PutDoc( Options.Binding == 0 ? "/L2R\n" : "/R2L\n");
764
        if (Options.hideToolBar)
765
                PutDoc("/HideToolbar true\n");
766
        if (Options.hideMenuBar)
767
                PutDoc("/HideMenubar true\n");
768
        if (Options.fitWindow)
769
                PutDoc("/FitWindow true\n");
20112 jghali 770
        PutDoc(" >>\n>>");
771
        writer.endObj(writer.CatalogObj);
20103 avox 772
}
773
 
774
void PDFLibCore::PDF_Begin_MetadataAndEncrypt()
775
{
19114 avox 776
        QString IDg(Datum);
777
        IDg += Options.fileName;
778
        IDg += "Scribus "+QString(VERSION);
779
        IDg += "Scribus PDF Library "+QString(VERSION);
780
        IDg += doc.documentInfo().title();
781
        IDg += doc.documentInfo().author();
782
        IDg += "/False";
20112 jghali 783
        writer.setFileId(Pdf::toPdfDocEncoding(IDg));
19114 avox 784
        if (Options.Encrypt)
785
        {
20112 jghali 786
                writer.setEncryption((Options.Version == PDFOptions::PDFVersion_14) || (Options.Version == PDFOptions::PDFVersion_15), Pdf::toPdfDocEncoding(Options.PassOwner), Pdf::toPdfDocEncoding(Options.PassUser), Options.Permissions);
19114 avox 787
        }
20103 avox 788
        writer.startObj(writer.InfoObj);
20112 jghali 789
        PutDoc("<<\n/Creator " + EncString(QByteArray("Scribus ") + VERSION, writer.InfoObj) + "\n");
20103 avox 790
        PutDoc("/Producer " + EncString(QByteArray("Scribus PDF Library ") + VERSION, writer.InfoObj) + "\n");
19114 avox 791
        QString docTitle = doc.documentInfo().title();
19115 avox 792
        if ((PDF_IsPDFX()) && (docTitle.isEmpty()))
20103 avox 793
                PutDoc("/Title " + EncStringUTF16(doc.DocName, writer.InfoObj) + "\n");
19114 avox 794
        else
20103 avox 795
                PutDoc("/Title " + EncStringUTF16(doc.documentInfo().title(), writer.InfoObj) + "\n");
796
        PutDoc("/Author " + EncStringUTF16(doc.documentInfo().author(), writer.InfoObj) + "\n");
797
        PutDoc("/Subject " + EncStringUTF16(doc.documentInfo().subject(), writer.InfoObj) + "\n");
798
        PutDoc("/Keywords " + EncStringUTF16(doc.documentInfo().keywords(), writer.InfoObj) + "\n");
799
        PutDoc("/CreationDate " + EncString(Datum, writer.InfoObj) + "\n");
800
        PutDoc("/ModDate " + EncString(Datum, writer.InfoObj) + "\n");
19114 avox 801
        if (Options.Version == PDFOptions::PDFVersion_X1a)
802
        {
803
                PutDoc("/GTS_PDFXVersion (PDF/X-1:2001)\n");
804
                PutDoc("/GTS_PDFXConformance (PDF/X-1a:2001)\n");
805
        }
19115 avox 806
        if (Options.Version == PDFOptions::PDFVersion_X3)
807
                PutDoc("/GTS_PDFXVersion (PDF/X-3:2002)\n");
19114 avox 808
        if (Options.Version == PDFOptions::PDFVersion_X4)
809
                PutDoc("/GTS_PDFXVersion (PDF/X-4)\n");
20112 jghali 810
        PutDoc("/Trapped /False\n>>");
811
        writer.endObj(writer.InfoObj);
20103 avox 812
 
20112 jghali 813
        // Encrypt
814
 
815
//      for (int t = 0; t < 6; ++t)
20103 avox 816
//              XRef.append(bytesWritten());
817
//      if (((Options.Version == PDFOptions::PDFVersion_15) || (Options.Version == PDFOptions::PDFVersion_X4)) && (Options.useLayers))
818
//              XRef.append(bytesWritten());
819
//      if (PDF_IsPDFX())
820
//              XRef.append(bytesWritten());
821
//      if (Options.Version == PDFOptions::PDFVersion_X4)
822
//              XRef.append(bytesWritten());
19114 avox 823
        if (Options.Encrypt)
20103 avox 824
        { // now done in writer.setEncrption():
825
//              writer.EncryptObj = writer.newObject();
826
//              writer.startObj(writer.EncryptObj);
827
//              PutDoc("<<\n/Filter /Standard\n");
828
//              PutDoc( KeyLen > 5 ? "/R 3\n/V 2\n/Length 128\n" : "/R 2\n/V 1\n");
829
//              PutDoc("/O "+Pdf::toHexString(ok)+"\n");
830
//              PutDoc("/U "+Pdf::toHexString(uk)+"\n");
20112 jghali 831
//              PutDoc("/P "+Pdf::toPdf(Options.Permissions)+"\n>>");
832
//              writer.endObj(writer.EncryptObj);
19114 avox 833
        }
20103 avox 834
}
835
 
836
QMap<QString, QMap<uint, FPointArray> >
837
PDFLibCore::PDF_Begin_FindUsedFonts(SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& DocFonts)
838
{
5387 avox 839
        QMap<QString, QMap<uint, FPointArray> > ReallyUsed;
3133 fschmid 840
        ReallyUsed.clear();
841
        PageItem* pgit;
20103 avox 842
        QMap<int, QByteArray> ind2PDFabr;
843
        const QByteArray tmpf[] = {"/Courier", "/Courier-Bold", "/Courier-Oblique", "/Courier-BoldOblique",
4017 fschmid 844
                                                                                                "/Helvetica", "/Helvetica-Bold", "/Helvetica-Oblique", "/Helvetica-BoldOblique",
4546 subik 845
                                                                                                "/Times-Roman", "/Times-Bold", "/Times-Italic", "/Times-BoldItalic",
4017 fschmid 846
                                                                                                "/ZapfDingbats", "/Symbol"};
847
        size_t ar = sizeof(tmpf) / sizeof(*tmpf);
848
        for (uint ax = 0; ax < ar; ++ax)
849
                ind2PDFabr[ax] = tmpf[ax];
16953 fschmid 850
        QList<PageItem*> allItems;
17407 fschmid 851
        for (QHash<int, PageItem*>::iterator itf = doc.FrameItems.begin(); itf != doc.FrameItems.end(); ++itf)
3133 fschmid 852
        {
17407 fschmid 853
                pgit = itf.value();
16953 fschmid 854
                if (pgit->isGroup())
855
                        allItems = pgit->asGroupFrame()->getItemList();
856
                else
857
                        allItems.append(pgit);
858
                for (int ii = 0; ii < allItems.count(); ii++)
3133 fschmid 859
                {
16953 fschmid 860
                        pgit = allItems.at(ii);
17312 fschmid 861
                        if (pgit->isTable())
862
                        {
863
                                for (int row = 0; row < pgit->asTable()->rows(); ++row)
864
                                {
865
                                        for (int col = 0; col < pgit->asTable()->columns(); col ++)
866
                                        {
867
                                                TableCell cell = pgit->asTable()->cellAt(row, col);
868
                                                if (cell.row() == row && cell.column() == col)
869
                                                {
870
                                                        PageItem* textFrame = cell.textFrame();
871
                                                        for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
872
                                                        {
873
                                                                ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
874
                                                        }
875
                                                }
876
                                        }
877
                                }
878
                        }
16953 fschmid 879
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 880
                        {
16953 fschmid 881
                                if (pgit->isAnnotation())
12763 fschmid 882
                                {
16953 fschmid 883
                                        int annotType  = pgit->annotation().Type();
17911 fschmid 884
                                        bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
17952 fschmid 885
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 886
                                                StdFonts.insert("/ZapfDingbats", "");
887
                                        if (pgit->itemText.length() > 0 || mustEmbed)
888
                                        {
889
                                                if (Options.Version < PDFOptions::PDFVersion_14)
890
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
891
                                                ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
892
                                        }
12763 fschmid 893
                                }
17751 jghali 894
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
895
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
896
                                for (uint e = start; e < stop; ++e)
16953 fschmid 897
                                {
898
                                        ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
899
                                }
8092 fschmid 900
                        }
3133 fschmid 901
                }
902
        }
9856 fschmid 903
        for (int c = 0; c < doc.MasterItems.count(); ++c)
3133 fschmid 904
        {
4264 craig 905
                pgit = doc.MasterItems.at(c);
16953 fschmid 906
                if (pgit->isGroup())
907
                        allItems = pgit->asGroupFrame()->getItemList();
908
                else
909
                        allItems.append(pgit);
910
                for (int ii = 0; ii < allItems.count(); ii++)
3133 fschmid 911
                {
16953 fschmid 912
                        pgit = allItems.at(ii);
17312 fschmid 913
                        if (pgit->isTable())
914
                        {
915
                                for (int row = 0; row < pgit->asTable()->rows(); ++row)
916
                                {
917
                                        for (int col = 0; col < pgit->asTable()->columns(); col ++)
918
                                        {
919
                                                TableCell cell = pgit->asTable()->cellAt(row, col);
920
                                                if (cell.row() == row && cell.column() == col)
921
                                                {
922
                                                        PageItem* textFrame = cell.textFrame();
923
                                                        for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
924
                                                        {
925
                                                                ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
926
                                                        }
927
                                                }
928
                                        }
929
                                }
930
                        }
16953 fschmid 931
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 932
                        {
16953 fschmid 933
                                if (pgit->isAnnotation())
12763 fschmid 934
                                {
16953 fschmid 935
                                        int annotType  = pgit->annotation().Type();
17911 fschmid 936
                                        bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
17952 fschmid 937
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 938
                                                StdFonts.insert("/ZapfDingbats", "");
939
                                        if (pgit->itemText.length() > 0 || mustEmbed)
940
                                        {
941
                                                if (Options.Version < PDFOptions::PDFVersion_14)
942
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
943
                                                ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
944
                                        }
12763 fschmid 945
                                }
17751 jghali 946
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
947
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
948
                                for (uint e = start; e < stop; ++e)
16953 fschmid 949
                                {
950
                                        ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
951
                                }
8092 fschmid 952
                        }
3133 fschmid 953
                }
954
        }
9856 fschmid 955
        for (int d = 0; d < doc.Items->count(); ++d)
3133 fschmid 956
        {
4264 craig 957
                pgit = doc.Items->at(d);
16953 fschmid 958
                if (pgit->isGroup())
959
                        allItems = pgit->asGroupFrame()->getItemList();
960
                else
961
                        allItems.append(pgit);
962
                for (int ii = 0; ii < allItems.count(); ii++)
3133 fschmid 963
                {
16953 fschmid 964
                        pgit = allItems.at(ii);
17312 fschmid 965
                        if (pgit->isTable())
966
                        {
967
                                for (int row = 0; row < pgit->asTable()->rows(); ++row)
968
                                {
969
                                        for (int col = 0; col < pgit->asTable()->columns(); col ++)
970
                                        {
971
                                                TableCell cell = pgit->asTable()->cellAt(row, col);
972
                                                if (cell.row() == row && cell.column() == col)
973
                                                {
974
                                                        PageItem* textFrame = cell.textFrame();
975
                                                        for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
976
                                                        {
977
                                                                ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
978
                                                        }
979
                                                }
980
                                        }
981
                                }
982
                        }
16953 fschmid 983
                        if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8092 fschmid 984
                        {
16953 fschmid 985
                                if (pgit->isAnnotation())
12763 fschmid 986
                                {
16953 fschmid 987
                                        int annotType  = pgit->annotation().Type();
17911 fschmid 988
                                        bool mustEmbed = ((annotType >= Annotation::Button) && (annotType <= Annotation::Listbox) && (annotType != Annotation::Checkbox));
17952 fschmid 989
                                        if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 990
                                                StdFonts.insert("/ZapfDingbats", "");
991
                                        if (pgit->itemText.length() > 0 || mustEmbed)
992
                                        {
993
                                                if (Options.Version < PDFOptions::PDFVersion_14)
994
                                                        StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
995
                                                ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
996
                                        }
12763 fschmid 997
                                }
17751 jghali 998
                                uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
999
                                uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1000
                                for (uint e = start; e < stop; ++e)
16953 fschmid 1001
                                {
1002
                                        ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
1003
                                }
8092 fschmid 1004
                        }
3133 fschmid 1005
                }
1006
        }
11453 fschmid 1007
/*      if (Options.docInfoMarks)
6943 fschmid 1008
        {
1009
                StdFonts.insert("/Helvetica", "");
11453 fschmid 1010
        } */
16052 fschmid 1011
        QStringList patterns = doc.getPatternDependencyList(doc.getUsedPatterns());
8559 subik 1012
        for (int c = 0; c < patterns.count(); ++c)
6407 fschmid 1013
        {
1014
                ScPattern pa = doc.docPatterns[patterns[c]];
9856 fschmid 1015
                for (int o = 0; o < pa.items.count(); o++)
6407 fschmid 1016
                {
1017
                        pgit = pa.items.at(o);
16953 fschmid 1018
                        if (pgit->isGroup())
1019
                                allItems = pgit->asGroupFrame()->getItemList();
1020
                        else
1021
                                allItems.append(pgit);
1022
                        for (int ii = 0; ii < allItems.count(); ii++)
6407 fschmid 1023
                        {
16953 fschmid 1024
                                pgit = allItems.at(ii);
17312 fschmid 1025
                                if (pgit->isTable())
1026
                                {
1027
                                        for (int row = 0; row < pgit->asTable()->rows(); ++row)
1028
                                        {
1029
                                                for (int col = 0; col < pgit->asTable()->columns(); col ++)
1030
                                                {
1031
                                                        TableCell cell = pgit->asTable()->cellAt(row, col);
1032
                                                        if (cell.row() == row && cell.column() == col)
1033
                                                        {
1034
                                                                PageItem* textFrame = cell.textFrame();
1035
                                                                for (uint e = 0; e < static_cast<uint>(textFrame->itemText.length()); ++e)
1036
                                                                {
1037
                                                                        ReallyUsed.insert(textFrame->itemText.charStyle(e).font().replacementName(), DocFonts[textFrame->itemText.charStyle(e).font().replacementName()]);
1038
                                                                }
1039
                                                        }
1040
                                                }
1041
                                        }
1042
                                }
16953 fschmid 1043
                                if ((pgit->itemType() == PageItem::TextFrame) || (pgit->itemType() == PageItem::PathText))
8351 fschmid 1044
                                {
16953 fschmid 1045
                                        if (pgit->isAnnotation())
12763 fschmid 1046
                                        {
17952 fschmid 1047
                                                if ((pgit->annotation().Type() == Annotation::Checkbox) || (pgit->annotation().Type() == Annotation::RadioButton))
16953 fschmid 1048
                                                        StdFonts.insert("/ZapfDingbats", "");
1049
                                                if (pgit->itemText.length() > 0)
1050
                                                {
1051
                                                        if (Options.Version < PDFOptions::PDFVersion_14)
1052
                                                                StdFonts.insert(ind2PDFabr[pgit->annotation().Font()], "");
1053
                                                        ReallyUsed.insert(pgit->itemText.defaultStyle().charStyle().font().replacementName(), DocFonts[pgit->itemText.defaultStyle().charStyle().font().replacementName()]);
1054
                                                }
12763 fschmid 1055
                                        }
17751 jghali 1056
                                        uint start = pgit->isTextFrame() ? (uint) pgit->firstInFrame() : 0;
1057
                                        uint stop  = pgit->isTextFrame() ? (uint) pgit->lastInFrame() + 1 : (uint) pgit->itemText.length();
1058
                                        for (uint e = start; e < stop; ++e)
16953 fschmid 1059
                                        {
1060
                                                ReallyUsed.insert(pgit->itemText.charStyle(e).font().replacementName(), DocFonts[pgit->itemText.charStyle(e).font().replacementName()]);
1061
                                        }
8351 fschmid 1062
                                }
6407 fschmid 1063
                        }
1064
                }
1065
        }
20112 jghali 1066
        return ReallyUsed;
20103 avox 1067
}
17628 jghali 1068
 
20103 avox 1069
static QByteArray sanitizeFontName(QString fn)
1070
{
20112 jghali 1071
        return Pdf::toPdfDocEncoding(fn.replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" ));
20103 avox 1072
}
17628 jghali 1073
 
20103 avox 1074
static QList<Pdf::Resource> asColorSpace(QList<PdfICCD> iccCSlist)
1075
{
20112 jghali 1076
        QList<Pdf::Resource> result;
1077
        foreach (Pdf::Resource r, iccCSlist)
1078
        {
1079
                result.append(r);
1080
        }
1081
        return result;
20103 avox 1082
}
1083
 
1084
static QList<Pdf::Resource> asColorSpace(QList<PdfSpotC> spotMapValues)
1085
{
20112 jghali 1086
        QList<Pdf::Resource> result;
1087
        foreach (Pdf::Resource r, spotMapValues)
1088
        {
1089
                result.append(r);
1090
        }
1091
        return result;
20103 avox 1092
}
1093
 
1094
 
1095
void PDFLibCore::PDF_WriteStandardFonts()
1096
{
20112 jghali 1097
        int a = 0;
1098
        QMap<QString, QString>::Iterator itStd;
1099
        for (itStd = StdFonts.begin(); itStd != StdFonts.end(); ++itStd)
1100
        {
1101
                PdfId fontObject = writer.newObject();
1102
                writer.startObj(fontObject);
1103
                PutDoc("<<\n/Type /Font\n/Subtype /Type1\n");
1104
                PutDoc("/Name /FoStd"+Pdf::toPdf(a)+"\n");
1105
                PutDoc("/BaseFont "+Pdf::toPdfDocEncoding(itStd.key())+"\n");
1106
                if (itStd.key() != "/ZapfDingbats")
1107
                {
1108
                        PutDoc("/Encoding << \n");
1109
                        PutDoc("/Differences [ \n");
1110
                        PutDoc("24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde\n");
1111
                        PutDoc("39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright\n");
1112
                        PutDoc("/minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron\n");
1113
                        PutDoc("/Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot\n");
1114
                        PutDoc("/.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine\n");
1115
                        PutDoc("188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex\n");
1116
                        PutDoc("/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash\n");
1117
                        PutDoc("/Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n");
1118
                        PutDoc("/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis\n");
1119
                        PutDoc("/divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis\n");
1120
                        PutDoc("] >>\n");
1121
                }
1122
                PutDoc(">>");
1123
                writer.endObj(fontObject);
1124
                pageData.FObjects["FoStd"+Pdf::toPdf(a)] = fontObject;
1125
                itStd.value() = "FoStd"+Pdf::toPdf(a);
1126
                a++;
1127
        }
20103 avox 1128
}
1129
 
1130
 
1131
PdfFont PDFLibCore::PDF_WriteType3Font(const QByteArray& name, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1132
{
20112 jghali 1133
        PdfFont result;
1134
        result.name = Pdf::toName(name);
1135
        result.method = Use_Type3;
1136
        result.encoding = Encode_256;
20103 avox 1137
 
20112 jghali 1138
        uint SubFonts = 0;
1139
        int glyphCount = 0;
1140
        double minx =  std::numeric_limits<double>::max();
1141
        double miny =  std::numeric_limits<double>::max();
1142
        double maxx = -std::numeric_limits<double>::max();
1143
        double maxy = -std::numeric_limits<double>::max();
1144
        QList<uint> glyphWidths;
1145
        QList<QByteArray> charProcs;
1146
        QByteArray encoding = "<< /Type /Encoding\n/Differences [ 0\n";
1147
        QByteArray fon;
1148
        QMap<uint, uint> glyphMapping;
1149
        ScFace::FaceEncoding gl;
1150
        face.glyphNames(gl);
1151
        QMap<uint,FPointArray>::ConstIterator ig;
1152
        for (ig = RealGlyphs.cbegin(); ig != RealGlyphs.cend(); ++ig)
1153
        {
1154
                FPoint np, np1, np2;
1155
                bool nPath = true;
1156
                fon.resize(0);
1157
                if (ig.value().size() > 3)
1158
                {
1159
                        FPointArray gly = ig.value();
1160
                        QTransform mat;
1161
                        mat.scale(100.0, -100.0);
1162
                        gly.map(mat);
1163
                        gly.translate(0, 1000);
1164
                        for (int poi = 0; poi < gly.size()-3; poi += 4)
1165
                        {
1166
                                if (gly.isMarker(poi))
1167
                                {
1168
                                        fon += "h\n";
1169
                                        nPath = true;
1170
                                        continue;
1171
                                }
1172
                                if (nPath)
1173
                                {
1174
                                        np = gly.point(poi);
1175
                                        fon += FToStr(np.x())+" "+FToStr(np.y())+" m\n";
1176
                                        nPath = false;
1177
                                }
1178
                                np = gly.point(poi+1);
1179
                                np1 = gly.point(poi+3);
1180
                                np2 = gly.point(poi+2);
1181
                                fon += FToStr(np.x()) + " " + FToStr(np.y()) + " " + FToStr(np1.x()) + " " + FToStr(np1.y()) + " " + FToStr(np2.x()) + " " + FToStr(np2.y()) + " c\n";
1182
                        }
1183
                        fon += "h f*\n";
1184
                        np = getMinClipF(&gly);
1185
                        np1 = getMaxClipF(&gly);
1186
                }
1187
                else
1188
                {
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;
20103 avox 1267
}
1268
 
1269
 
1270
PdfFont PDFLibCore::PDF_WriteGlyphsAsXForms(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1271
{
20112 jghali 1272
        PdfFont result;
1273
        result.name = Pdf::toName(fontName);
1274
        result.method = Use_XForm;
1275
        result.encoding = Encode_224;
20103 avox 1276
 
20112 jghali 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;
20103 avox 1337
}
1338
 
1339
PdfId PDFLibCore::PDF_EmbedFontObject(const QByteArray& font, const QByteArray& subtype)
1340
 
1341
{
20112 jghali 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;
20103 avox 1358
}
1359
 
1360
PdfId PDFLibCore::PDF_WriteFontDescriptor(const QByteArray& fontName, ScFace& face, ScFace::FontFormat fformat, PdfId embeddedFontObject)
1361
{
20112 jghali 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;
20103 avox 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
{
20112 jghali 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;
20103 avox 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
{
20112 jghali 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);
20103 avox 1701
 
20112 jghali 1702
        return result;
20103 avox 1703
}
1704
 
1705
 
1706
static void dumpFont(QString name, QByteArray data)
1707
{
20112 jghali 1708
        QFile file(name);
1709
        file.open(QIODevice::WriteOnly);
1710
        QDataStream out(&file);
1711
        out.writeRawData(data.data(), data.length());
20103 avox 1712
}
1713
 
1714
static void dumpCFF(QString name, cff::CFF font)
1715
{
20112 jghali 1716
        QFile file(name);
1717
        file.open(QIODevice::WriteOnly);
1718
        QDataStream out(&file);
1719
        font.dump(out);
20103 avox 1720
}
1721
 
1722
 
1723
PdfFont PDFLibCore::PDF_WriteTtfSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1724
{
20112 jghali 1725
        QByteArray font;
1726
        face.RawData(font);
20103 avox 1727
dumpFont(face.psName() + ".ttf", font);
20112 jghali 1728
        QList<ScFace::gid_type> glyphs = RealGlyphs.uniqueKeys();
1729
        glyphs.removeAll(0);
1730
        glyphs.prepend(0);
1731
        QByteArray subset = sfnt::subsetFace(font, glyphs);
20103 avox 1732
dumpFont(face.psName()+"subs.ttf", subset);
20112 jghali 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;
20103 avox 1747
}
1748
 
1749
 
1750
PdfFont PDFLibCore::PDF_WriteCffSubsetFont(const QByteArray& fontName, ScFace& face, const QMap<uint,FPointArray>& RealGlyphs)
1751
{
20112 jghali 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;
20103 avox 1788
}
1789
 
1790
 
1791
PdfId PDFLibCore::PDF_EmbedType1AsciiFontObject(const QByteArray& fon)
1792
{
20112 jghali 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;
20103 avox 1833
}
1834
 
1835
 
1836
PdfId PDFLibCore::PDF_EmbedType1BinaryFontObject(const QByteArray& bb)
1837
{
20112 jghali 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;
20103 avox 1882
}
1883
 
1884
 
1885
PdfId PDFLibCore::PDF_EmbedFontObject(const QString& name, ScFace& face)
1886
{
20112 jghali 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;
20103 avox 1916
}
1917
 
1918
 
1919
void PDFLibCore::PDF_Begin_WriteUsedFonts(SCFonts &AllFonts, const QMap<QString, QMap<uint, FPointArray> >& ReallyUsed)
1920
{
20112 jghali 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
        }
20103 avox 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
                {
20112 jghali 2014
                        PutDoc(Pdf::toName(itlp.key()) + "\n<<\n/Type /Halftone\n/HalftoneType 1\n/Frequency ");
20103 avox 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");
20112 jghali 2038
                PutDoc(">>");
2039
                writer.endObj(halftones);
20103 avox 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);
20112 jghali 2065
                PutDoc("\nendstream");
2066
                writer.endObj(iccProfileObject);
20103 avox 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");
20112 jghali 2101
                                PutDoc(">>\nstream\n"+EncStream(colorDesc, separationFunction)+"\nendstream");
2102
                                writer.endObj(separationFunction);
20103 avox 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
20112 jghali 2109
                                        PutDoc(Pdf::toName(itf.key().simplified().replace("#", "#23").replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "#20" )));
2110
                                PutDoc(" /DeviceCMYK "+Pdf::toObjRef(separationFunction)+" ]");
2111
                                writer.endObj(separationColorspace);
20103 avox 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<