1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/generic/dcpsg.cpp
3
// Purpose: Generic wxPostScriptDC implementation
4
// Author: Julian Smart, Robert Roebling, Markus Holzhem
7
// Copyright: (c) Julian Smart
8
// Licence: wxWindows licence
9
/////////////////////////////////////////////////////////////////////////////
11
#include "wx/wxprec.h"
17
#if wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT
19
#include "wx/generic/dcpsg.h"
25
#include "wx/dcmemory.h"
31
#include "wx/prntbase.h"
32
#include "wx/generic/prntdlgg.h"
34
#include "wx/filename.h"
35
#include "wx/stdpaths.h"
57
//-----------------------------------------------------------------------------
58
// start and end of document/page
59
//-----------------------------------------------------------------------------
61
static const char *wxPostScriptHeaderConicTo = "\
65
/conic_cntrl_y exch def\n\
66
/conic_cntrl_x exch def\n\
70
/p1_x p0_x conic_cntrl_x p0_x sub 2 3 div mul add def\n\
71
/p1_y p0_y conic_cntrl_y p0_y sub 2 3 div mul add def\n\
72
/p2_x p1_x to_x p0_x sub 1 3 div mul add def\n\
73
/p2_y p1_y to_y p0_y sub 1 3 div mul add def\n\
74
p1_x p1_y p2_x p2_y to_x to_y curveto\n\
78
static const char *wxPostScriptHeaderEllipse = "\
79
/ellipsedict 8 dict def\n\
80
ellipsedict /mtrx matrix put\n\
84
/startangle exch def\n\
89
/savematrix mtrx currentmatrix def\n\
92
0 0 1 startangle endangle arc\n\
93
savematrix setmatrix\n\
98
static const char *wxPostScriptHeaderEllipticArc= "\
99
/ellipticarcdict 8 dict def\n\
100
ellipticarcdict /mtrx matrix put\n\
102
{ ellipticarcdict begin\n\
104
/endangle exch def\n\
105
/startangle exch def\n\
110
/savematrix mtrx currentmatrix def\n\
113
do_fill { 0 0 moveto } if\n\
114
0 0 1 startangle endangle arc\n\
115
savematrix setmatrix\n\
116
do_fill { fill }{ stroke } ifelse\n\
120
static const char *wxPostScriptHeaderSpline = "\
121
/DrawSplineSection {\n\
128
/xa x1 x2 x1 sub 0.666667 mul add def\n\
129
/ya y1 y2 y1 sub 0.666667 mul add def\n\
130
/xb x3 x2 x3 sub 0.666667 mul add def\n\
131
/yb y3 y2 y3 sub 0.666667 mul add def\n\
133
xa ya xb yb x3 y3 curveto\n\
137
static const char *wxPostScriptHeaderColourImage = "\
138
% define 'colorimage' if it isn't defined\n\
139
% ('colortogray' and 'mergeprocs' come from xwd2ps\n\
141
/colorimage where % do we know about 'colorimage'?\n\
142
{ pop } % yes: pop off the 'dict' returned\n\
143
{ % no: define one\n\
144
/colortogray { % define an RGB->I function\n\
145
/rgbdata exch store % call input 'rgbdata'\n\
146
rgbdata length 3 idiv\n\
147
/npixls exch store\n\
149
0 1 npixls 1 sub {\n\
151
rgbdata rgbindx get 20 mul % Red\n\
152
rgbdata rgbindx 1 add get 32 mul % Green\n\
153
rgbdata rgbindx 2 add get 12 mul % Blue\n\
154
add add 64 idiv % I = .5G + .31R + .18B\n\
156
/rgbindx rgbindx 3 add store\n\
158
grays 0 npixls getinterval\n\
161
% Utility procedure for colorimage operator.\n\
162
% This procedure takes two procedures off the\n\
163
% stack and merges them into a single procedure.\n\
165
/mergeprocs { % def\n\
184
/colorimage { % def\n\
185
pop pop % remove 'false 3' operands\n\
186
{colortogray} mergeprocs\n\
189
} ifelse % end of 'false' case\n\
192
static const char wxPostScriptHeaderReencodeISO1[] =
194
"dup dup findfont dup length dict begin\n"
195
"{ 1 index /FID ne { def }{ pop pop } ifelse } forall\n"
196
"/Encoding ISOLatin1Encoding def\n"
197
"currentdict end definefont\n"
199
"/ISOLatin1Encoding [\n"
200
"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
201
"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
202
"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
203
"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
204
"/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright\n"
205
"/parenleft/parenright/asterisk/plus/comma/minus/period/slash\n"
206
"/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon\n"
207
"/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N\n"
208
"/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright\n"
209
"/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m\n"
210
"/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde\n"
211
"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
212
"/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef\n"
213
"/.notdef/dotlessi/grave/acute/circumflex/tilde/macron/breve\n"
214
"/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut\n";
216
static const char wxPostScriptHeaderReencodeISO2[] =
217
"/ogonek/caron/space/exclamdown/cent/sterling/currency/yen/brokenbar\n"
218
"/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot\n"
219
"/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior\n"
220
"/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine\n"
221
"/guillemotright/onequarter/onehalf/threequarters/questiondown\n"
222
"/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla\n"
223
"/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex\n"
224
"/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis\n"
225
"/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute\n"
226
"/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis\n"
227
"/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave\n"
228
"/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex\n"
229
"/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis\n"
230
"/yacute/thorn/ydieresis\n"
233
//-------------------------------------------------------------------------------
235
//-------------------------------------------------------------------------------
238
IMPLEMENT_DYNAMIC_CLASS(wxPostScriptDC, wxDC)
240
wxPostScriptDC::wxPostScriptDC()
241
: wxDC(new wxPostScriptDCImpl(this))
245
wxPostScriptDC::wxPostScriptDC(const wxPrintData& printData)
246
: wxDC(new wxPostScriptDCImpl(this, printData))
251
static const double RAD2DEG = 180.0 / M_PI;
253
// we don't want to use only 72 dpi from PS print
254
static const int DPI = 600;
255
static const double PS2DEV = 600.0 / 72.0;
256
static const double DEV2PS = 72.0 / 600.0;
258
#define XLOG2DEV(x) ((double)(LogicalToDeviceX(x)) * DEV2PS)
259
#define XLOG2DEVREL(x) ((double)(LogicalToDeviceXRel(x)) * DEV2PS)
260
#define YLOG2DEV(x) ((m_pageHeight - (double)LogicalToDeviceY(x)) * DEV2PS)
261
#define YLOG2DEVREL(x) ((double)(LogicalToDeviceYRel(x)) * DEV2PS)
264
IMPLEMENT_ABSTRACT_CLASS(wxPostScriptDCImpl, wxDCImpl)
266
//-------------------------------------------------------------------------------
268
wxPostScriptDCImpl::wxPostScriptDCImpl( wxPostScriptDC *owner ) :
273
m_pageHeight = 842 * PS2DEV;
278
wxPostScriptDCImpl::wxPostScriptDCImpl( wxPostScriptDC *owner, const wxPrintData& data ) :
283
// this calculates m_pageHeight required for
284
// taking the inverted Y axis into account
285
SetPrintData( data );
291
wxPostScriptDCImpl::wxPostScriptDCImpl( wxPrinterDC *owner ) :
296
m_pageHeight = 842 * PS2DEV;
301
wxPostScriptDCImpl::wxPostScriptDCImpl( wxPrinterDC *owner, const wxPrintData& data ) :
306
// this calculates m_pageHeight required for
307
// taking the inverted Y axis into account
308
SetPrintData( data );
313
void wxPostScriptDCImpl::Init()
325
m_underlinePosition = 0.0;
326
m_underlineThickness = 0.0;
330
wxPostScriptDCImpl::~wxPostScriptDCImpl ()
339
bool wxPostScriptDCImpl::IsOk() const
344
wxRect wxPostScriptDCImpl::GetPaperRect() const
349
return wxRect(0,0,w,h);
352
int wxPostScriptDCImpl::GetResolution() const
357
void wxPostScriptDCImpl::DoSetClippingRegion (wxCoord x, wxCoord y, wxCoord w, wxCoord h)
359
wxCHECK_RET( m_ok , wxT("invalid postscript dc") );
362
DestroyClippingRegion();
372
buffer.Printf( "gsave\n"
378
"closepath clip newpath\n",
379
XLOG2DEV(x), YLOG2DEV(y),
380
XLOG2DEV(x+w), YLOG2DEV(y),
381
XLOG2DEV(x+w), YLOG2DEV(y+h),
382
XLOG2DEV(x), YLOG2DEV(y+h) );
383
buffer.Replace( ",", "." );
388
void wxPostScriptDCImpl::DestroyClippingRegion()
390
wxCHECK_RET( m_ok , wxT("invalid postscript dc") );
395
PsPrint( "grestore\n" );
398
wxDCImpl::DestroyClippingRegion();
401
void wxPostScriptDCImpl::Clear()
403
// This should fail silently to avoid unnecessary
405
// wxFAIL_MSG( wxT("wxPostScriptDCImpl::Clear not implemented.") );
408
bool wxPostScriptDCImpl::DoFloodFill (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour &WXUNUSED(col), wxFloodFillStyle WXUNUSED(style))
410
wxFAIL_MSG( wxT("wxPostScriptDCImpl::FloodFill not implemented.") );
414
bool wxPostScriptDCImpl::DoGetPixel (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour * WXUNUSED(col)) const
416
wxFAIL_MSG( wxT("wxPostScriptDCImpl::GetPixel not implemented.") );
420
void wxPostScriptDCImpl::DoCrossHair (wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
422
wxFAIL_MSG( wxT("wxPostScriptDCImpl::CrossHair not implemented.") );
425
void wxPostScriptDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
427
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
429
if ( m_pen.IsTransparent() )
435
buffer.Printf( "newpath\n"
439
XLOG2DEV(x1), YLOG2DEV(y1),
440
XLOG2DEV(x2), YLOG2DEV(y2) );
441
buffer.Replace( ",", "." );
444
CalcBoundingBox( x1, y1 );
445
CalcBoundingBox( x2, y2 );
448
void wxPostScriptDCImpl::DoDrawArc (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
450
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
452
wxCoord dx = x1 - xc;
453
wxCoord dy = y1 - yc;
454
double radius = sqrt( (double)(dx*dx+dy*dy) );
455
double alpha1, alpha2;
457
if (x1 == x2 && y1 == y2)
462
else if ( wxIsNullDouble(radius) )
469
alpha1 = (x1 - xc == 0) ?
470
(y1 - yc < 0) ? 90.0 : -90.0 :
471
-atan2(double(y1-yc), double(x1-xc)) * RAD2DEG;
472
alpha2 = (x2 - xc == 0) ?
473
(y2 - yc < 0) ? 90.0 : -90.0 :
474
-atan2(double(y2-yc), double(x2-xc)) * RAD2DEG;
476
while (alpha1 <= 0) alpha1 += 360;
477
while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between
478
while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree
479
while (alpha2 > 360) alpha2 -= 360;
481
int i_radius = wxRound( radius );
483
if ( m_brush.IsNonTransparent() )
488
buffer.Printf( "newpath\n"
489
"%f %f %f %f %f %f ellipse\n"
493
XLOG2DEV(xc), YLOG2DEV(yc),
494
XLOG2DEVREL(i_radius), YLOG2DEVREL(i_radius),
496
XLOG2DEV(xc), YLOG2DEV(yc) );
497
buffer.Replace( ",", "." );
500
CalcBoundingBox( xc-i_radius, yc-i_radius );
501
CalcBoundingBox( xc+i_radius, yc+i_radius );
504
if ( m_pen.IsNonTransparent() )
509
buffer.Printf( "newpath\n"
510
"%f %f %f %f %f %f ellipse\n"
512
XLOG2DEV(xc), YLOG2DEV(yc),
513
XLOG2DEVREL(i_radius), YLOG2DEVREL(i_radius),
515
buffer.Replace( ",", "." );
518
CalcBoundingBox( xc-i_radius, yc-i_radius );
519
CalcBoundingBox( xc+i_radius, yc+i_radius );
523
void wxPostScriptDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
525
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
527
if ( sa >= 360 || sa <= -360 )
528
sa -= int(sa/360)*360;
529
if ( ea >= 360 || ea <=- 360 )
530
ea -= int(ea/360)*360;
536
if ( wxIsSameDouble(sa, ea) )
538
DoDrawEllipse(x,y,w,h);
542
if ( m_brush.IsNonTransparent() )
547
buffer.Printf( "newpath\n"
548
"%f %f %f %f %f %f true ellipticarc\n",
549
XLOG2DEV(x+w/2), YLOG2DEV(y+h/2),
550
XLOG2DEVREL(w/2), YLOG2DEVREL(h/2),
552
buffer.Replace( ",", "." );
555
CalcBoundingBox( x ,y );
556
CalcBoundingBox( x+w, y+h );
559
if ( m_pen.IsNonTransparent() )
564
buffer.Printf( "newpath\n"
565
"%f %f %f %f %f %f false ellipticarc\n",
566
XLOG2DEV(x+w/2), YLOG2DEV(y+h/2),
567
XLOG2DEVREL(w/2), YLOG2DEVREL(h/2),
569
buffer.Replace( ",", "." );
572
CalcBoundingBox( x ,y );
573
CalcBoundingBox( x+w, y+h );
577
void wxPostScriptDCImpl::DoDrawPoint (wxCoord x, wxCoord y)
579
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
581
if ( m_pen.IsTransparent() )
587
buffer.Printf( "newpath\n"
591
XLOG2DEV(x), YLOG2DEV(y),
592
XLOG2DEV(x+1), YLOG2DEV(y) );
593
buffer.Replace( ",", "." );
596
CalcBoundingBox( x, y );
599
void wxPostScriptDCImpl::DoDrawPolygon (int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset, wxPolygonFillMode fillStyle)
601
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
605
if ( m_brush.IsNonTransparent() )
609
PsPrint( "newpath\n" );
611
double xx = XLOG2DEV(points[0].x + xoffset);
612
double yy = YLOG2DEV(points[0].y + yoffset);
615
buffer.Printf( "%f %f moveto\n", xx, yy );
616
buffer.Replace( ",", "." );
619
CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
621
for (int i = 1; i < n; i++)
623
xx = XLOG2DEV(points[i].x + xoffset);
624
yy = YLOG2DEV(points[i].y + yoffset);
626
buffer.Printf( "%f %f lineto\n", xx, yy );
627
buffer.Replace( ",", "." );
630
CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
633
PsPrint( (fillStyle == wxODDEVEN_RULE ? "eofill\n" : "fill\n") );
636
if ( m_pen.IsNonTransparent() )
640
PsPrint( "newpath\n" );
642
double xx = XLOG2DEV(points[0].x + xoffset);
643
double yy = YLOG2DEV(points[0].y + yoffset);
646
buffer.Printf( "%f %f moveto\n", xx, yy );
647
buffer.Replace( ",", "." );
650
CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset );
652
for (int i = 1; i < n; i++)
654
xx = XLOG2DEV(points[i].x + xoffset);
655
yy = YLOG2DEV(points[i].y + yoffset);
657
buffer.Printf( "%f %f lineto\n", xx, yy );
658
buffer.Replace( ",", "." );
661
CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset);
664
PsPrint( "closepath\n" );
665
PsPrint( "stroke\n" );
669
void wxPostScriptDCImpl::DoDrawPolyPolygon (int n, const int count[], const wxPoint points[], wxCoord xoffset, wxCoord yoffset, wxPolygonFillMode fillStyle)
671
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
675
if ( m_brush.IsNonTransparent() )
679
PsPrint( "newpath\n" );
682
for (int i = 0; i < n; ofs += count[i++])
684
double xx = XLOG2DEV(points[ofs].x + xoffset);
685
double yy = YLOG2DEV(points[ofs].y + yoffset);
688
buffer.Printf( "%f %f moveto\n", xx, yy );
689
buffer.Replace( ",", "." );
692
CalcBoundingBox( points[ofs].x + xoffset, points[ofs].y + yoffset );
694
for (int j = 1; j < count[i]; j++)
696
xx = XLOG2DEV(points[ofs+j].x + xoffset);
697
yy = YLOG2DEV(points[ofs+j].y + yoffset);
699
buffer.Printf( "%f %f lineto\n", xx, yy );
700
buffer.Replace( ",", "." );
703
CalcBoundingBox( points[ofs+j].x + xoffset, points[ofs+j].y + yoffset);
706
PsPrint( (fillStyle == wxODDEVEN_RULE ? "eofill\n" : "fill\n") );
709
if ( m_pen.IsNonTransparent() )
713
PsPrint( "newpath\n" );
716
for (int i = 0; i < n; ofs += count[i++])
718
double xx = XLOG2DEV(points[ofs].x + xoffset);
719
double yy = YLOG2DEV(points[ofs].y + yoffset);
722
buffer.Printf( "%f %f moveto\n", xx, yy );
723
buffer.Replace( ",", "." );
726
CalcBoundingBox( points[ofs].x + xoffset, points[ofs].y + yoffset );
728
for (int j = 1; j < count[i]; j++)
730
xx = XLOG2DEV(points[ofs+j].x + xoffset);
731
yy = YLOG2DEV(points[ofs+j].y + yoffset);
733
buffer.Printf( "%f %f lineto\n", xx, yy );
734
buffer.Replace( ",", "." );
737
CalcBoundingBox( points[ofs+j].x + xoffset, points[ofs+j].y + yoffset);
740
PsPrint( "closepath\n" );
741
PsPrint( "stroke\n" );
745
void wxPostScriptDCImpl::DoDrawLines (int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset)
747
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
749
if ( m_pen.IsTransparent() )
757
for ( i =0; i<n ; i++ )
758
CalcBoundingBox( points[i].x+xoffset, points[i].y+yoffset );
761
buffer.Printf( "newpath\n"
763
XLOG2DEV(points[0].x+xoffset),
764
YLOG2DEV(points[0].y+yoffset) );
765
buffer.Replace( ",", "." );
768
for (i = 1; i < n; i++)
770
buffer.Printf( "%f %f lineto\n",
771
XLOG2DEV(points[i].x+xoffset),
772
YLOG2DEV(points[i].y+yoffset) );
773
buffer.Replace( ",", "." );
777
PsPrint( "stroke\n" );
780
void wxPostScriptDCImpl::DoDrawRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
782
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
787
if ( m_brush.IsNonTransparent() )
792
buffer.Printf( "newpath\n"
799
XLOG2DEV(x), YLOG2DEV(y),
800
XLOG2DEV(x + width), YLOG2DEV(y),
801
XLOG2DEV(x + width), YLOG2DEV(y + height),
802
XLOG2DEV(x), YLOG2DEV(y + height) );
803
buffer.Replace( ",", "." );
806
CalcBoundingBox( x, y );
807
CalcBoundingBox( x + width, y + height );
810
if ( m_pen.IsNonTransparent() )
815
buffer.Printf( "newpath\n"
822
XLOG2DEV(x), YLOG2DEV(y),
823
XLOG2DEV(x + width), YLOG2DEV(y),
824
XLOG2DEV(x + width), YLOG2DEV(y + height),
825
XLOG2DEV(x), YLOG2DEV(y + height) );
826
buffer.Replace( ",", "." );
829
CalcBoundingBox( x, y );
830
CalcBoundingBox( x + width, y + height );
834
void wxPostScriptDCImpl::DoDrawRoundedRectangle (wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
836
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
843
// Now, a negative radius is interpreted to mean
844
// 'the proportion of the smallest X or Y dimension'
845
double smallest = width < height ? width : height;
846
radius = (-radius * smallest);
849
wxCoord rad = (wxCoord) radius;
851
if ( m_brush.IsNonTransparent() )
855
/* Draw rectangle anticlockwise */
857
buffer.Printf( "newpath\n"
858
"%f %f %f 90 180 arc\n"
860
"%f %f %f 180 270 arc\n"
862
"%f %f %f 270 0 arc\n"
864
"%f %f %f 0 90 arc\n"
868
XLOG2DEV(x + rad), YLOG2DEV(y + rad), XLOG2DEVREL(rad),
869
XLOG2DEV(x), YLOG2DEV(y + height - rad),
870
XLOG2DEV(x + rad), YLOG2DEV(y + height - rad), XLOG2DEVREL(rad),
871
XLOG2DEV(x + width - rad), YLOG2DEV(y + height),
872
XLOG2DEV(x + width - rad), YLOG2DEV(y + height - rad), XLOG2DEVREL(rad),
873
XLOG2DEV(x + width), YLOG2DEV(y + rad),
874
XLOG2DEV(x + width - rad), YLOG2DEV(y + rad), XLOG2DEVREL(rad),
875
XLOG2DEV(x + rad), YLOG2DEV(y) );
876
buffer.Replace( ",", "." );
879
CalcBoundingBox( x, y );
880
CalcBoundingBox( x + width, y + height );
883
if ( m_pen.IsNonTransparent() )
887
/* Draw rectangle anticlockwise */
889
buffer.Printf( "newpath\n"
890
"%f %f %f 90 180 arc\n"
892
"%f %f %f 180 270 arc\n"
894
"%f %f %f 270 0 arc\n"
896
"%f %f %f 0 90 arc\n"
900
XLOG2DEV(x + rad), YLOG2DEV(y + rad), XLOG2DEVREL(rad),
901
XLOG2DEV(x), YLOG2DEV(y + height - rad),
902
XLOG2DEV(x + rad), YLOG2DEV(y + height - rad), XLOG2DEVREL(rad),
903
XLOG2DEV(x + width - rad), YLOG2DEV(y + height),
904
XLOG2DEV(x + width - rad), YLOG2DEV(y + height - rad), XLOG2DEVREL(rad),
905
XLOG2DEV(x + width), YLOG2DEV(y + rad),
906
XLOG2DEV(x + width - rad), YLOG2DEV(y + rad), XLOG2DEVREL(rad),
907
XLOG2DEV(x + rad), YLOG2DEV(y) );
908
buffer.Replace( ",", "." );
911
CalcBoundingBox( x, y );
912
CalcBoundingBox( x + width, y + height );
916
void wxPostScriptDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
918
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
923
if ( m_brush.IsNonTransparent() )
928
buffer.Printf( "newpath\n"
929
"%f %f %f %f 0 360 ellipse\n"
931
XLOG2DEV(x + width / 2), YLOG2DEV(y + height / 2),
932
XLOG2DEVREL(width / 2), YLOG2DEVREL(height / 2) );
933
buffer.Replace( ",", "." );
936
CalcBoundingBox( x - width, y - height );
937
CalcBoundingBox( x + width, y + height );
940
if ( m_pen.IsNonTransparent() )
945
buffer.Printf( "newpath\n"
946
"%f %f %f %f 0 360 ellipse\n"
948
XLOG2DEV(x + width / 2), YLOG2DEV(y + height / 2),
949
XLOG2DEVREL(width / 2), YLOG2DEVREL(height / 2) );
950
buffer.Replace( ",", "." );
953
CalcBoundingBox( x - width, y - height );
954
CalcBoundingBox( x + width, y + height );
958
void wxPostScriptDCImpl::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y )
960
DoDrawBitmap( icon, x, y, true );
963
/* this has to be char, not wxChar */
964
static const char hexArray[] = "0123456789ABCDEF";
966
void wxPostScriptDCImpl::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool WXUNUSED(useMask) )
968
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
970
if (!bitmap.IsOk()) return;
972
wxImage image = bitmap.ConvertToImage();
974
if (!image.IsOk()) return;
976
wxCoord w = image.GetWidth();
977
wxCoord h = image.GetHeight();
979
double ww = XLOG2DEVREL(image.GetWidth());
980
double hh = YLOG2DEVREL(image.GetHeight());
982
double xx = XLOG2DEV(x);
983
double yy = YLOG2DEV(y + bitmap.GetHeight());
986
buffer.Printf( "/origstate save def\n"
988
"/pix %d string def\n"
989
"/grays %d string def\n"
996
"{currentfile pix readhexstring pop}\n"
997
"false 3 colorimage\n",
998
w, w, xx, yy, ww, hh, w, h, w, -h, h );
999
buffer.Replace( ",", "." );
1002
unsigned char* data = image.GetData();
1004
// size of the buffer = width*rgb(3)*hexa(2)+'\n'
1005
wxCharBuffer charbuffer(w*6 + 1);
1006
int firstDigit, secondDigit;
1009
for (int j = 0; j < h; j++)
1011
char* bufferindex = charbuffer.data();
1014
for (int i = 0; i < w*3; i++)
1016
firstDigit = (int)(*data/16.0);
1017
secondDigit = (int)(*data - (firstDigit*16.0));
1018
*(bufferindex++) = hexArray[firstDigit];
1019
*(bufferindex++) = hexArray[secondDigit];
1023
*(bufferindex++) = '\n';
1027
fwrite( charbuffer, 1, strlen( charbuffer ), m_pstream );
1029
PsPrint( charbuffer );
1033
PsPrint( "origstate restore\n" );
1036
void wxPostScriptDCImpl::SetFont( const wxFont& font )
1038
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1040
if (!font.IsOk()) return;
1044
int Style = m_font.GetStyle();
1045
int Weight = m_font.GetWeight();
1048
switch (m_font.GetFamily())
1053
if (Style == wxITALIC)
1055
if (Weight == wxBOLD)
1056
name = "/Courier-BoldOblique";
1058
name = "/Courier-Oblique";
1062
if (Weight == wxBOLD)
1063
name = "/Courier-Bold";
1071
if (Style == wxITALIC)
1073
if (Weight == wxBOLD)
1074
name = "/Times-BoldItalic";
1076
name = "/Times-Italic";
1080
if (Weight == wxBOLD)
1081
name = "/Times-Bold";
1083
name = "/Times-Roman";
1089
name = "/ZapfChancery-MediumItalic";
1095
if (Style == wxITALIC)
1097
if (Weight == wxBOLD)
1098
name = "/Helvetica-BoldOblique";
1100
name = "/Helvetica-Oblique";
1104
if (Weight == wxBOLD)
1105
name = "/Helvetica-Bold";
1107
name = "/Helvetica";
1113
// We may legitimately call SetFont before BeginDoc
1118
PsPrint( " reencodeISO def\n" );
1120
PsPrint( " findfont\n" );
1123
float size = float(m_font.GetPointSize());
1124
size = size * GetFontPointSizeAdjustment(DPI);
1126
buffer.Printf( "%f scalefont setfont\n", size * m_scaleX );
1127
buffer.Replace( ",", "." );
1131
void wxPostScriptDCImpl::SetPen( const wxPen& pen )
1133
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1135
if (!pen.IsOk()) return;
1137
int oldStyle = m_pen.IsOk() ? m_pen.GetStyle() : wxPENSTYLE_INVALID;
1138
wxPenCap oldCap = m_pen.IsOk() ? m_pen.GetCap() : wxCAP_INVALID;
1139
wxPenJoin oldJoin = m_pen.IsOk() ? m_pen.GetJoin() : wxJOIN_INVALID;
1142
wxPenCap cap = m_pen.IsOk() ? m_pen.GetCap() : wxCAP_INVALID;
1143
wxPenJoin join = m_pen.IsOk() ? m_pen.GetJoin() : wxJOIN_INVALID;
1147
if (m_pen.GetWidth() <= 0)
1150
width = (double) m_pen.GetWidth();
1153
buffer.Printf( "%f setlinewidth\n", width * DEV2PS * m_scaleX );
1154
buffer.Replace( ",", "." );
1158
Line style - WRONG: 2nd arg is OFFSET
1160
Here, I'm afraid you do not conceive meaning of parameters of 'setdash'
1161
operator correctly. You should look-up this in the Red Book: the 2nd parame-
1162
ter is not number of values in the array of the first one, but an offset
1163
into this description of the pattern. I mean a real *offset* not index
1164
into array. I.e. If the command is [3 4] 1 setdash is used, then there
1165
will be first black line *2* units wxCoord, then space 4 units, then the
1166
pattern of *3* units black, 4 units space will be repeated.
1169
static const char *dotted = "[2 5] 2";
1170
static const char *short_dashed = "[4 4] 2";
1171
static const char *wxCoord_dashed = "[4 8] 2";
1172
static const char *dotted_dashed = "[6 6 2 6] 4";
1176
switch (m_pen.GetStyle())
1178
case wxPENSTYLE_DOT: psdash = dotted; break;
1179
case wxPENSTYLE_SHORT_DASH: psdash = short_dashed; break;
1180
case wxPENSTYLE_LONG_DASH: psdash = wxCoord_dashed; break;
1181
case wxPENSTYLE_DOT_DASH: psdash = dotted_dashed; break;
1182
case wxPENSTYLE_USER_DASH:
1185
int nDashes = m_pen.GetDashes (&dashes);
1187
for (int i = 0; i < nDashes; ++i)
1189
buffer.Printf( "%d ", dashes [i] );
1192
PsPrint ("] 0 setdash\n");
1196
case wxPENSTYLE_SOLID:
1197
case wxPENSTYLE_TRANSPARENT:
1198
default: psdash = "[] 0"; break;
1201
if ( psdash && (oldStyle != m_pen.GetStyle()) )
1204
PsPrint( " setdash\n" );
1207
if ( cap != wxCAP_INVALID && cap != oldCap )
1211
case wxCAP_ROUND: buffer = "1"; break;
1212
case wxCAP_PROJECTING: buffer = "2"; break;
1213
case wxCAP_BUTT: buffer = "0"; break;
1215
// This case is just to fix compiler warning, this is impossible
1216
// due to the test above.
1217
case wxCAP_INVALID: break;
1219
buffer << " setlinecap\n";
1223
if ( join != wxJOIN_INVALID && join != oldJoin )
1227
case wxJOIN_BEVEL: buffer = "2"; break;
1228
case wxJOIN_ROUND: buffer = "1"; break;
1229
case wxJOIN_MITER: buffer = "0"; break;
1230
case wxJOIN_INVALID: break;
1232
buffer << " setlinejoin\n";
1237
unsigned char red = m_pen.GetColour().Red();
1238
unsigned char blue = m_pen.GetColour().Blue();
1239
unsigned char green = m_pen.GetColour().Green();
1243
// Anything not white is black
1244
if (! (red == (unsigned char) 255 &&
1245
blue == (unsigned char) 255 &&
1246
green == (unsigned char) 255) )
1248
red = (unsigned char) 0;
1249
green = (unsigned char) 0;
1250
blue = (unsigned char) 0;
1255
if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1257
double redPS = (double)(red) / 255.0;
1258
double bluePS = (double)(blue) / 255.0;
1259
double greenPS = (double)(green) / 255.0;
1261
buffer.Printf( "%f %f %f setrgbcolor\n", redPS, greenPS, bluePS );
1262
buffer.Replace( ",", "." );
1266
m_currentBlue = blue;
1267
m_currentGreen = green;
1271
void wxPostScriptDCImpl::SetBrush( const wxBrush& brush )
1273
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1275
if (!brush.IsOk()) return;
1280
unsigned char red = m_brush.GetColour().Red();
1281
unsigned char blue = m_brush.GetColour().Blue();
1282
unsigned char green = m_brush.GetColour().Green();
1286
// Anything not white is black
1287
if (! (red == (unsigned char) 255 &&
1288
blue == (unsigned char) 255 &&
1289
green == (unsigned char) 255) )
1291
red = (unsigned char) 0;
1292
green = (unsigned char) 0;
1293
blue = (unsigned char) 0;
1298
if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1300
double redPS = (double)(red) / 255.0;
1301
double bluePS = (double)(blue) / 255.0;
1302
double greenPS = (double)(green) / 255.0;
1305
buffer.Printf( "%f %f %f setrgbcolor\n", redPS, greenPS, bluePS );
1306
buffer.Replace( ",", "." );
1310
m_currentBlue = blue;
1311
m_currentGreen = green;
1315
void wxPostScriptDCImpl::DoDrawText( const wxString& text, wxCoord x, wxCoord y )
1317
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1319
const wxWX2MBbuf textbuf = text.mb_str();
1323
if (m_textForegroundColour.IsOk())
1325
unsigned char red = m_textForegroundColour.Red();
1326
unsigned char blue = m_textForegroundColour.Blue();
1327
unsigned char green = m_textForegroundColour.Green();
1331
// Anything not white is black
1332
if (! (red == (unsigned char) 255 &&
1333
blue == (unsigned char) 255 &&
1334
green == (unsigned char) 255))
1336
red = (unsigned char) 0;
1337
green = (unsigned char) 0;
1338
blue = (unsigned char) 0;
1342
// maybe setgray here ?
1343
if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1345
double redPS = (double)(red) / 255.0;
1346
double bluePS = (double)(blue) / 255.0;
1347
double greenPS = (double)(green) / 255.0;
1350
buffer.Printf( "%f %f %f setrgbcolor\n", redPS, greenPS, bluePS );
1351
buffer.Replace( ",", "." );
1355
m_currentBlue = blue;
1356
m_currentGreen = green;
1360
wxCoord text_w, text_h, text_descent;
1362
GetOwner()->GetTextExtent(text, &text_w, &text_h, &text_descent);
1364
int size = m_font.GetPointSize();
1366
// wxCoord by = y + (wxCoord)floor( double(size) * 2.0 / 3.0 ); // approximate baseline
1367
// commented by V. Slavik and replaced by accurate version
1368
// - note that there is still rounding error in text_descent!
1369
wxCoord by = y + size - text_descent; // baseline
1372
buffer.Printf( "%f %f moveto\n", XLOG2DEV(x), YLOG2DEV(by) );
1373
buffer.Replace( ",", "." );
1377
for ( const char *p = textbuf; *p != '\0'; p++ )
1379
int c = (unsigned char)*p;
1380
if (c == ')' || c == '(' || c == '\\')
1382
/* Cope with special characters */
1384
PsPrint( (char) c );
1386
else if ( c >= 128 )
1388
/* Cope with character codes > 127 */
1389
buffer.Printf( "\\%o", c );
1394
PsPrint( (char) c );
1398
PsPrint( ") show\n" );
1400
if (m_font.GetUnderlined())
1402
wxCoord uy = (wxCoord)(y + size - m_underlinePosition);
1404
buffer.Printf( "gsave\n"
1410
XLOG2DEV(x), YLOG2DEV(uy),
1411
m_underlineThickness,
1412
XLOG2DEV(x + text_w), YLOG2DEV(uy) );
1413
buffer.Replace( ",", "." );
1417
CalcBoundingBox( x, y );
1418
CalcBoundingBox( x + size * text.length() * 2/3 , y );
1421
void wxPostScriptDCImpl::DoDrawRotatedText( const wxString& text, wxCoord x, wxCoord y, double angle )
1423
if ( wxIsNullDouble(angle) )
1425
DoDrawText(text, x, y);
1429
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1433
if (m_textForegroundColour.IsOk())
1435
unsigned char red = m_textForegroundColour.Red();
1436
unsigned char blue = m_textForegroundColour.Blue();
1437
unsigned char green = m_textForegroundColour.Green();
1441
// Anything not white is black
1442
if (! (red == (unsigned char) 255 &&
1443
blue == (unsigned char) 255 &&
1444
green == (unsigned char) 255))
1446
red = (unsigned char) 0;
1447
green = (unsigned char) 0;
1448
blue = (unsigned char) 0;
1452
// maybe setgray here ?
1453
if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
1455
double redPS = (double)(red) / 255.0;
1456
double bluePS = (double)(blue) / 255.0;
1457
double greenPS = (double)(green) / 255.0;
1460
buffer.Printf( "%f %f %f setrgbcolor\n", redPS, greenPS, bluePS );
1461
buffer.Replace( ",", "." );
1465
m_currentBlue = blue;
1466
m_currentGreen = green;
1470
int size = m_font.GetPointSize();
1473
buffer.Printf( "%f %f moveto\n", XLOG2DEV(x), YLOG2DEV(y));
1474
buffer.Replace( ",", "." );
1477
buffer.Printf( "%f rotate\n", angle );
1478
buffer.Replace( ",", "." );
1482
const wxWX2MBbuf textbuf = text.mb_str();
1485
for ( const char *p = textbuf; *p != '\0'; p++ )
1487
int c = (unsigned char)*p;
1488
if (c == ')' || c == '(' || c == '\\')
1490
/* Cope with special characters */
1492
PsPrint( (char) c );
1494
else if ( c >= 128 )
1496
/* Cope with character codes > 127 */
1497
buffer.Printf( "\\%o", c);
1502
PsPrint( (char) c );
1507
PsPrint( ") show\n" );
1509
buffer.Printf( "%f rotate\n", -angle );
1510
buffer.Replace( ",", "." );
1513
if (m_font.GetUnderlined())
1515
wxCoord uy = (wxCoord)(y + size - m_underlinePosition);
1517
GetOwner()->GetTextExtent(text, &w, &h);
1526
XLOG2DEV(x), YLOG2DEV(uy),
1527
m_underlineThickness,
1528
XLOG2DEV(x + w), YLOG2DEV(uy) );
1529
buffer.Replace( ",", "." );
1533
CalcBoundingBox( x, y );
1534
CalcBoundingBox( x + size * text.length() * 2/3 , y );
1537
void wxPostScriptDCImpl::SetBackground (const wxBrush& brush)
1539
m_backgroundBrush = brush;
1542
void wxPostScriptDCImpl::SetLogicalFunction(wxRasterOperationMode WXUNUSED(function))
1544
wxFAIL_MSG( wxT("wxPostScriptDCImpl::SetLogicalFunction not implemented.") );
1548
void wxPostScriptDCImpl::DoDrawSpline( const wxPointList *points )
1550
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1554
// a and b are not used
1556
double c, d, x1, y1, x2, y2, x3, y3;
1559
wxPointList::compatibility_iterator node = points->GetFirst();
1560
p = node->GetData();
1564
node = node->GetNext();
1565
p = node->GetData();
1572
(double)(x1 + c) / 2;
1577
(double)(y1 + d) / 2;
1580
buffer.Printf( "newpath\n"
1583
XLOG2DEV(wxRound(x1)), YLOG2DEV(wxRound(y1)),
1584
XLOG2DEV(wxRound(x3)), YLOG2DEV(wxRound(y3)) );
1585
buffer.Replace( ",", "." );
1588
CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
1589
CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
1591
node = node->GetNext();
1594
q = node->GetData();
1602
x3 = (double)(x2 + c) / 2;
1603
y3 = (double)(y2 + d) / 2;
1605
buffer.Printf( "%f %f %f %f %f %f DrawSplineSection\n",
1606
XLOG2DEV(wxRound(x1)), YLOG2DEV(wxRound(y1)),
1607
XLOG2DEV(wxRound(x2)), YLOG2DEV(wxRound(y2)),
1608
XLOG2DEV(wxRound(x3)), YLOG2DEV(wxRound(y3)) );
1609
buffer.Replace( ",", "." );
1612
CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
1613
CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
1615
node = node->GetNext();
1619
At this point, (x2,y2) and (c,d) are the position of the
1620
next-to-last and last point respectively, in the point list
1623
buffer.Printf( "%f %f lineto\nstroke\n", XLOG2DEV(wxRound(c)), YLOG2DEV(wxRound(d)) );
1624
buffer.Replace( ",", "." );
1627
#endif // wxUSE_SPLINES
1629
wxCoord wxPostScriptDCImpl::GetCharWidth() const
1631
// Chris Breeze: reasonable approximation using wxMODERN/Courier
1632
return (wxCoord) (GetCharHeight() * 72.0 / 120.0);
1635
void wxPostScriptDCImpl::SetPrintData(const wxPrintData& data)
1639
wxPaperSize id = m_printData.GetPaperId();
1640
wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
1641
if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
1646
w = paper->GetSizeDeviceUnits().x;
1647
h = paper->GetSizeDeviceUnits().y;
1650
if (m_printData.GetOrientation() == wxLANDSCAPE)
1651
m_pageHeight = w * PS2DEV;
1653
m_pageHeight = h * PS2DEV;
1656
void wxPostScriptDCImpl::ComputeScaleAndOrigin()
1658
const wxRealPoint origScale(m_scaleX, m_scaleY);
1660
wxDCImpl::ComputeScaleAndOrigin();
1662
// If scale has changed call SetPen to recalculate the line width
1663
// and SetFont to recalculate font size
1664
if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.IsOk() )
1671
void wxPostScriptDCImpl::DoGetSize(int* width, int* height) const
1673
wxPaperSize id = m_printData.GetPaperId();
1675
wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
1677
if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
1683
w = paper->GetSizeDeviceUnits().x;
1684
h = paper->GetSizeDeviceUnits().y;
1687
if (m_printData.GetOrientation() == wxLANDSCAPE)
1695
*width = wxRound( w * PS2DEV );
1698
*height = wxRound( h * PS2DEV );
1701
void wxPostScriptDCImpl::DoGetSizeMM(int *width, int *height) const
1703
wxPaperSize id = m_printData.GetPaperId();
1705
wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(id);
1707
if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
1713
w = paper->GetWidth() / 10;
1714
h = paper->GetHeight() / 10;
1717
if (m_printData.GetOrientation() == wxLANDSCAPE)
1724
if (width) *width = w;
1725
if (height) *height = h;
1728
// Resolution in pixels per logical inch
1729
wxSize wxPostScriptDCImpl::GetPPI(void) const
1731
return wxSize( DPI, DPI );
1735
bool wxPostScriptDCImpl::StartDoc( const wxString& WXUNUSED(message) )
1737
wxCHECK_MSG( m_ok, false, wxT("invalid postscript dc") );
1739
if (m_printData.GetPrintMode() != wxPRINT_MODE_STREAM )
1741
if (m_printData.GetFilename() == wxEmptyString)
1743
wxString filename = wxFileName::CreateTempFileName( wxT("ps") );
1744
m_printData.SetFilename(filename);
1747
m_pstream = wxFopen( m_printData.GetFilename(), wxT("w+") );
1751
wxLogError( _("Cannot open file for PostScript printing!"));
1761
PsPrint( "%!PS-Adobe-2.0\n" );
1763
PsPrint( "%%Creator: wxWidgets PostScript renderer\n" );
1765
buffer.Printf( "%%%%CreationDate: %s\n", wxNow() );
1768
if (m_printData.GetOrientation() == wxLANDSCAPE)
1769
PsPrint( "%%Orientation: Landscape\n" );
1771
PsPrint( "%%Orientation: Portrait\n" );
1773
const wxChar *paper;
1774
switch (m_printData.GetPaperId())
1776
case wxPAPER_LETTER: paper = wxT("Letter"); break; // Letter: paper ""; 8 1/2 by 11 inches
1777
case wxPAPER_LEGAL: paper = wxT("Legal"); break; // Legal, 8 1/2 by 14 inches
1778
case wxPAPER_A4: paper = wxT("A4"); break; // A4 Sheet, 210 by 297 millimeters
1779
case wxPAPER_TABLOID: paper = wxT("Tabloid"); break; // Tabloid, 11 by 17 inches
1780
case wxPAPER_LEDGER: paper = wxT("Ledger"); break; // Ledger, 17 by 11 inches
1781
case wxPAPER_STATEMENT: paper = wxT("Statement"); break; // Statement, 5 1/2 by 8 1/2 inches
1782
case wxPAPER_EXECUTIVE: paper = wxT("Executive"); break; // Executive, 7 1/4 by 10 1/2 inches
1783
case wxPAPER_A3: paper = wxT("A3"); break; // A3 sheet, 297 by 420 millimeters
1784
case wxPAPER_A5: paper = wxT("A5"); break; // A5 sheet, 148 by 210 millimeters
1785
case wxPAPER_B4: paper = wxT("B4"); break; // B4 sheet, 250 by 354 millimeters
1786
case wxPAPER_B5: paper = wxT("B5"); break; // B5 sheet, 182-by-257-millimeter paper
1787
case wxPAPER_FOLIO: paper = wxT("Folio"); break; // Folio, 8-1/2-by-13-inch paper
1788
case wxPAPER_QUARTO: paper = wxT("Quaro"); break; // Quarto, 215-by-275-millimeter paper
1789
case wxPAPER_10X14: paper = wxT("10x14"); break; // 10-by-14-inch sheet
1790
default: paper = wxT("A4");
1793
buffer.Printf( "%%%%DocumentPaperSizes: %s\n", paper );
1796
PsPrint( "%%EndComments\n\n" );
1798
PsPrint( "%%BeginProlog\n" );
1799
PsPrint( wxPostScriptHeaderConicTo );
1800
PsPrint( wxPostScriptHeaderEllipse );
1801
PsPrint( wxPostScriptHeaderEllipticArc );
1802
PsPrint( wxPostScriptHeaderColourImage );
1803
PsPrint( wxPostScriptHeaderReencodeISO1 );
1804
PsPrint( wxPostScriptHeaderReencodeISO2 );
1805
if (wxPostScriptHeaderSpline)
1806
PsPrint( wxPostScriptHeaderSpline );
1807
PsPrint( "%%EndProlog\n" );
1809
SetBrush( *wxBLACK_BRUSH );
1810
SetPen( *wxBLACK_PEN );
1811
SetBackground( *wxWHITE_BRUSH );
1812
SetTextForeground( *wxBLACK );
1814
// set origin according to paper size
1815
SetDeviceOrigin( 0,0 );
1821
void wxPostScriptDCImpl::EndDoc ()
1823
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1828
PsPrint( "grestore\n" );
1832
fclose( m_pstream );
1837
// THE FOLLOWING HAS BEEN CONTRIBUTED BY Andy Fyfe <andy@hyperparallel.com>
1838
wxCoord wx_printer_translate_x, wx_printer_translate_y;
1839
double wx_printer_scale_x, wx_printer_scale_y;
1841
wx_printer_translate_x = (wxCoord)m_printData.GetPrinterTranslateX();
1842
wx_printer_translate_y = (wxCoord)m_printData.GetPrinterTranslateY();
1844
wx_printer_scale_x = m_printData.GetPrinterScaleX();
1845
wx_printer_scale_y = m_printData.GetPrinterScaleY();
1847
// Compute the bounding box. Note that it is in the default user
1848
// coordinate system, thus we have to convert the values.
1849
wxCoord minX = (wxCoord) XLOG2DEV(m_minX);
1850
wxCoord minY = (wxCoord) YLOG2DEV(m_minY);
1851
wxCoord maxX = (wxCoord) XLOG2DEV(m_maxX);
1852
wxCoord maxY = (wxCoord) YLOG2DEV(m_maxY);
1854
// LOG2DEV may have changed the minimum to maximum vice versa
1855
if ( minX > maxX ) { wxCoord tmp = minX; minX = maxX; maxX = tmp; }
1856
if ( minY > maxY ) { wxCoord tmp = minY; minY = maxY; maxY = tmp; }
1858
// account for used scaling (boundingbox is before scaling in ps-file)
1859
double scale_x = m_printData.GetPrinterScaleX() / ms_PSScaleFactor;
1860
double scale_y = m_printData.GetPrinterScaleY() / ms_PSScaleFactor;
1862
wxCoord llx, lly, urx, ury;
1863
llx = (wxCoord) ((minX+wx_printer_translate_x)*scale_x);
1864
lly = (wxCoord) ((minY+wx_printer_translate_y)*scale_y);
1865
urx = (wxCoord) ((maxX+wx_printer_translate_x)*scale_x);
1866
ury = (wxCoord) ((maxY+wx_printer_translate_y)*scale_y);
1867
// (end of bounding box computation)
1870
// If we're landscape, our sense of "x" and "y" is reversed.
1871
if (m_printData.GetOrientation() == wxLANDSCAPE)
1874
tmp = llx; llx = lly; lly = tmp;
1875
tmp = urx; urx = ury; ury = tmp;
1877
// We need either the two lines that follow, or we need to subtract
1878
// min_x from real_translate_y, which is commented out below.
1879
llx = llx - (wxCoord)(m_minX*wx_printer_scale_y);
1880
urx = urx - (wxCoord)(m_minX*wx_printer_scale_y);
1883
// The Adobe specifications call for integers; we round as to make
1884
// the bounding larger.
1885
PsPrintf( wxT("%%%%BoundingBox: %d %d %d %d\n"),
1886
(wxCoord)floor((double)llx), (wxCoord)floor((double)lly),
1887
(wxCoord)ceil((double)urx), (wxCoord)ceil((double)ury) );
1889
// To check the correctness of the bounding box, postscript commands
1890
// to draw a box corresponding to the bounding box are generated below.
1891
// But since we typically don't want to print such a box, the postscript
1892
// commands are generated within comments. These lines appear before any
1893
// adjustment of scale, rotation, or translation, and hence are in the
1894
// default user coordinates.
1895
PsPrint( "% newpath\n" );
1896
PsPrintf( wxT("%% %d %d moveto\n"), llx, lly );
1897
PsPrintf( wxT("%% %d %d lineto\n"), urx, lly );
1898
PsPrintf( wxT("%% %d %d lineto\n"), urx, ury );
1899
PsPrintf( wxT("%% %d %d lineto closepath stroke\n"), llx, ury );
1903
wxPostScriptPrintNativeData *data =
1904
(wxPostScriptPrintNativeData *) m_printData.GetNativeData();
1906
if (m_ok && (m_printData.GetPrintMode() == wxPRINT_MODE_PRINTER))
1909
command += data->GetPrinterCommand();
1910
command += wxT(" ");
1911
command += data->GetPrinterOptions();
1912
command += wxT(" ");
1913
command += m_printData.GetFilename();
1915
wxExecute( command, true );
1916
wxRemoveFile( m_printData.GetFilename() );
1921
void wxPostScriptDCImpl::StartPage()
1923
wxCHECK_RET( m_ok, wxT("invalid postscript dc") );
1926
buffer.Printf( wxT("%%%%Page: %d\n"), m_pageNumber++ );
1930
wxPostScriptPrintNativeData *data =
1931
(wxPostScriptPrintNativeData *) m_printData.GetNativeData();
1933
wxCoord translate_x = (wxCoord)data->GetPrinterTranslateX();
1934
wxCoord translate_y = (wxCoord)data->GetPrinterTranslateY();
1936
buffer.Printf( "%d %d translate\n", translate_x, translate_y );
1939
double scale_x = data->GetPrinterScaleX();
1940
double scale_y = data->GetPrinterScaleY();
1942
buffer.Printf( "%f %f scale\n", scale_x, scale_y );
1943
buffer.Replace( ",", "." );
1948
// Each page starts with an "initgraphics" which resets the
1949
// transformation and so we need to rotate the page for
1950
// landscape printing)
1952
// I copied this one from a PostScript tutorial, but to no avail. RR.
1953
// PsPrint( "90 rotate llx neg ury nef translate\n" );
1955
if (m_printData.GetOrientation() == wxLANDSCAPE)
1956
PsPrint( "90 rotate\n" );
1959
void wxPostScriptDCImpl::EndPage ()
1961
wxCHECK_RET( m_ok , wxT("invalid postscript dc") );
1963
PsPrint( "showpage\n" );
1966
bool wxPostScriptDCImpl::DoBlit( wxCoord xdest, wxCoord ydest,
1967
wxCoord fwidth, wxCoord fheight,
1969
wxCoord xsrc, wxCoord ysrc,
1970
wxRasterOperationMode rop,
1971
bool WXUNUSED(useMask), wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask) )
1973
wxCHECK_MSG( m_ok, false, wxT("invalid postscript dc") );
1975
wxCHECK_MSG( source, false, wxT("invalid source dc") );
1977
// blit into a bitmap
1978
wxBitmap bitmap( (int)fwidth, (int)fheight );
1980
memDC.SelectObject(bitmap);
1981
memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */
1982
memDC.SelectObject(wxNullBitmap);
1984
//draw bitmap. scaling and positioning is done there
1985
GetOwner()->DrawBitmap( bitmap, xdest, ydest );
1990
wxCoord wxPostScriptDCImpl::GetCharHeight() const
1993
return m_font.GetPointSize();
1998
void wxPostScriptDCImpl::PsPrint( const wxString& str )
2000
const wxCharBuffer psdata(str.utf8_str());
2002
wxPostScriptPrintNativeData *data =
2003
(wxPostScriptPrintNativeData *) m_printData.GetNativeData();
2005
switch (m_printData.GetPrintMode())
2008
// append to output stream
2009
case wxPRINT_MODE_STREAM:
2011
wxOutputStream* outputstream = data->GetOutputStream();
2012
wxCHECK_RET( outputstream, wxT("invalid outputstream") );
2013
outputstream->Write( psdata, strlen( psdata ) );
2016
#endif // wxUSE_STREAMS
2018
// save data into file
2020
wxCHECK_RET( m_pstream, wxT("invalid postscript dc") );
2021
fwrite( psdata, 1, strlen( psdata ), m_pstream );
2025
void wxPostScriptDCImpl::DoGetTextExtent(const wxString& string,
2026
wxCoord *x, wxCoord *y,
2027
wxCoord *descent, wxCoord *externalLeading,
2028
const wxFont *theFont ) const
2030
const wxFont *fontToUse = theFont;
2032
if (!fontToUse) fontToUse = &m_font;
2034
const float fontSize =
2035
fontToUse->GetPointSize() * GetFontPointSizeAdjustment(72.0);
2041
if (descent) (*descent) = 0;
2042
if (externalLeading) (*externalLeading) = 0;
2048
const wxWX2MBbuf strbuf = string.mb_str();
2050
// conversion failed (non e.g. ISO characters)
2054
#if !wxUSE_AFM_FOR_POSTSCRIPT
2055
/* Provide a VERY rough estimate (avoid using it).
2056
* Produces accurate results for mono-spaced font
2057
* such as Courier (aka wxMODERN) */
2060
*x = strlen (strbuf) * fontSize * 72.0 / 120.0;
2062
*y = (wxCoord) (fontSize * 1.32); /* allow for descender */
2063
if (descent) *descent = 0;
2064
if (externalLeading) *externalLeading = 0;
2067
/* method for calculating string widths in postscript:
2068
/ read in the AFM (adobe font metrics) file for the
2069
/ actual font, parse it and extract the character widths
2070
/ and also the descender. this may be improved, but for now
2071
/ it works well. the AFM file is only read in if the
2072
/ font is changed. this may be chached in the future.
2073
/ calls to GetTextExtent with the font unchanged are rather
2076
/ for each font and style used there is an AFM file necessary.
2077
/ currently i have only files for the roman font family.
2078
/ I try to get files for the other ones!
2080
/ CAVE: the size of the string is currently always calculated
2081
/ in 'points' (1/72 of an inch). this should later on be
2082
/ changed to depend on the mapping mode.
2083
/ CAVE: the path to the AFM files must be set before calling this
2084
/ fun3B3Bction. this is usually done by a call like the following:
2085
/ wxSetAFMPath("d:\\wxw161\\afm\\");
2089
/ wxPostScriptDC dc(NULL, true);
2091
/ wxSetAFMPath("d:\\wxw161\\afm\\");
2092
/ dc.StartDoc("Test");
2095
/ dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL));
2096
/ dc.GetTextExtent("Hallo",&w,&h);
2101
/ by steve (stefan.hammes@urz.uni-heidelberg.de)
2103
/ updated: 14.05.95 */
2105
/* these static vars are for storing the state between calls */
2106
static int lastFamily= INT_MIN;
2107
static int lastSize= INT_MIN;
2108
static int lastStyle= INT_MIN;
2109
static int lastWeight= INT_MIN;
2110
static int lastDescender = INT_MIN;
2111
static int lastWidths[256]; /* widths of the characters */
2113
double UnderlinePosition = 0.0;
2114
double UnderlineThickness = 0.0;
2116
// Get actual parameters
2117
int Family = fontToUse->GetFamily();
2118
int Size = fontToUse->GetPointSize();
2119
int Style = fontToUse->GetStyle();
2120
int Weight = fontToUse->GetWeight();
2122
// If we have another font, read the font-metrics
2123
if (Family!=lastFamily || Size!=lastSize || Style!=lastStyle || Weight!=lastWeight)
2125
// Store actual values
2126
lastFamily = Family;
2129
lastWeight = Weight;
2138
if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("CourBoO.afm");
2139
else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("CourBo.afm");
2140
else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("CourO.afm");
2141
else name = wxT("Cour.afm");
2146
if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("TimesBoO.afm");
2147
else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("TimesBo.afm");
2148
else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("TimesO.afm");
2149
else name = wxT("TimesRo.afm");
2154
name = wxT("Zapf.afm");
2160
if ((Style == wxITALIC) && (Weight == wxBOLD)) name = wxT("HelvBoO.afm");
2161
else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = wxT("HelvBo.afm");
2162
else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = wxT("HelvO.afm");
2163
else name = wxT("Helv.afm");
2168
FILE *afmFile = NULL;
2170
// Get the directory of the AFM files
2173
// VZ: I don't know if the cast always works under Unix but it clearly
2174
// never does under Windows where the pointer is
2175
// wxWindowsPrintNativeData and so calling GetFontMetricPath() on
2178
wxPostScriptPrintNativeData *data =
2179
wxDynamicCast(m_printData.GetNativeData(), wxPostScriptPrintNativeData);
2181
if (data && !data->GetFontMetricPath().empty())
2183
afmName = data->GetFontMetricPath();
2184
afmName << wxFILE_SEP_PATH << name;
2188
if ( !afmName.empty() )
2189
afmFile = wxFopen(afmName, wxT("r"));
2193
#if defined(__UNIX__) && !defined(__VMS__)
2194
afmName = wxGetDataDir();
2196
afmName = wxStandardPaths::Get().GetDataDir();
2197
#endif // __UNIX__/!__UNIX__
2199
afmName << wxFILE_SEP_PATH
2200
#if defined(__LINUX__) || defined(__FREEBSD__)
2201
<< wxT("gs_afm") << wxFILE_SEP_PATH
2203
<< wxT("afm") << wxFILE_SEP_PATH
2206
afmFile = wxFopen(afmName,wxT("r"));
2209
/* 2. open and process the file
2210
/ a short explanation of the AFM format:
2211
/ we have for each character a line, which gives its size
2214
/ C 63 ; WX 444 ; N question ; B 49 -14 395 676 ;
2216
/ that means, we have a character with ascii code 63, and width
2217
/ (444/1000 * fontSize) points.
2218
/ the other data is ignored for now!
2220
/ when the font has changed, we read in the right AFM file and store the
2221
/ character widths in an array, which is processed below (see point 3.). */
2224
wxLogDebug( wxT("GetTextExtent: can't open AFM file '%s'"), afmName.c_str() );
2225
wxLogDebug( wxT(" using approximate values"));
2226
for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */
2227
lastDescender = -150; /* dito. */
2231
/* init the widths array */
2232
for(int i=0; i<256; i++) lastWidths[i] = INT_MIN;
2233
/* some variables for holding parts of a line */
2234
char cString[10], semiString[10], WXString[10];
2235
char descString[20];
2236
char upString[30], utString[30];
2240
/* read in the file and parse it */
2241
while(fgets(line,sizeof(line),afmFile)!=NULL)
2243
/* A.) check for descender definition */
2244
if (strncmp(line,"Descender",9)==0)
2246
if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) ||
2247
(strcmp(descString,"Descender")!=0))
2249
wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad descender)"), afmName.c_str(),line );
2252
/* JC 1.) check for UnderlinePosition */
2253
else if(strncmp(line,"UnderlinePosition",17)==0)
2255
if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) ||
2256
(strcmp(upString,"UnderlinePosition")!=0))
2258
wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlinePosition)"), afmName.c_str(), line );
2261
/* JC 2.) check for UnderlineThickness */
2262
else if(strncmp(line,"UnderlineThickness",18)==0)
2264
if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) ||
2265
(strcmp(utString,"UnderlineThickness")!=0))
2267
wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad UnderlineThickness)"), afmName.c_str(), line );
2270
/* JC 3.) check for EncodingScheme */
2271
else if(strncmp(line,"EncodingScheme",14)==0)
2273
if ((sscanf(line,"%s%s",utString,encString)!=2) ||
2274
(strcmp(utString,"EncodingScheme")!=0))
2276
wxLogDebug( wxT("AFM-file '%s': line '%s' has error (bad EncodingScheme)"), afmName.c_str(), line );
2278
else if (strncmp(encString, "AdobeStandardEncoding", 21))
2280
wxLogDebug( wxT("AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)"),
2281
afmName.c_str(),line, encString);
2284
/* B.) check for char-width */
2285
else if(strncmp(line,"C ",2)==0)
2287
if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5)
2289
wxLogDebug(wxT("AFM-file '%s': line '%s' has an error (bad character width)"),afmName.c_str(),line);
2291
if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0)
2293
wxLogDebug(wxT("AFM-file '%s': line '%s' has a format error"),afmName.c_str(),line);
2295
/* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */
2296
if (ascii>=0 && ascii<256)
2298
lastWidths[ascii] = cWidth; /* store width */
2302
/* MATTHEW: this happens a lot; don't print an error */
2303
/* wxLogDebug("AFM-file '%s': ASCII value %d out of range",afmName.c_str(),ascii); */
2306
/* C.) ignore other entries. */
2310
/* hack to compute correct values for german 'Umlaute'
2311
/ the correct way would be to map the character names
2312
/ like 'adieresis' to corresp. positions of ISOEnc and read
2313
/ these values from AFM files, too. Maybe later ... */
2315
// NB: casts to int are needed to suppress gcc 3.3 warnings
2316
lastWidths[196] = lastWidths[(int)'A']; // U+00C4 A Umlaute
2317
lastWidths[228] = lastWidths[(int)'a']; // U+00E4 a Umlaute
2318
lastWidths[214] = lastWidths[(int)'O']; // U+00D6 O Umlaute
2319
lastWidths[246] = lastWidths[(int)'o']; // U+00F6 o Umlaute
2320
lastWidths[220] = lastWidths[(int)'U']; // U+00DC U Umlaute
2321
lastWidths[252] = lastWidths[(int)'u']; // U+00FC u Umlaute
2322
lastWidths[223] = lastWidths[(int)251]; // U+00DF eszett (scharfes s)
2324
/* JC: calculate UnderlineThickness/UnderlinePosition */
2326
// VS: dirty, but is there any better solution?
2328
pt = (double*) &m_underlinePosition;
2329
*pt = YLOG2DEVREL((wxCoord)(UnderlinePosition * fontSize)) / 1000.0f;
2330
pt = (double*) &m_underlineThickness;
2331
*pt = YLOG2DEVREL((wxCoord)(UnderlineThickness * fontSize)) / 1000.0f;
2336
/* 3. now the font metrics are read in, calc size this
2337
/ is done by adding the widths of the characters in the
2338
/ string. they are given in 1/1000 of the size! */
2341
float height=fontSize; /* by default */
2342
unsigned char *p=(unsigned char *)wxMBSTRINGCAST strbuf;
2345
// String couldn't be converted which used to SEGV as reported here:
2346
// http://bugs.debian.org/702378
2347
// http://trac.wxwidgets.org/ticket/15300
2348
// Upstream suggests "just return if the conversion failed".
2351
if (descent) (*descent) = 0;
2352
if (externalLeading) (*externalLeading) = 0;
2357
if(lastWidths[*p]== INT_MIN)
2359
wxLogDebug(wxT("GetTextExtent: undefined width for character '%c' (%d)"), *p,*p);
2360
sum += lastWidths[(unsigned char)' ']; /* assume space */
2364
sum += lastWidths[*p];
2368
double widthSum = sum;
2369
widthSum *= fontSize;
2370
widthSum /= 1000.0F;
2372
/* add descender to height (it is usually a negative value) */
2373
//if (lastDescender != INT_MIN)
2375
// height += (wxCoord)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
2377
// - commented by V. Slavik - height already contains descender in it
2378
// (judging from few experiments)
2380
/* return size values */
2382
*x = (wxCoord)widthSum;
2384
*y = (wxCoord)height;
2386
/* return other parameters */
2389
if(lastDescender!=INT_MIN)
2391
*descent = (wxCoord)(((-lastDescender)/1000.0F) * fontSize); /* MATTHEW: forgot scale */
2399
/* currently no idea how to calculate this! */
2400
if (externalLeading) *externalLeading = 0;
2406
#endif // wxUSE_PRINTING_ARCHITECTURE && wxUSE_POSTSCRIPT