1 /*
2 * << H a r u --free pdf library >> -- PdfContents.cpp
3 *
4 * Copyright (c) 1999-2003 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
5 *
6 * Permission to use, copy, modify, distribute and sell this software
7 * and its documentation for any purpose is hereby granted without fee,
8 * provided that the above copyright notice appear in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation.
11 * It is provided "as is" without express or implied warranty.
12 *
13 */
14
15 #include <assert.h>
16 #include "libharu.h"
17
18 /*----- PdfContents class ----------------------------------------------------*/
19
PdfContents(PdfPage * page)20 PdfContents::PdfContents(PdfPage *page)
21 : PdfStream(page->GetXref())
22 {
23 /* initialize attributes to the default */
24 fPage = page;
25 fFontMgr = fPage->FontMgr();
26 fXObjectMgr = fPage->XObjectMgr();
27
28 fWordSpace = PDF_DEF_WORDSPACE;
29 fCharSpace = PDF_DEF_CHARSPACE;
30 fFontSize = PDF_DEF_FONTSIZE;
31 fHScalling = PDF_DEF_HSCALING;
32 fTextLeading = PDF_DEF_LEADING;
33 fRenderingMode = PDF_DEF_RENDERING_MODE;
34 fTextRaise = PDF_DEF_RAISE;
35 fLineWidth = PDF_DEF_LINEWIDTH;
36 fLineCap = PDF_DEF_LINECAP;
37 fLineJoin = PDF_DEF_LINEJOIN;
38 fMiterLimit = PDF_DEF_MITERLIMIT;
39 fDashOn = 0;
40 fDashOff = 0;
41 fDashPhase = 0;
42 fFlatness = 0;
43
44 fCurPoint.x = 0;
45 fCurPoint.y = 0;
46 fTextPoint.x = 0;
47 fTextPoint.y = 0;
48 fMatrix = PdfTextMatrix(1, 0, 0, 1, 0, 0);
49 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
50
51 fRGBFill.red = 0;
52 fRGBFill.green = 0;
53 fRGBFill.blue = 0;
54 fRGBStroke.red = 0;
55 fRGBStroke.green = 0;
56 fRGBStroke.blue = 0;
57 fGrayFill = 0;
58 fGrayStroke = 0;
59 }
60
61 void
Init()62 PdfContents::Init()
63 {
64 GetXref()->AddObject(this);
65 fPage->AddElement("Contents", this);
66
67 PdfNumber *length = new PdfNumber(0);
68 GetXref()->AddObject(length);
69 AddElement("Length", length);
70 }
71
72 /* graphics mode checking macro */
73 #define GMODE_ERROR(method_name) { \
74 throw PdfException(PDF_RUNTIME_ERROR, "ERROR: %s invalid graphics " \
75 "mode(%d).", method_name, (int)fGMode); \
76 }
77
78 /* font checking macro */
79
80
81
82 double
TextWidth(const char * text,int * numchars,int * numwords)83 PdfContents::TextWidth(const char* text, int* numchars, int* numwords)
84 {
85 if (fFont == NULL)
86 throw PdfException(PDF_RUNTIME_ERROR, "ERROR: PdfContents::TextWidth "
87 "current font has not been set.");
88
89 pdf_text_width pw = fFont->TextWidth(text);
90
91 double w1 = pw.width * fFontSize / 1000;
92 double w2 = (pw.numchars - 1) * fCharSpace;
93 double w3 = (pw.numwords - 1) * fWordSpace;
94
95 PDF_DEBUG_PRINT(("PdfContents::TextWidth pw.width=%d, pw.numchars=%d, "
96 "pw.numwords=%d\n", pw.width, pw.numchars, pw.numwords));
97
98 if (numchars != NULL)
99 *numchars = pw.numchars;
100
101 if (numwords != NULL)
102 *numwords = pw.numwords;
103
104 return w1 + w2 + w3;
105 }
106
107 void
CharWidths(const char * chars,double * widths)108 PdfContents::CharWidths(const char* chars, double* widths)
109 {
110 assert(chars);
111 assert(widths);
112
113 if (fFont == NULL)
114 throw PdfException(PDF_RUNTIME_ERROR, "ERROR: PdfContents::CharWidths "
115 "current font has not been set.");
116
117 int len = strlen(chars);
118 unsigned int* w = new unsigned int[len];
119 unsigned int* pw = w;
120 double* pf = widths;
121
122 fFont->TextWidths(chars, w);
123 for (int i = 0; i < len; i++) {
124 *pf = *pw * fFontSize / 1000;
125 pf++;
126 pw++;
127 }
128
129 delete[] w;
130 }
131
132 unsigned int
MeasureText(const char * text,double width,double * realwidth)133 PdfContents::MeasureText(const char* text, double width, double* realwidth)
134 {
135 assert(text);
136 assert(width > 0);
137
138 if (fFont == NULL)
139 throw PdfException(PDF_RUNTIME_ERROR, "ERROR: "
140 "PdfContents::MeasureText current font has not been set.");
141
142 return fFont->MeasureText(text, width, fFontSize, fCharSpace,
143 fWordSpace, realwidth);
144 }
145
146 void
TextOut(double x,double y,const char * text)147 PdfContents::TextOut(double x, double y, const char* text)
148 {
149 BeginText();
150 MoveTextPos(x, y);
151 ShowText(text);
152 EndText();
153 }
154
155 void
TextRect(const char * text,pdf_rect rect,int max_len)156 PdfContents::TextRect(const char* text, pdf_rect rect, int max_len)
157 {
158 char *tmp;
159 double w = rect.right - rect.left;
160 int len = strlen(text);
161 if (len == 0)
162 return;
163
164 /* copy the text to temporary buffer */
165 tmp = new char[len + 1];
166 int j = 0;
167 for (int i = 0; i < len; i++) {
168 if (text[i] != 0x0a) {
169 tmp[j] = text[i];
170 j++;
171 }
172 }
173 len = j;
174
175 /* replace \n charactor to 0x00 */
176 for (int k = 0; k < len; k++)
177 if (tmp[k] == 0x0d)
178 tmp[k] = 0x00;
179
180 try {
181 char* buf = new char[max_len + 1];
182
183 try {
184 BeginText();
185 double ascent = Font()->Ascent() * FontSize() / 1000;
186 MoveTextPos(rect.left, rect.top - ascent);
187
188 char* pstr = tmp;
189 char* end = tmp + len;
190
191 while (pstr < end) {
192 if (*pstr == 0x00)
193 MoveToNextLine();
194 else {
195 /* calcurate how many charactor of the text can be
196 * included in a line
197 */
198 int cnt = MeasureText(pstr, w);
199 if (cnt <= max_len) {
200 memcpy(buf, pstr, cnt);
201 buf[cnt] = 0x00;
202 } else {
203 memcpy(buf, pstr, max_len);
204 buf[max_len] = 0x00;
205 }
206 ShowText(buf);
207 MoveToNextLine();
208
209 if ((TextPos()).y < rect.bottom + TextLeading())
210 break;
211 pstr += cnt;
212 }
213 }
214
215 EndText();
216 } catch (...) {
217 delete[] buf;
218 throw;
219 }
220 delete[] buf;
221 } catch (...) {
222 delete[] tmp;
223 throw;
224 }
225 delete[] tmp;
226 }
227
228 /*----- General graphics state -------------------------------------*/
229
230 void
SetLineWidth(double linewidth)231 PdfContents::SetLineWidth(double linewidth)
232 {
233 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_TEXT_OBJECT)
234 GMODE_ERROR("SetLineWidth")
235
236 if (linewidth < 0)
237 throw PdfException(PDF_ERR_OUT_OF_RANGE,
238 "ERROR: SetLineWidth invalid value(%d).", (int)linewidth);
239
240 *GetStream() << linewidth
241 << " w\012";
242 fLineWidth = linewidth;
243 return;
244 }
245
246 void
SetLineCap(pdf_line_cap_style linecap)247 PdfContents::SetLineCap(pdf_line_cap_style linecap)
248 {
249 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_TEXT_OBJECT)
250 GMODE_ERROR("SetLineCap")
251
252 *GetStream() << (unsigned int)linecap
253 << " J\012";
254 fLineCap = linecap;
255 return;
256 }
257
258 void
SetLineJoin(pdf_line_join_style linejoin)259 PdfContents::SetLineJoin(pdf_line_join_style linejoin)
260 {
261 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_TEXT_OBJECT)
262 GMODE_ERROR("SetLineJoin")
263
264 *GetStream() << (unsigned int)linejoin
265 << " j\012";
266 fLineJoin = linejoin;
267 return;
268 }
269
270 void
SetMiterLimit(double miterlimit)271 PdfContents::SetMiterLimit(double miterlimit)
272 {
273 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_TEXT_OBJECT)
274 GMODE_ERROR("SetMiterLimit")
275
276 if (miterlimit < 1)
277 throw PdfException(PDF_ERR_OUT_OF_RANGE,
278 "ERROR: PdfContents::SetLineJoin (%d)"
279 ")--linejoin must be more than or equal to 1.", (int)miterlimit);
280
281 *GetStream() << miterlimit
282 << " M\012";
283 fMiterLimit = miterlimit;
284 return;
285 }
286
287 void
SetDash(unsigned int on,unsigned int off,unsigned int phase)288 PdfContents::SetDash(unsigned int on, unsigned int off, unsigned int phase)
289 {
290 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_TEXT_OBJECT)
291 GMODE_ERROR("SetDash")
292
293 fDashOn = on;
294 if (on == off || on == 0)
295 fDashOff = 0;
296 else
297 fDashOff = off;
298 fDashPhase = phase;
299
300 *GetStream() << '[';
301 if (fDashOn > 0) {
302 *GetStream() << fDashOn;
303 if (fDashOff > 0) {
304 *GetStream() << ' ' << fDashOff;
305 }
306 }
307 *GetStream() << ']'
308 << fDashPhase
309 << " d\012";
310 return;
311 }
312
313 void
SetFlat(unsigned int flatness)314 PdfContents::SetFlat(unsigned int flatness)
315 {
316 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_TEXT_OBJECT)
317 GMODE_ERROR("SetFlat")
318
319 if (flatness > 100)
320 throw PdfException(PDF_ERR_OUT_OF_RANGE,
321 "ERROR: PdfContents::SetFlat flatness must "
322 "be between 0 to 100.(%d).\n", flatness);
323
324 fFlatness = flatness;
325 *GetStream() << flatness
326 << " i\012";
327 return;
328 }
329
330 /*----- Special graphics state -------------------------------------*/
331
332 void
GSave()333 PdfContents::GSave()
334 {
335 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION)
336 GMODE_ERROR("GSave")
337
338 *GetStream() << "q\012";
339 return;
340 }
341
342 void
GRestore()343 PdfContents::GRestore()
344 {
345 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION)
346 GMODE_ERROR("GRestore")
347
348 *GetStream() << "Q\012";
349 return;
350 }
351
352 void
Concat(double a,double b,double c,double d,double e,double f)353 PdfContents::Concat(double a, double b, double c, double d, double e, double f)
354 {
355 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION)
356 GMODE_ERROR("Concat")
357
358 *GetStream() << a << ' '
359 << b << ' '
360 << c << ' '
361 << d << ' '
362 << e << ' '
363 << f << " cm\012";
364 return;
365 }
366
367 /*----- Path construction ------------------------------------------*/
368
369 void
MoveTo(double x,double y)370 PdfContents::MoveTo(double x, double y)
371 {
372 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_PATH_OBJECT)
373 GMODE_ERROR("MoveTo")
374
375 *GetStream() << x << ' '
376 << y << " m\012";
377 fCurPoint.x = x;
378 fCurPoint.y = y;
379 fStartPoint.x = x;
380 fStartPoint.y = y;
381 fGMode = PDF_GMODE_PATH_OBJECT;
382 return;
383 }
384
385 void
LineTo(double x,double y)386 PdfContents::LineTo(double x, double y)
387 {
388 if (fGMode != PDF_GMODE_PATH_OBJECT)
389 GMODE_ERROR("LineTo")
390
391 *GetStream() << x << ' '
392 << y << " l\012";
393 fCurPoint.x = x;
394 fCurPoint.y = y;
395 return;
396 }
397
398 void
CurveTo(double x1,double y1,double x2,double y2,double x3,double y3)399 PdfContents::CurveTo(double x1, double y1, double x2,
400 double y2, double x3, double y3)
401 {
402 if (fGMode != PDF_GMODE_PATH_OBJECT)
403 GMODE_ERROR("CurveTo")
404
405 *GetStream() << x1 << ' '
406 << y1 << ' '
407 << x2 << ' '
408 << y2 << ' '
409 << x3 << ' '
410 << y3 << " c\012";
411 fCurPoint.x = x3;
412 fCurPoint.y = y3;
413 return;
414 }
415
416 void
CurveTo2(double x2,double y2,double x3,double y3)417 PdfContents::CurveTo2(double x2, double y2, double x3, double y3)
418 {
419 if (fGMode != PDF_GMODE_PATH_OBJECT)
420 GMODE_ERROR("CurveTo2")
421
422 *GetStream() << x2 << ' '
423 << y2 << ' '
424 << x3 << ' '
425 << y3 << " v\012";
426 fCurPoint.x = x3;
427 fCurPoint.y = y3;
428 return;
429 }
430
431 void
CurveTo3(double x1,double y1,double x3,double y3)432 PdfContents::CurveTo3(double x1, double y1, double x3,
433 double y3)
434 {
435 if (fGMode != PDF_GMODE_PATH_OBJECT)
436 GMODE_ERROR("CurveTo3")
437
438 *GetStream() << x1 << ' '
439 << y1 << ' '
440 << x3 << ' '
441 << y3 << " y\012";
442 fCurPoint.x = x3;
443 fCurPoint.y = y3;
444 return;
445 }
446
447 void
ClosePath()448 PdfContents::ClosePath()
449 {
450 if (fGMode != PDF_GMODE_PATH_OBJECT)
451 GMODE_ERROR("ClosePath")
452
453 *GetStream() << "h\012";
454 fCurPoint = fStartPoint;
455 return;
456 }
457
458 void
Rectangle(double x,double y,double width,double height)459 PdfContents::Rectangle(double x, double y, double width,
460 double height)
461 {
462 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION && fGMode != PDF_GMODE_PATH_OBJECT)
463 GMODE_ERROR("Rectangle")
464
465 *GetStream() << x << ' '
466 << y << ' '
467 << width << ' '
468 << height << " re\012";
469 fCurPoint.x = x;
470 fCurPoint.y = y;
471 fGMode = PDF_GMODE_PATH_OBJECT;
472 return;
473 }
474
475 /*----- Path painting ----------------------------------------------*/
476
477 void
Stroke()478 PdfContents::Stroke()
479 {
480 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
481 GMODE_ERROR("Stroke")
482
483 *GetStream() << "S\012";
484 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
485 return;
486 }
487
488 void
ClosePathStroke()489 PdfContents::ClosePathStroke()
490 {
491 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
492 GMODE_ERROR("ClosePathStroke")
493
494 *GetStream() << "s\012";
495 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
496 return;
497 }
498
499 void
Fill()500 PdfContents::Fill()
501 {
502 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
503 GMODE_ERROR("Fill")
504
505 *GetStream() << "f\012";
506 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
507 return;
508 }
509
510 void
Eofill()511 PdfContents::Eofill()
512 {
513 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
514 GMODE_ERROR("Eofill")
515
516 *GetStream() << "f*\012";
517 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
518 return;
519 }
520
521 void
FillStroke()522 PdfContents::FillStroke()
523 {
524 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
525 GMODE_ERROR("FillStroke")
526
527 *GetStream() << "B\012";
528 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
529 return;
530 }
531
532 void
EofillStroke()533 PdfContents::EofillStroke()
534 {
535 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
536 GMODE_ERROR("EofillStroke")
537
538 *GetStream() << "B*\012";
539 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
540 return;
541 }
542
543 void
ClosePathFillStroke()544 PdfContents::ClosePathFillStroke()
545 {
546 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
547 GMODE_ERROR("ClosePathFillStroke")
548
549 *GetStream() << "b\012";
550 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
551 return;
552 }
553
554 void
ClosePathEofillStroke()555 PdfContents::ClosePathEofillStroke()
556 {
557 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
558 GMODE_ERROR("ClosePathEofillStroke")
559
560 *GetStream() << "b*\012";
561 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
562 return;
563 }
564
565 void
EndPath()566 PdfContents::EndPath()
567 {
568 if (fGMode != PDF_GMODE_PATH_OBJECT && fGMode != PDF_GMODE_CLIPPING_PATH)
569 GMODE_ERROR("EndPath")
570
571 *GetStream() << "n\012";
572 fCurPoint.x = 0; //
573 fCurPoint.y = 0; //
574 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
575 return;
576 }
577
578 /*----- Clipping paths ---------------------------------------------*/
579
580 void
Clip()581 PdfContents::Clip()
582 {
583 if (fGMode != PDF_GMODE_PATH_OBJECT)
584 GMODE_ERROR("Clip")
585
586 *GetStream() << "W\012";
587 fGMode = PDF_GMODE_CLIPPING_PATH;
588 return;
589 }
590
591 void
EoClip()592 PdfContents::EoClip()
593 {
594 if (fGMode != PDF_GMODE_PATH_OBJECT)
595 GMODE_ERROR("Eolip")
596
597 *GetStream() << "W*\012";
598 fGMode = PDF_GMODE_CLIPPING_PATH;
599 return;
600 }
601
602 /*----- Text object ------------------------------------------------*/
603
604 void
BeginText()605 PdfContents::BeginText()
606 {
607 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION)
608 GMODE_ERROR("BeginText")
609
610 fPage->AddProcSet(PDF_PROCSET_TEXT);
611
612 *GetStream() << "BT\012";
613 fTextPoint.x = 0;
614 fTextPoint.y = 0;
615 fMatrix = PdfTextMatrix(1, 0, 0, 1, 0, 0);
616
617 fGMode = PDF_GMODE_TEXT_OBJECT;
618 return;
619 }
620
621 void
EndText()622 PdfContents::EndText()
623 {
624 if (fGMode != PDF_GMODE_TEXT_OBJECT)
625 GMODE_ERROR("EndText")
626
627 *GetStream() << "ET\012";
628
629 fGMode = PDF_GMODE_PAGE_DESCRIPTION;
630 return;
631 }
632
633 /*----- Text state -------------------------------------------------*/
634
635 void
SetCharSpace(double value)636 PdfContents::SetCharSpace(double value)
637 {
638 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
639 GMODE_ERROR("SetCharSpace")
640
641 if (value < PDF_MIN_CHARSPACE || value > PDF_MAX_CHARSPACE)
642 throw PdfException(PDF_ERR_OUT_OF_RANGE,
643 "ERROR: SetCharSpace out of range(%f)", value);
644
645 *GetStream() << value << " "
646 << "Tc\012";
647 fCharSpace = value;
648 return;
649 }
650
651 void
SetWordSpace(double value)652 PdfContents::SetWordSpace(double value)
653 {
654 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
655 GMODE_ERROR("SetWordSpace")
656
657 if (value < PDF_MIN_WORDSPACE || value > PDF_MAX_WORDSPACE)
658 throw PdfException(PDF_ERR_OUT_OF_RANGE,
659 "ERROR: SetWordSpace out of range(%f)", value);
660
661 *GetStream() << value << " "
662 << "Tw\012";
663 fWordSpace = value;
664 return;
665 }
666
667 void
SetHorizontalScalling(double value)668 PdfContents::SetHorizontalScalling(double value)
669 {
670 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
671 GMODE_ERROR("SetHorizontalScalling")
672
673 if (value < PDF_MIN_HORIZONTALSCALING ||
674 value > PDF_MAX_HORIZONTALSCALING) {
675 throw PdfException(PDF_ERR_OUT_OF_RANGE,
676 "ERROR: SetHorizontalScalling out of range(%f)", value);
677 }
678
679 *GetStream() << value << " "
680 << "Tz\012";
681 fHScalling = value;
682 return;
683 }
684
685 void
SetTextLeading(double value)686 PdfContents::SetTextLeading(double value)
687 {
688 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
689 GMODE_ERROR("SetTextLeading")
690
691 *GetStream() << value << " "
692 << "TL\012";
693 fTextLeading = value;
694 return;
695 }
696
697 void
SetFontAndSize(const char * fontname,double size)698 PdfContents::SetFontAndSize(const char* fontname, double size)
699 {
700 assert(fFontMgr);
701
702 PdfFont* font = fFontMgr->GetFont(fontname);
703 if (font == NULL) {
704 throw PdfException(PDF_RUNTIME_ERROR,
705 "ERROR: font[%s] is not found.", fontname);
706 }
707
708 SetFontAndSize(font, size);
709 }
710
711 void
SetFontAndSize(PdfFont * font,double size)712 PdfContents::SetFontAndSize(PdfFont* font, double size)
713 {
714 if (font == NULL)
715 throw PdfException(PDF_RUNTIME_ERROR,
716 "ERROR: Invalid paramator[font].");
717 if (size <= 0)
718 throw PdfException(PDF_RUNTIME_ERROR,
719 "ERROR: Invalid font size[%f].", size);
720
721 fFont = font;
722 const char* local_fontname = fPage->GetFontName(font);
723 if (local_fontname != NULL)
724 WriteEscapeName(GetStream(), local_fontname);
725 else {
726 char tmp_fontname[20];
727
728 #ifdef __WIN32__
729 _snprintf(tmp_fontname, 20, "F%d", (int)fPage->CountFonts());
730 #else
731 snprintf(tmp_fontname, 20, "F%d", (int)fPage->CountFonts());
732 #endif
733
734 fPage->AddFont(font, tmp_fontname);
735 WriteEscapeName(GetStream(), tmp_fontname);
736 }
737
738 *GetStream() << " "
739 << size
740 << " Tf\012";
741
742 fFontSize = size;
743 return;
744 }
745
746 void
SetTextRenderingMode(pdf_text_rendering_mode mode)747 PdfContents::SetTextRenderingMode(pdf_text_rendering_mode mode)
748 {
749 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
750 GMODE_ERROR("SetTextRenderingMode")
751
752 *GetStream() << (int)mode
753 << " Tr\012";
754 fRenderingMode = mode;
755 return;
756 }
757
758 void
SetTextRaise(double value)759 PdfContents::SetTextRaise(double value)
760 {
761 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
762 GMODE_ERROR("SetTextRaise")
763
764 *GetStream() << value
765 << " Ts\012";
766 fTextRaise = value;
767 return;
768 }
769
770 /*--- Text positioning -----------------------------------------------------*/
771
772 void
MoveTextPos(double tx,double ty)773 PdfContents::MoveTextPos(double tx, double ty)
774 {
775 if (fGMode != PDF_GMODE_TEXT_OBJECT)
776 GMODE_ERROR("MoveTextPos")
777
778 *GetStream() << tx << " "
779 << ty
780 << " Td\012";
781 fMatrix.x += tx;
782 fMatrix.y += ty;
783 fTextPoint.x = fMatrix.x;
784 fTextPoint.y += ty;
785 return;
786 }
787
788 void
MoveTextPos2(double tx,double ty)789 PdfContents::MoveTextPos2(double tx, double ty)
790 {
791 if (fGMode != PDF_GMODE_TEXT_OBJECT)
792 GMODE_ERROR("MoveTextPos2")
793
794 *GetStream() << tx << " "
795 << ty
796 << " TD\012";
797 fMatrix.x += tx;
798 fMatrix.y += ty;
799 fTextPoint.x = fMatrix.x;
800 fTextPoint.y += ty;
801 fTextLeading = -ty;
802 return;
803 }
804
805 void
SetTextMatrix(double a,double b,double c,double d,double x,double y)806 PdfContents::SetTextMatrix(double a, double b, double c,
807 double d, double x, double y)
808 {
809 if (fGMode != PDF_GMODE_TEXT_OBJECT)
810 GMODE_ERROR("SetTextMatrix")
811
812 *GetStream() << a << " "
813 << b << " "
814 << c << " "
815 << d << " "
816 << x << " "
817 << y
818 << " Tm\012";
819 fMatrix.a = a;
820 fMatrix.b = b;
821 fMatrix.c = c;
822 fMatrix.d = d;
823 fMatrix.x = x;
824 fMatrix.y = y;
825 fTextPoint.x = fMatrix.x;
826 fTextPoint.y = fMatrix.y;
827 return;
828 }
829
830 void
MoveToNextLine()831 PdfContents::MoveToNextLine()
832 {
833 if (fGMode != PDF_GMODE_TEXT_OBJECT)
834 GMODE_ERROR("MoveToNextLine")
835
836 *GetStream() << "T*\012";
837
838 /* calculate the reference point of text */
839 fMatrix.x += fTextLeading * fMatrix.b;
840 fMatrix.y -= fTextLeading * fMatrix.a;
841
842 /* set text point to the start of new line. */
843 fTextPoint.x = fMatrix.x;
844 fTextPoint.y = fMatrix.y;
845
846 PDF_DEBUG_PRINT(("PdfContents::MoveToNextLine -- x=%f, y=%f\n"
847 , fTextPoint.x, fTextPoint.y));
848
849 return;
850 }
851
852 /*--- Text showing ---------------------------------------------------------*/
853 void
ShowText(const char * text)854 PdfContents::ShowText(const char* text)
855 {
856 if (fGMode != PDF_GMODE_TEXT_OBJECT)
857 GMODE_ERROR("ShowText")
858
859 if (text == NULL || strlen(text) < 1)
860 return;
861
862 WriteEscapeText(GetStream(), text);
863 *GetStream() << " Tj\012";
864
865 /* set text point to the end of this line */
866 double w = TextWidth(text);
867
868 if (fFont->WritingMode() == PDF_WMODE_HORIZONTAL) {
869 fTextPoint.x += w * fMatrix.a;
870 fTextPoint.y += w * fMatrix.b;
871 } else {
872 fTextPoint.y -= w * fMatrix.a;
873 fTextPoint.x -= w * fMatrix.b;
874 }
875 return;
876 }
877
878 void
ShowTextNextLine(const char * text)879 PdfContents::ShowTextNextLine(const char* text)
880 {
881 if (fGMode != PDF_GMODE_TEXT_OBJECT)
882 GMODE_ERROR("ShowTextNextLine")
883
884 if (text == NULL || strlen(text) < 1)
885 return;
886
887 /* calculate the reference point of text. */
888 fMatrix.x += fTextLeading * fMatrix.b;
889 fMatrix.y -= fTextLeading * fMatrix.a;
890
891 /* set text point to the start of new line. */
892 fTextPoint.x = fMatrix.x;
893 fTextPoint.y = fMatrix.y;
894
895 WriteEscapeText(GetStream(), text);
896 *GetStream() << " '\012";
897
898 /* set text point to the end of this line */
899 double w = TextWidth(text);
900
901 if (fFont->WritingMode() == PDF_WMODE_HORIZONTAL) {
902 fTextPoint.x += w * fMatrix.a;
903 fTextPoint.y += w * fMatrix.b;
904 } else {
905 fTextPoint.y -= w * fMatrix.a;
906 fTextPoint.x -= w * fMatrix.b;
907 }
908
909 return;
910 }
911
912 void
ShowTextNextLine(double aw,double ac,const char * text)913 PdfContents::ShowTextNextLine(double aw, double ac,
914 const char* text)
915 {
916 if (fGMode != PDF_GMODE_TEXT_OBJECT)
917 GMODE_ERROR("ShowTextNextLine")
918
919 if (text == NULL || strlen(text) < 1)
920 return;
921
922 fWordSpace = aw;
923 fCharSpace = ac;
924
925 /* calculate the reference point of text */
926 fMatrix.x += fTextLeading * fMatrix.b;
927 fMatrix.y -= fTextLeading * fMatrix.a;
928
929 /* set text point to the start of new line. */
930 fTextPoint.x = fMatrix.x;
931 fTextPoint.y = fMatrix.y;
932
933 *GetStream() << aw << " "
934 << ac << " ";
935 WriteEscapeText(GetStream(), text);
936 *GetStream() << " \"\012";
937
938 /* set text point to the end of this line */
939 double w = TextWidth(text);
940
941 if (fFont->WritingMode() == PDF_WMODE_HORIZONTAL) {
942 fTextPoint.x += w * fMatrix.a;
943 fTextPoint.y += w * fMatrix.b;
944 } else {
945 fTextPoint.y -= w * fMatrix.a;
946 fTextPoint.x -= w * fMatrix.b;
947 }
948
949 return;
950 }
951
952 /*--- Color showing --------------------------------------------------------*/
953
954 void
SetGrayFill(double gray)955 PdfContents::SetGrayFill(double gray)
956 {
957 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
958 GMODE_ERROR("SetGrayFill")
959
960 if (gray < 0 || gray > 1)
961 throw PdfException(PDF_ERR_OUT_OF_RANGE,
962 "ERROR: SetGrayFill out of range(%f)", gray);
963
964 *GetStream() << gray
965 << " g\012";
966
967 fGrayFill = gray;
968
969 return;
970 }
971
972 void
SetGrayStroke(double gray)973 PdfContents::SetGrayStroke(double gray)
974 {
975 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
976 GMODE_ERROR("SetGrayStroke")
977
978 if (gray < 0 || gray > 1)
979 throw PdfException(PDF_ERR_OUT_OF_RANGE,
980 "ERROR: SetGrayStroke out of range(%f).", gray);
981
982 *GetStream() << gray
983 << " G\012";
984
985 fGrayStroke = gray;
986
987 return;
988 }
989
990 void
SetRGBFill(int r,int g,int b)991 PdfContents::SetRGBFill(int r, int g, int b)
992 {
993 SetRGBFill((double)r / 255, (double)g / 255, (double)b / 255);
994 }
995
996 void
SetRGBFill(double r,double g,double b)997 PdfContents::SetRGBFill(double r, double g, double b)
998 {
999 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
1000 GMODE_ERROR("SetRGBFill")
1001
1002 if (r < 0 || r > 1 ||
1003 g < 0 || g > 1 ||
1004 b < 0 || b > 1) {
1005 throw PdfException(PDF_ERR_OUT_OF_RANGE,
1006 "ERROR: SetRGBFill out of range(%f:%f:%f).", r, g, b);
1007 }
1008
1009 fRGBFill.red = r;
1010 fRGBFill.green = g;
1011 fRGBFill.blue = b;
1012
1013 *GetStream() << r
1014 << " "
1015 << g
1016 << " "
1017 << b
1018 << " rg\012";
1019
1020 return;
1021 }
1022
1023 void
SetRGBStroke(int r,int g,int b)1024 PdfContents::SetRGBStroke(int r, int g, int b)
1025 {
1026 SetRGBStroke((double)r / 255, (double)g / 255, (double)b / 255);
1027 }
1028
1029 void
SetRGBStroke(double r,double g,double b)1030 PdfContents::SetRGBStroke(double r, double g, double b)
1031 {
1032 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
1033 GMODE_ERROR("SetRGBStroke")
1034
1035 if (r < 0 || r > 1 ||
1036 g < 0 || g > 1 ||
1037 b < 0 || b > 1) {
1038 throw PdfException(PDF_ERR_OUT_OF_RANGE,
1039 "ERROR: SetRGBStroke out of range(%f:%f:%f).", r, g, b);
1040 }
1041
1042 fRGBStroke.red = r;
1043 fRGBStroke.green = g;
1044 fRGBStroke.blue = b;
1045
1046 *GetStream() << r
1047 << " "
1048 << g
1049 << " "
1050 << b
1051 << " RG\012";
1052
1053 return;
1054 }
1055
1056 void
SetCMYKFill(double c,double m,double y,double k)1057 PdfContents::SetCMYKFill(double c, double m, double y, double k)
1058 {
1059 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
1060 GMODE_ERROR("SetCMYKFill")
1061
1062 if (c < 0 || c > 1 ||
1063 m < 0 || m > 1 ||
1064 y < 0 || y > 1 ||
1065 k < 0 || k > 1) {
1066 throw PdfException(PDF_ERR_OUT_OF_RANGE,
1067 "ERROR: SetCYMKFill out of range(%f:%f:%f:%f).", c, m, y, k);
1068 }
1069
1070 *GetStream() << c
1071 << " "
1072 << m
1073 << " "
1074 << y
1075 << " "
1076 << k
1077 << " k\012";
1078
1079 return;
1080 }
1081
1082 void
SetCMYKStroke(double c,double m,double y,double k)1083 PdfContents::SetCMYKStroke(double c, double m, double y, double k)
1084 {
1085 if (fGMode != PDF_GMODE_TEXT_OBJECT && fGMode != PDF_GMODE_PAGE_DESCRIPTION)
1086 GMODE_ERROR("SetCMYKStroke")
1087
1088 if (c < 0 || c > 1 ||
1089 m < 0 || m > 1 ||
1090 y < 0 || y > 1 ||
1091 k < 0 || k > 1) {
1092 throw PdfException(PDF_ERR_OUT_OF_RANGE,
1093 "ERROR: SetCMYKStroke out of range(%f:%f:%f:%f).", c, m, y, k);
1094 }
1095
1096 *GetStream() << c
1097 << " "
1098 << m
1099 << " "
1100 << y
1101 << " "
1102 << k
1103 << " K\012";
1104
1105 return;
1106 }
1107
1108 /*----------------------------------------------------------------------------*/
1109 /*------ XObjects ------------------------------------------------------------*/
1110
1111 void
ExecuteXObject(const char * name)1112 PdfContents::ExecuteXObject(const char *name)
1113 {
1114 assert(fXObjectMgr);
1115
1116 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION)
1117 GMODE_ERROR("ExecuteXObject")
1118
1119 /* find x-object from XObjectManager by name */
1120 PdfXObject* obj = fXObjectMgr->GetXObject(name);
1121 if (obj == NULL)
1122 throw PdfException(PDF_RUNTIME_ERROR,
1123 "ERROR: XObject[%s] is not found.", name);
1124
1125 ExecuteXObject(obj);
1126 }
1127
1128 void
ExecuteXObject(PdfXObject * obj)1129 PdfContents::ExecuteXObject(PdfXObject* obj)
1130 {
1131 assert(fXObjectMgr);
1132
1133 if (fGMode != PDF_GMODE_PAGE_DESCRIPTION)
1134 GMODE_ERROR("ExecuteXObject");
1135
1136 /* check the xobject is valid or not. */
1137 if (obj == NULL || obj->Name() == NULL)
1138 throw PdfException(PDF_RUNTIME_ERROR,
1139 "ERROR: Invalid XObject.");
1140
1141 /* get the local-name which is used in page-object */
1142 const char* local_name = fPage->GetXObjectName(obj);
1143
1144 if (local_name != NULL)
1145 WriteEscapeName(GetStream(), local_name);
1146 else {
1147 fPage->AddXObject(obj, obj->Name());
1148 WriteEscapeName(GetStream(), obj->Name());
1149 }
1150
1151 *GetStream() << " Do\012";
1152 }
1153
1154 /*----------------------------------------------------------------------------*/
1155
1156