Subversion Repositories Scribus

Rev

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