Subversion Repositories Scribus

Rev

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