Class: FXDCPostscript

Inherits:
FXDC
  • Object
show all
Defined in:
lib/IFMapper/FXDCPostscript.rb

Overview

Class used to do Postscript printing. This class has only the basic functionality needed for doing so and replaces the still somewhat buggy version of Fox’s 1.2 FXDCPrint

Constant Summary collapse

@@printcmd =

-#%d’

'lpr -P%s -o l -'

Instance Method Summary collapse

Methods inherited from FXDC

#drawBSpline

Constructor Details

#initialize(app) ⇒ FXDCPostscript

Returns a new instance of FXDCPostscript.



393
394
395
# File 'lib/IFMapper/FXDCPostscript.rb', line 393

def initialize(app)
  @font = app.getNormalFont()
end

Instance Method Details

#_headerObject



57
58
59
60
61
62
63
64
# File 'lib/IFMapper/FXDCPostscript.rb', line 57

def _header
  @f.puts <<'HEADER'
%%!PS-Adobe-3.0
%%%%Title: Print Job
%%%%Creator: IFMapper
HEADER

end

#_rect(x, y, w, h) ⇒ Object



233
234
235
236
237
238
239
240
# File 'lib/IFMapper/FXDCPostscript.rb', line 233

def _rect(x, y, w, h)
    xl, yt = tfm(x, y)
    xr, yb = tfm(x + w - 1, y + h - 1)
    bbox(xl,yt)
    bbox(xr,yb)
    @f.print "newpath %g %g moveto %g %g lineto %g %g lineto %g %g lineto %g %g lineto " % 
	[xl,yt,xr,yt,xr,yb,xl,yb,xl,yt]
end

#bbox(x, y) ⇒ Object

Extends bounding box with point x,y



226
227
228
229
230
231
# File 'lib/IFMapper/FXDCPostscript.rb', line 226

def bbox(x, y)
  @xmin = x if x < @xmin
  @ymin = y if y < @ymin
  @xmax = x if x > @xmax
  @ymax = y if y > @ymax
end

#beginPage(num = 1, &block) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/IFMapper/FXDCPostscript.rb', line 176

def beginPage(num = 1, &block)
  # Output page number
  @f.puts "%%%%Page: #{@page} #{@page}" # Ghostscript requests this, I do not know if it is right

  # Reset page bounding box
  if @flags & PRINT_NOBOUNDS != 0
    @xmin= 1000000;
    @xmax=-1000000;
    @ymin= 1000000;
    @ymax=-1000000;
    @f.puts "%%%%PageBoundingBox: (atend)"
  else
    # Use the doc bounding box
    @f.puts "%%%%PageBoundingBox: %d %d %d %d" % [@xmin, @ymin, @xmax, @ymax]
  end

  # Page setup
  @f.puts "%%%%BeginPageSetup"
  @f.puts "%%%%EndPageSetup"
  @f.puts "gsave"

  # Maybe in landscape?
  if @flags & PRINT_LANDSCAPE != 0
    @f.puts "#{@width} 0.0 translate"
    @f.puts "90 rotate"
  end

  if block_given?
    yield self
    endPage()
  end
end

#beginPrint(printer, &block) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/IFMapper/FXDCPostscript.rb', line 66

def beginPrint(printer, &block)
  @flags = printer.flags
  if @flags & PRINT_DEST_FILE != 0
    @f = File.open( printer.name, 'w' )
  else
    buffer = @@printcmd % [ printer.name, printer.numcopies ]
    puts buffer
    @f = File.popen( buffer, 'w')
  end


  @width  = printer.mediawidth.to_f
  @height = printer.mediaheight.to_f

  @xmin   = printer.leftmargin.to_f
  @xmax   = @width - printer.rightmargin 

  @ymin   = printer.bottommargin.to_f
  @ymax   = @height - printer.topmargin 


  _header
  if @flags & PRINT_NOBOUNDS != 0
    xmin = 10000000.0
    xmax = -xmin
    ymin = 10000000.0
    ymax = -ymin
    @f.puts "%%%%BoundingBox: (atend)"
  else
    @f.puts "%%%%BoundingBox: %d %d %d %d" %
	[ @xmin, @ymin, @xmax, @ymax ]
  end

  @numpages = 1 + printer.firstpage - printer.lastpage
  if    @flags & PRINT_PAGES_ODD
    @numpages = 1 + (printer.topage - printer.frompage) / 2  
  elsif @flags & PRINT_PAGES_EVEN
    @numpages = 1 + (printer.topage - printer.frompage) / 2  
  elsif @pages & PRINT_PAGES_RANGE
    @numpages = 1 + printer.topage - printer.frompage
  end

  if @numpages == 0
    @f.puts "%%%%Pages: (atend)"
  else
    @f.puts "%%%%Pages: #{@numpages}"
  end

  @f.puts "%%%%DocumentFonts:"
  @f.puts "%%%%EndComments"
  @f.puts "%%%%BeginProlog\n\n"

  # Various definitions
  @f.puts "%% h w x y drawRect\n"
  @f.puts "/drawRect {\n\tnewpath moveto dup 0 rlineto exch dup 0 exch\n\trlineto exch neg 0 rlineto neg 0 exch rlineto\n\tclosepath stroke\n} def\n"
  @f.puts "%% h w x y fillRect\n"
  @f.puts "/fillRect {\n\tnewpath moveto dup 0 rlineto exch dup 0 exch\n\trlineto exch neg 0 rlineto neg 0 exch rlineto\n\tclosepath fill stroke\n} def\n"
  @f.puts "%% x y a b drawLine\n"
  @f.puts "/drawLine {\n\tnewpath moveto lineto stroke\n} def\n"
  @f.puts "%% x y ..... npoints drawLines\n"
  @f.puts "/drawLines {\n\t3 1 roll newpath moveto {lineto} repeat stroke\n} def\n"
  @f.puts "%% x y a b ..... nsegments drawSegmt\n"
  @f.puts "/drawSegmt {\n\tnewpath {\n\t\tmoveto lineto\n\t} repeat stroke\n} def\n"
  @f.puts "%% x y drawPoint\n"
  @f.puts "/drawPoint {\n\ttranslate 1 1 scale 8 8 1 [ 8 0 0 8 0 0 ] {<0000>} image\n} def\n"
  @f.puts "%% centerx centery  startAngle endAngle radiusX radiusY drawArc\n"
  @f.puts "/drawArc {\n\tgsave dup 3 1 roll div dup 1 scale 6 -1 roll\n\texch div 5 1 roll  3 -2 roll arc stroke grestore\n} def\n"
  @f.puts "/fillChord {\n\tgsave dup 3 1 roll div dup 1 scale 6 -1 roll\n\texch div 5 1 roll  3 -2 roll arc fill grestore\n} def\n"
  @f.puts "%% (string) x y height drawText\n"
  @f.puts "/drawText {\n\tgsave findfont exch scalefont setfont moveto\n\tshow grestore\n} def\n"


  @f.puts "%%%%EndProlog"

  @f.puts "%%%%BeginSetup"
  @f.puts "/#copies #{printer.numcopies} def"
  @f.puts "%%%%EndSetup"

  @page = 0

  if block_given?
    yield self
    endPrint()
  end
end

#drawLine(x1, y1, x2, y2) ⇒ Object



248
249
250
251
252
253
254
# File 'lib/IFMapper/FXDCPostscript.rb', line 248

def drawLine(x1, y1, x2, y2)
  xx1, yy1 = tfm(x1, y1)
  xx2, yy2 = tfm(x2, y2)
  bbox(xx1,yy1)
  bbox(xx2,yy2)
  @f.puts "newpath %g %g moveto %g %g lineto stroke" % [xx1, yy1, xx2, yy2]
end

#drawLines(points) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/IFMapper/FXDCPostscript.rb', line 256

def drawLines(points)
  return if points.size < 2
  xx, yy = tfm(points[0].x, points[0].y)
  bbox(xx,yy)
  @f.print "newpath %g %g moveto" % [xx, yy]
  1.upto(points.size-1) { |i|
    xx, yy = tfm(points[i].x, points[i].y)
    bbox(xx,yy)
    @f.print " %g %g lineto" % [xx, yy]
  }
  @f.puts " stroke"
end

#drawRectangle(x, y, w, h) ⇒ Object



242
243
244
245
# File 'lib/IFMapper/FXDCPostscript.rb', line 242

def drawRectangle(x, y, w, h)
  _rect(x, y, w, h)
  @f.puts "stroke"
end

#drawText(x, y, text) ⇒ Object



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/IFMapper/FXDCPostscript.rb', line 269

def drawText(x, y, text)
  # Draw string (only foreground bits)
  # Contributed by S. Ancelot <[email protected]>
  xx, yy = tfm( x, y )

  pxrange = @pxmax - @pxmin
  pyrange = @pymax - @pymin

  if @flags & PRINT_LANDSCAPE != 0
    mxmin = @ymin
    mxmax = @ymax
    mymin = @width - @xmax
    mymax = @width - @xmin
    mxrange = mxmax - mxmin
    myrange = mymax - mymin
  else
    mxmin = @xmin
    mxmax = @xmax
    mymin = @ymin
    mymax = @ymax
    mxrange = mxmax - mxmin
    myrange = mymax - mymin
  end

  fsize = 0.1 * @font.getSize

  # Hack...
  # Account for dpi and scale up or down with graph...
  # Perhaps override screen resolution via registry
  # FXint screenres=getApp()->reg().readUnsignedEntry("SETTINGS","screenres",100);
  # Validate
  screenres = 100
#     if(screenres<50) screenres=50;
#       if(screenres>200) screenres=200;

  if pyrange / pxrange <= myrange / mxrange
    # short/wide
    fsize *= (mxrange/pxrange)*(screenres/72.0)
  else
    # tall/thin
    fsize *= (myrange/pyrange)*(screenres/72.0)
  end

  fname = @font.name
  if fname =~ /times/i
    fname = 'Times-Roman'
  elsif fname =~ /(helvetica|verdana|tahoma|arial)/i
    fname = 'Helvetica'
  else
    fname = 'Courier'
  end

  if @font.getWeight == FXFont::FONTWEIGHT_BOLD
    fname << '-Bold'
    if @font.getSlant == FXFont::FONTSLANT_ITALIC
	fname << 'Italic'
    elsif @font.getSlant == FXFont::FONTSLANT_OBLIQUE
	fname << 'Oblique'
    end
  else
    if @font.getSlant == FXFont::FONTSLANT_ITALIC
	fname << '-Italic'
    elsif @font.getSlant == FXFont::FONTSLANT_OBLIQUE
	fname << '-Oblique'
    end
  end

  @f.puts "(%s) %g %g %d /%s drawText" % [text, xx, yy, fsize, fname]
end

#endPageObject



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/IFMapper/FXDCPostscript.rb', line 209

def endPage
  @f.puts "%%%%PageTrailer"

  # We now know the bounding box
  if @flags & PRINT_NOBOUNDS != 0
    if @xmin < @xmax and @ymin < @ymax
	@f.puts "%%%%BoundingBox: %d %d %d %d" [@xmin, @ymin, @xmax, @ymax]
    else
	@f.puts "%%%%BoundingBox: 0 0 100 100" # Gotta come up with something...
    end
  end
  @f.puts "showpage"
  @f.puts "grestore"
  @page += 1
end

#endPrintObject



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/IFMapper/FXDCPostscript.rb', line 153

def endPrint
  @f.puts "%%%%Trailer\n"

  # We now know the bounding box
  if @flags & PRINT_NOBOUNDS != 0
    if @xmin < @xmax and @ymin < @ymax
	@f.puts "%%%%BoundingBox: %d %d %d %d" %
 [ @xmin, @ymin, @xmax, @ymax ]
    else
	@f.puts "%%%%BoundingBox: 0 0 100 100"
    end
  end

  # We now know the page count
  if not (@flags & PRINT_PAGES_ODD|PRINT_PAGES_EVEN|PRINT_PAGES_RANGE)
    @f.puts "%%%%Pages: #{page}"
  end

  @f.puts "%%%%EOF"
  @f.close
end

#fillPolygon(points) ⇒ Object



344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/IFMapper/FXDCPostscript.rb', line 344

def fillPolygon(points)
  return if points.size < 3
  xx, yy = tfm(points[0].x, points[0].y)
  bbox(xx,yy)
  @f.print "newpath %g %g moveto" % [ xx, yy ]
  1.upto(points.size-1) { |i|
    xx, yy = tfm(points[i].x, points[i].y)
    bbox(xx,yy)
    @f.print " %g %g lineto" % [ xx, yy ]
  }
  @f.puts " fill"
end

#fillRectangle(x, y, w, h) ⇒ Object



339
340
341
342
# File 'lib/IFMapper/FXDCPostscript.rb', line 339

def fillRectangle(x, y, w, h)
  _rect(x, y, w, h)
  @f.puts "fill"
end

#fontObject



401
402
403
# File 'lib/IFMapper/FXDCPostscript.rb', line 401

def font
  return @font
end

#font=(x) ⇒ Object



397
398
399
# File 'lib/IFMapper/FXDCPostscript.rb', line 397

def font=(x)
  @font = x
end

#foreground=(c) ⇒ Object



365
366
367
368
369
370
371
372
# File 'lib/IFMapper/FXDCPostscript.rb', line 365

def foreground=(c)
  if c.kind_of?(String)
    clr = fxcolorfromname(c)
  else
    clr = c
  end
  @f.puts "%g %g %g setrgbcolor" % [FXREDVAL(clr)/255.0,FXGREENVAL(clr)/255.0,FXBLUEVAL(clr)/255.0]
end

#lineCap=(x) ⇒ Object



377
378
379
380
381
382
# File 'lib/IFMapper/FXDCPostscript.rb', line 377

def lineCap=(x)
  ncap = 0
  ncap = 1 if CAP_ROUND == x
  ncap = 3 if CAP_PROJECTING == x
  @f.puts "#{ncap} setlinecap"
end

#lineJoin=(x) ⇒ Object



374
375
# File 'lib/IFMapper/FXDCPostscript.rb', line 374

def lineJoin=(x)
end

#lineStyle=(x) ⇒ Object



357
358
359
360
361
362
363
# File 'lib/IFMapper/FXDCPostscript.rb', line 357

def lineStyle=(x)
  if x == LINE_SOLID
    @f.puts "[ ] 0 setdash"
  elsif x == LINE_ONOFF_DASH
    @f.puts "[2 2] 0 setdash"
  end
end

#lineWidthObject



384
385
386
# File 'lib/IFMapper/FXDCPostscript.rb', line 384

def lineWidth
  return @lineWidth
end

#lineWidth=(x) ⇒ Object



388
389
390
391
# File 'lib/IFMapper/FXDCPostscript.rb', line 388

def lineWidth=(x)
  @lineWidth = x
  @f.puts "%f setlinewidth" % [x * 0.5]
end

#setContentRange(xmin, ymin, xmax, ymax) ⇒ Object



11
12
13
14
15
16
# File 'lib/IFMapper/FXDCPostscript.rb', line 11

def setContentRange(xmin, ymin, xmax, ymax)
  @pxmin = xmin.to_f
  @pymin = ymin.to_f
  @pxmax = xmax.to_f
  @pymax = ymax.to_f
end

#tfm(xi, yi) ⇒ Object

Transform point



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/IFMapper/FXDCPostscript.rb', line 19

def tfm(xi, yi)
  pxrange = @pxmax - @pxmin
  pyrange = @pymax - @pymin

  if @flags & PRINT_LANDSCAPE != 0
    mxmin = @ymin.to_f
    mxmax = @ymax.to_f
    mymin = @width - @xmax
    mymax = @width - @xmin
    mxrange = mxmax - mxmin
    myrange = mymax - mymin
  else
    mxmin = @xmin
    mxmax = @xmax
    mymin = @ymin
    mymax = @ymax
    mxrange = mxmax-mxmin
    myrange = mymax-mymin
  end

  if pyrange/pxrange <= myrange/mxrange
    # short/wide
    xo = mxmin + ((xi.to_f-@pxmin)/pxrange) * mxrange;
    yo = mymin + 0.5 * (myrange-pyrange * (mxrange/pxrange)) + 
 (pyrange-yi.to_f) * (mxrange/pxrange)
  else
    # tall/thin
    xo = mxmin + 0.5 * (mxrange-pxrange * (myrange/pyrange)) + 
	xi * (myrange/pyrange)
    yo = mymin + ((pyrange-yi.to_f)/pyrange) * myrange
  end
  return [xo, yo]
end