qd.pl
上传用户:qdrechuli
上传日期:2022-08-01
资源大小:917k
文件大小:32k
源码类别:

视频捕捉/采集

开发平台:

Visual C++

  1. #!/usr/local/bin/perl
  2. # $Id: qd.pl,v 1.2 1994/09/29 01:24:24 lstein Exp $
  3. # This is a package of routines that let you create Macintosh 
  4. # PICT files from within perl.  It implements a subset of Quickdraw
  5. # drawing commands, primarily those related to line drawing, rectangles,
  6. # ovals, polygons, and text.  Flagrantly absent are: regions and the 
  7. # snazzy color transfer modes.  Regions are absent because they were
  8. # more trouble than I had time for, and the transfer modes because I
  9. # never use them.  (The latter shouldn't be too hard to add.)  Also 
  10. # missing are the pixmap commands.  If you want to do pixmaps, you
  11. # should be using the ppm utilities.
  12. # A QUICK TUTORIAL ON QUICKDRAW
  13. # Quickdraw is not Postscript.  You cannot write routines in it or get
  14. # (any useful) information out of it.  Quickdraw pictures are a series of
  15. # drawing commands, concatenated together in a binary format.
  16. #
  17. # A Macintosh picture consists of a header describing the size of the
  18. # picture and its bounding rectangle, followed by a series of drawing
  19. # commands, followed by a termination code.  This perl library is
  20. # modeled closely on the way that you would draw a picture on the Mac.
  21. # First you open the picture with the &qd'OpenPicture() command.  This
  22. # initializes some data structures.  Then you call a series of drawing
  23. # subroutines, such as &qd'TextFont(), &qd'MoveTo(), &qd'DrawString().
  24. # These routines append their data to the growing (but still private)
  25. # picture.  You then close the picture with &qd'ClosePicture.  This
  26. # returns a scalar variable containing the binary picture data.
  27. # RECTANGLES
  28. #
  29. # To open a picture you need to define a rectangle that will serve as
  30. # its frame and will define its drawing area.  The rectangle is (of 
  31. # course) a binary structure.  The following utilities allow you to
  32. # create and manipulate rectangles:
  33. #
  34. #   &qd'SetRect(*myRect,left,top,right,bottom); # Set the sides of $myRect
  35. #   &qd'OffsetRect(*myRect,deltaH,deltaV);      # Shift the rectangle as indicated
  36. #   &qd'InsetRect(*myRect,deltaH,deltaV);       # Shrink rectangle by size indicated
  37. # OPENING A PICTURE
  38. #
  39. # Pass a previously-defined rectangle to the routine OpenPicture.  Only one picture
  40. # may be open at a time.  The rectangle defines the drawing area in pixels.
  41. # A printer page is 8.5 x 11 inches, at 72 pixels per inch = 612 x 792 pixels.
  42. #
  43. #   &qd'OpenPicture($myRect);
  44. #
  45. # You will next very likely want to set the clipping rectangle to the same rectangle
  46. # you used to open the picture with.  Clipping rectangles limit quickdraw's drawing
  47. # to the area within the rectangle.  Even if you don't use clipping, however, it's a
  48. # good idea to define the rectangle because some drawing programs behave eratically
  49. # when displaying unclipped pictures.
  50. # You then issue drawing commands.  When you're done you can get the picture data with
  51. # something like $pictData = &qd'ClosePicture;
  52. # SETTING THE FOREGROUND AND BACKGROUND COLORS
  53. #
  54. # The foreground color is the color of the ink when a "frame" or "paint" command
  55. # is given.  The background color is the color of the erased area when an "erase"
  56. # command is given.  The defaults are black and white.  The colors can be changed
  57. # in either of two ways:
  58. #
  59. #  1. The "old" 8-color system: black, white, red, green, blue, cyan, magenta, yellow
  60. #     Call the routines &qd'FgColor() and &qd'BgColor() with one of the constants
  61. #     $qd'REDCOLOR,$qd'GREENCOLOR, etc.  This gives you a limited number of highly
  62. #     satured colors.
  63. #
  64. #  2. The new 24-bit color system.  Call the routines &qd'RGBForeColor() and 
  65. #     &qd'RGBBackColor(), passing the routines the red, green and blue components
  66. #     of the color.  These components are two-byte unsigned integers, so you can choose
  67. #     any value between 0x000 and 0xFFFF.  Higher is darker, so:
  68. #     (0x0000,0x0000,0x0000) = BLACK
  69. #     (0xFFFFF,0xFFFF,0xFFFF) = WHITE
  70. #     (0xFFFFF,0x0000,0x0000) = PURE RED
  71. #     etc.
  72. # SETTING THE PATTERN
  73. #
  74. # Like colors, the drawing commands use the current pattern, a 32 row x 32 column 
  75. # bit array that defines the pattern of the "ink".
  76. # The default pattern is $qd'BLACK, which is solid black.  The only
  77. # other pattern I've defined is $qd'GRAY, which is a 50% checkerboard.  You
  78. # might want to define others.
  79. #
  80. # The current pattern is set using &qd'PenPat($myPattern).
  81. # LINE DRAWING
  82. #
  83. # Quickdraw has the concept of the "current point" of the pen.  Generally
  84. # you move the pen to a point and then start drawing.  The next time you draw,
  85. # the pen will be wherever the last drawing command left it.  In addition, the
  86. # pen has a width, a pattern and a color.  In the below descriptions, 
  87. # h=horizontal, v=vertical
  88. #
  89. # &qd'MoveTo(h,v)           # Move to indicated coordinates (0,0 is upper left of picture)
  90. # &qd'LineTo(h,v)           # Draw from current position to indicated position
  91. # &qd'Line(dh,dv)           # Draw a line dh pixels horizontally, dv pixels vertically,
  92. #                             starting at current position
  93. # &qd'PenSize(h,v)          # Set the size of the pen to h pixels wide, v pixels high
  94. # PEN SCALING
  95. #
  96. # The original quickdraw was incapable of drawing at higher than the screen resolution,
  97. # so even if the PenSize is set to (1,1) the lines will appear chunky when printed out
  98. # on the laserwriter (which has four times the resolution of the screen).  Call 
  99. # &qd'Scale(1,4) to fix this problem by shrinking the pen down to a quarter of its
  100. # (1,1) size.
  101. #
  102. # &qd'Scale(numerator,denominator) # Scale the pen by the fraction numerator/denominator
  103. # TEXT
  104. #
  105. # &qd'TextFont(fontCode)    # Set the current font to indicated code.  Currently
  106. #                             defined fonts are $qd'TIMES, $qd'NEWCENTURYSCHOOLBK,
  107. #                             $qd'SYMBOL, $qd'HELVETICA, and $qd'COURIER.
  108. #
  109. # &qd'TextSize(size)        # Set the current font size (in points).  12 point is typical
  110. #
  111. # &qd'TextFace(attributes)  # Set one or more font style attributes.  Currently defined
  112. #                             are $qd'PLAIN, $qd'BOLD, $qd'ITALIC, $qd'UNDERLINE, and
  113. #                             can be used in combination: 
  114. #                             &qd'TextFace($qd'BOLD + $qd'ITALIC);
  115. #
  116. # &qd'DrawString(string)    # Draw the indicated text.  It will be drawn from the
  117. #                             current pen location.  Word wrap is NOT supported.
  118. #                             Rotated text is NOT supported.
  119. #
  120. # &qd'TextWidth(string)     # This will return an approximate width for the string
  121. #                             when it is printed in the current size, font and face.
  122. #                             Unfortunately, since perl has no access to the Macintosh
  123. #                             font description tables, the number returned by this
  124. #                             routine will be wildly inaccurate at best.
  125. #                             However, if you have X11R5 bdf fonts installed, we look 
  126. #                             in the directory $qd'X11FONTS in order to find a bdf metrics
  127. #                             font to use.  This will give you extremely accurate measurements.
  128. #                             Please set this variable to whatever is correct for your local
  129. #                             system.  To add more fonts, put them in your bdf font directory
  130. #                             and update the %qd'font_metric_files array at the bottom of this
  131. #                             file.  It maps a key consisting of the Quickdraw font number, 
  132. #                             font size, and font style (0 for plain, 1 for italic, 2 for bold,
  133. #                             3 for both) to the appropriate bdf file.
  134. # RECTANGLES
  135. #
  136. # Draw rectangles using the routines:
  137. #   &qd'FrameRect($myRect);                     # Draw wire-frame rectangle
  138. #   &qd'PaintRect($myRect);                     # Fill rectangle with current foreground
  139. #                                                 color and pattern
  140. #   &qd'EraseRect($myRect);                     # Erase the rectangle (fill with bg color)
  141. #   &qd'InvertRect($myRect);                    # Invert black and white in rectangle
  142. # OVALS
  143. #
  144. # Draw ovals using the routines:
  145. #   &qd'FrameOval($myRect);                     # Draw wire-frame oval
  146. #   &qd'PaintOval($myRect);                     # Fill oval with current foreground
  147. #                                                 color and pattern
  148. #   &qd'EraseOval($myRect);                     # Erase the oval (fill with bg color)
  149. #   &qd'InvertOval($myRect);                    # Invert black and white in oval
  150. #   &qd'FillOval($myRect,$pat);                 # Fill with specified pattern
  151. # ROUND RECTANGLES
  152. # Draw round-cornered rectangles with these routines.  They each take an oval radius
  153. # to determine the amount of curvature.  Values of 10-20 are typical.
  154. #   &qd'FrameRoundRect($myRect,$ovalWidth,$ovalHeight); # wire-frame outline
  155. #   &qd'PaintRoundRect($myRect,$ovalWidth,$ovalHeight); # fill with current foreground
  156. #   &qd'EraseRoundRect($myRect,$ovalWidth,$ovalHeight); # erase
  157. #   &qd'InvertRoundRect($myRect,$ovalWidth,$ovalHeight);# invert
  158. #   &qd'FillRoundRect($myRect,$ovalWidth,$ovalHeight,$pat); # fill with specified pattern
  159. # ARCS
  160. # Draw an arc subtending the specified rectangle.  Angles are in degrees and
  161. # start pointing northward and get larger clockwise:
  162. # e.g. PaintArc($r,45,90) gives you a pie wedge from 2 o'clock to 5 o'clock
  163. #   &qd'FrameArc($rect,$startAngle,$arcAngle);  # wire-frame the arc
  164. #   &qd'PaintArc($rect,$startAngle,$arcAngle);  # fill with current foreground
  165. #   &qd'EraseArc($rect,$startAngle,$arcAngle);  # erase arc
  166. #   &qd'InvertArc($rect,$startAngle,$arcAngle);  # flip white and black
  167. #   &qd'FillArc($rect,,$startAngle,$arcAngle,$pat);  # fill with specified pattern
  168. # POLYGONS
  169. # Calling OpenPoly returns the name of a variable in which a growing
  170. # polygon structure will be stored.  Once a polygon is opened, all drawing
  171. # commands cease to have an effect on the picture.  Instead, all MoveTo,
  172. # LineTo and Line commands accumulate polygon vertices into the data structure.
  173. # Call ClosePoly to stop recording drawing commands.  The polygon can now
  174. # be moved, scaled, drawn, filled and erased as many times as wished.  Call
  175. # KillPoly to release the memory taken up by the polygon
  176. #   $polygon = &qd'OpenPoly;                      # begin recording drawing commands
  177. #   &qd'ClosePoly($polygon);                      # stop recording drawing commands
  178. #   &qd'FramePoly($polygon);                      # wire-frame the polygon
  179. #   &qd'PaintPoly($polygon);                      # fill with current foreground
  180. #   &qd'ErasePoly($polygon);                      # erase polygon
  181. #   &qd'FillPoly($polygon,$pat);                  # fill polygon with pattern
  182. #   &qd'OffsetPoly($polygon,$dh,$dv);             # translate poly by dh horizontally, dv vertically
  183. #   &qd'MapPoly($polygon,$srcRect,$destRect);     # map polygon from coordinate system defined by
  184.                                                   #  source rectangle to that defined by destination
  185.                                                   #  rectangle (moving or resizing it as needed)
  186. # PRINTING OUT THE PICTURE IN A FORM THAT THE MACINTOSH CAN READ
  187. #
  188. # The Mac expects its picture files to begin with 512 bytes of "application specific"
  189. # data.  By default the picture data that you get will be proceeded by 512 bytes of
  190. # 0's.  If you want something else, or if you just want the picture data, set the
  191. # package variable $qd'PICTHEADER to whatever you desire before calling ClosePicture.
  192. # In order for the picture data to be readable on the Macintosh, the file type must
  193. # be set to 'PICT'.  A number of UNIX utilities, including mcvert and BinHex allow
  194. # you to do this.  Or you can use the picttoppm utility (part of the netppm suite of
  195. # graphics tools) to translate the file into any format you desire.
  196. # A WORKING EXAMPLE
  197. # require "qd.pl";
  198. # &qd'SetRect(*myRect,0,0,500,500);          # Define a 500 pixel square
  199. # &qd'OpenPicture($myRect);                  # Begin defining the picture
  200. # &qd'ClipRect($myRect);                     # Always a good idea
  201. # &qd'MoveTo(5,5);                           # Move the pen to a starting point
  202. # &qd'LineTo(400,400);                       # A diagonal line
  203. # &qd'TextFont($qd'COURIER);                 # Set the font
  204. # &qd'MoveTo(50,20);                         # Move the pen to a new starting point
  205. # &qd'DrawString("Hello there!");            # Friendly greeting
  206. # &qd'SetRect(*myRect,80,80,250,250);        # New rectangle
  207. # &qd'RGBForeColor(0x0000,0x0000,0xFFFF);    # Set the color to blue
  208. # &qd'PaintRect($myRect);                    # Fill rectangle with that color
  209. # $data = &qd'ClosePicture;                  # Close picture and retrieve data
  210. #  # Pipe through binhex, setting the creator type to JVWR for JPEG Viewer
  211. #  # Note: BinHex is available at <ftp://genome.wi.mit.edu/software/util/BinHex>
  212. # open (BINHEX "| BinHex -t PICT -c JVWR -n 'An Example'"); 
  213. # print BINHEX $data;
  214. # close BINHEX;
  215. # # Turn it into a GIF file, using the ppm utilities
  216. # open (GIF, "| picttoppm | ppmtogif -transparent white");
  217. # print GIF $data;
  218. # close GIF;
  219. # MISCELLANEOUS NOTES
  220. # NOTE: For some reason the various FILL routines don't work as
  221. # advertised.  They are simulated by a PnPat followed by a paint
  222. # --------------------------------------------------------------------
  223. # Quickdraw-like functions -- now using PICT2
  224. # --------------------------------------------------------------------
  225. {
  226. package qd;
  227. # Directory to look in to find font metric definitions -- change this
  228. # for your installation
  229. $X11FONTS = '/usr/local/X11R5/X11/fonts/bdf';
  230. # Apple quickdraw constants
  231. $TIMES = 20;
  232. $HELVETICA = 21;
  233. $COURIER = 22;
  234. $SYMBOL = 23;
  235. $NEWCENTURYSCHOOLBK = 34;
  236. $PLAIN = 0;
  237. $BOLD = 1;
  238. $ITALIC = 2;
  239. $UNDERLINE = 4;
  240. # Some minimal patterns -- define your own if you like
  241. $GRAY = pack ('n4',0xAA55,0xAA55,0xAA55,0xAA55);
  242. $DKGRAY = pack ('n4',0xDD77,0xDD77,0xDD77,0xDD77);
  243. $LTGRAY = pack ('n4',0x8822,0x8822,0x8822,0x8822);
  244. $WHITE = pack('n4',0x0000,0x0000,0x0000,0x0000);
  245. $BLACK = pack ('n4',0xFFFF,0xFFFF,0xFFFF,0xFFFF);
  246. # absolute colors to be used with FgColor/BgColor
  247. # (for better control, use RGBFgColor/RGBBgColor)
  248. $BLACKCOLOR = 33;
  249. $WHITECOLOR = 30;
  250. $REDCOLOR = 209;
  251. $GREENCOLOR = 329;
  252. $BLUECOLOR = 389;
  253. $CYANCOLOR = 269;
  254. $MAGENTACOLOR = 149;
  255. $YELLOWCOLOR = 89;
  256. # This defines the header used at the beginning of PICT files:
  257. $PICTHEADER = "" x 512;
  258. # These are phoney font metrics which we use when no font metrics files are
  259. # around to help us out.
  260. $fudgefactor = 0.55;
  261. $ITALICEXTRA = 0.05;
  262. $BOLDEXTRA = 0.08;
  263. # Initial starting values
  264. $textFont = $HELVETICA;
  265. $textSize = 12;
  266. $textFace = $PLAIN;
  267. $rgbfgcolor = pack('n*',0xFFFF,0xFFFF,0xFFFF);
  268. $rgbbgcolor = pack('n*',0,0,0);
  269. $fgcolor = $BLACKCOLOR;
  270. $bgcolor = $WHITECOLOR;
  271. $polySave = undef;
  272. $_PnPattern = $BLACK;
  273. $_polyName = "polygon000";
  274. sub OpenPicture {               # begin a picture
  275.     local($rect) = @_;
  276.     $currH = $currV = 0;        # current pen position
  277.     $pict = $PICTHEADER;        # the header
  278.     $pict .= pack('n',0);       # size int (placeholder)
  279.     $pict .= $rect;             # pict frame
  280.     $pict .= pack('n',0x0011);  # Type 2 picture
  281.     $pict .= pack('n',0x02FF);  # version number
  282.     $pict .= pack('nC24',0x0C00,0);     # reserved header opcode + 24 bytes of reserved data
  283.     # initialize the font and size
  284.     &TextFont($textFont);
  285.     &TextSize($textSize);
  286.     &TextFace($textFace);
  287. }
  288. sub ClosePicture {              # close pict and return it
  289.     $pict .= pack ('n',0x00FF); # end of pict code
  290.     substr($pict,512,2) = pack('n',length($pict) - 512); # fill in length 
  291.     return $pict;
  292. }
  293. sub ClipRect {
  294.     local($rect) = @_;
  295.     $pict .= pack('nn',0x0001,0x0A) . $rect;
  296. }
  297. sub PenPat {
  298.     local($newpat) = @_;
  299.     return unless $newpat ne $_PnPattern;
  300.     $_PnPattern = $newpat;
  301.     $pict .= pack('n',0x0009) . $_PnPattern;
  302. }
  303. sub RGBForeColor {
  304.     local($rgb) = pack('n3',@_);
  305.     return unless $rgb ne $rgbfgcolor;
  306.     $rgbfgcolor = $rgb;
  307.     $pict .= pack('n',0x001A) . $rgbfgcolor;
  308. }
  309. sub RGBBackColor {
  310.     local($rgb) = pack('n3',@_);
  311.     return unless $rgb ne $rgbbgcolor;
  312.     $rgbbgcolor = $rgb;
  313.     $pict .= pack('n',0x001B) . $rgbbgcolor;
  314. }
  315. sub FgColor {
  316.     local($color) = @_;
  317.     return unless $color != $fgcolor;
  318.     $fgcolor = $color;
  319.     $pict .= pack('nL',0x000E,$color);
  320. }
  321. sub BgColor {
  322.     local($color) = @_;
  323.     return unless $color != $bgcolor;
  324.     $bgcolor = $color;
  325.     $pict .= pack('nL',0x000F,$color);
  326. }
  327. sub TextFont {
  328.     local($font) = @_;
  329.     $textFont = $font;
  330.     $pict .= pack('nn',0x0003,$font);
  331. }
  332. sub TextSize {
  333.     local($size) = @_;
  334.     $textSize = $size;
  335.     $pict .= pack('nn',0x000D,$size);
  336. }
  337. sub PenSize {
  338.     local($h,$v) = @_;
  339.     $pict .= pack('nnn',0x0007,$v,$h);
  340. }
  341. sub TextFace {
  342.     return if $textFace == @_[0];
  343.     $textFace = @_[0];
  344.     $pict .= pack ('nCC',0x0004,$textFace,0); # (zero added to pad to word)
  345. }
  346. sub DrawString {
  347.     local($text) = @_;
  348.     $text .= "" x ((length($text) + 1) % 2); # pad text to an odd length
  349.     $pict .= pack('nnnC',0x0028,$currV,$currH,length($text)) . $text;
  350. }
  351. # RECTANGLE MANIPULATION ROUTINES.  Note that
  352. # the rectangles are passed by NAME rather than by value,
  353. # in accordance with the MacOS way of doing things.
  354. sub SetRect {
  355.     local(*r,$h1,$v1,$h2,$v2) = @_;
  356.     $r = pack ('n4',$v1,$h1,$v2,$h2);
  357. }
  358. sub OffsetRect {
  359.     local(*r,$x,$y) = @_;
  360.     local($v1,$h1,$v2,$h2) = unpack('n4',$r);
  361.     $h1 += $x; $h2 += $x;
  362.     $v1 += $y; $v2 += $y;
  363.     $r = pack ('n4',$v1,$h1,$v2,$h2);    
  364. }
  365. sub InsetRect {
  366.     local(*r,$x,$y) = @_;
  367.     local($v1,$h1,$v2,$h2) = unpack('n4',$r);
  368.     $h1 -= int($x/2); $h2 -= int($x/2);
  369.     $v1 -= int($y/2); $v2 -= int($y/2);
  370.     $r = pack ('n4',$v1,$h1,$v2,$h2);    
  371. }
  372. # A few utility routine to translate between perl
  373. # arrays and rectangles.
  374. # four-element perl array to quickdraw rect structure
  375. sub a2r {
  376.     local($top,$left,$bottom,$right) = @_;
  377.     return pack('n4',$top,$left,$bottom,$right);
  378. }
  379. # rectangle to four-element perl array
  380. sub r2a {
  381.     local($rect) = @_;
  382.     return unpack('n4',$rect);
  383. }
  384. # associative array in which the keys are 'top','left','bottom','right'
  385. # to quickdraw rect structure
  386. sub aa2r {
  387.     local(%r) = @_;
  388.     return pack('n4',$r{'top'},$r{'left'},$r{'bottom'},$r{'right'});
  389. }
  390. # quickdraw rect structure to associative array
  391. sub r2aa {
  392.     local($r) = @_;
  393.     local(%r);
  394.     ($r{'top'},$r{'left'},$r{'bottom'},$r{'right'}) = unpack('n4',$r);
  395.     return %r;
  396. }
  397. # LINE DRAWING ROUTINES
  398. sub MoveTo {
  399.     ($currH,$currV) = @_;
  400. }
  401. sub Move {
  402.     local($dh,$dv) = @_;
  403.     $currH += $dh;
  404.     $currV += $dv;
  405. }
  406. sub LineTo {
  407.     local($h,$v) = @_;
  408.     # Special handling for polygons
  409.     if (defined(@polySave)) {
  410.         &_addVertex(*polySave,$h,$v)
  411.     } else {
  412.         $pict .= pack('nn4',0x0020,$currV,$currH,$v,$h);
  413.     }
  414.     ($currH,$currV) = ($h,$v);
  415. }
  416. sub Line {
  417.     local($dh,$dv) = @_;
  418.     # Special handling for polygons
  419.     if (defined(@polySave)) {
  420.         &_addVertex(*polySave,$h,$v);
  421.     } else {
  422.         $pict .= pack('nn4',0x0020,$currV,$currH,$currV+$dv,$currH+$dh);
  423.     }
  424.     ($currH,$currV) = ($currH+$dh,$currV+$dv);
  425. }
  426. sub Scale { #use picComment to set laserwriter line scaling
  427.     local($numerator,$denominator)= @_;
  428.     $pict .= pack('nnnn2',0x00A1,182,4,$numerator,$denominator);
  429. }
  430. # Rectangles
  431. sub FrameRect {
  432.     local($rect) = @_;
  433.     $pict .= pack('n',0x0030) . $rect;
  434. }
  435. sub PaintRect {
  436.     local($rect) = @_;
  437.     $pict .= pack('n',0x0031) . $rect;
  438. }
  439. sub EraseRect {
  440.     local($rect) = @_;
  441.     $pict .= pack('n',0x0032) . $rect;
  442. }
  443. sub InvertRect {
  444.     local($rect) = @_;
  445.     $pict .= pack('n',0x0033) . $rect;
  446. }
  447. sub FillRect {
  448.     local($rect,$pattern) = @_;
  449.     local($oldpat) = $_PnPattern;
  450.     &PenPat($pattern);
  451.     &PaintRect($rect);
  452.     &PenPat($oldpat);
  453. }
  454. # Ovals
  455. sub FrameOval {
  456.     local($rect) = @_;
  457.     $pict .= pack('n',0x0050) . $rect;
  458. }
  459. sub PaintOval {
  460.     local($rect) = @_;
  461.     $pict .= pack('n',0x0051) . $rect;
  462. }
  463. sub EraseOval {
  464.     local($rect) = @_;
  465.     $pict .= pack('n',0x0052) . $rect;
  466. }
  467. sub InvertOval {
  468.     local($rect) = @_;
  469.     $pict .= pack('n',0x0053) . $rect;
  470. }
  471. sub FillOval {
  472.     local($rect,$pattern) = @_;
  473.     local($oldpat) = $_PnPattern;
  474.     &PenPat($pattern);
  475.     &PaintOval($rect);
  476.     &PenPat($oldpat);
  477. }
  478. # Arcs
  479. sub FrameArc {
  480.     local($rect,$startAngle,$arcAngle) = @_;
  481.     $pict .= pack('n',0x0060) . $rect;
  482.     $pict .= pack('nn',$startAngle,$arcAngle);
  483. }
  484. sub PaintArc {
  485.     local($rect,$startAngle,$arcAngle) = @_;
  486.     $pict .= pack('n',0x0061) . $rect;
  487.     $pict .= pack('nn',$startAngle,$arcAngle);
  488. }
  489. sub EraseArc {
  490.     local($rect,$startAngle,$arcAngle) = @_;
  491.     $pict .= pack('n',0x0062) . $rect;
  492.     $pict .= pack('nn',$startAngle,$arcAngle);
  493. }
  494. sub InvertArc {
  495.     local($rect,$startAngle,$arcAngle) = @_;
  496.     $pict .= pack('n',0x0063) . $rect;
  497.     $pict .= pack('nn',$startAngle,$arcAngle);
  498. }
  499. sub FillArc {
  500.     local($rect,$startAngle,$arcAngle,$pattern) = @_;
  501.     local($oldpat) = $_PnPattern;
  502.     &PenPat($pattern);
  503.     &PaintArc($rect,$startAngle,$arcAngle);
  504.     &PenPat($oldpat);
  505. }
  506. # Round rects
  507. sub FrameRoundRect {
  508.     local($rect,$ovalWidth,$ovalHeight) = @_;
  509.     unless ($_roundRectCurvature eq "$ovalWidth $ovalHeight") {
  510.         $pict .= pack('nn2',0x000B,$ovalHeight,$ovalWidth);
  511.         $_roundRectCurvature = "$ovalWidth $ovalHeight";
  512.     }
  513.     $pict .= pack('n',0x0040) . $rect;
  514. }
  515. sub PaintRoundRect {
  516.     local($rect,$ovalWidth,$ovalHeight) = @_;
  517.     unless ($_roundRectCurvature eq "$ovalWidth $ovalHeight") {
  518.         $pict .= pack('nn2',0x000B,$ovalHeight,$ovalWidth);
  519.         $_roundRectCurvature = "$ovalWidth $ovalHeight";
  520.     }
  521.     $pict .= pack('n',0x0041) . $rect;
  522. }
  523. sub EraseRoundRect {
  524.     local($rect,$ovalWidth,$ovalHeight) = @_;
  525.     unless ($_roundRectCurvature eq "$ovalWidth $ovalHeight") {
  526.         $pict .= pack('nn2',0x000B,$ovalHeight,$ovalWidth);
  527.         $_roundRectCurvature = "$ovalWidth $ovalHeight";
  528.     }
  529.     $pict .= pack('n',0x0042) . $rect;
  530. }
  531. sub InvertRoundRect {
  532.     local($rect,$ovalWidth,$ovalHeight) = @_;
  533.     unless ($_roundRectCurvature eq "$ovalWidth $ovalHeight") {
  534.         $pict .= pack('nn2',0x000B,$ovalHeight,$ovalWidth);
  535.         $_roundRectCurvature = "$ovalWidth $ovalHeight";
  536.     }
  537.     $pict .= pack('n',0x0043) . $rect;
  538. }
  539. sub FillRoundRect {
  540.     local($rect,$ovalWidth,$ovalHeight,$pattern) = @_;
  541.     local($oldpat) = $_PnPattern;
  542.     &PenPat($pattern);
  543.     &PaintRoundRect($rect,$ovalWidth,$ovalHeight);
  544.     &PenPat($oldpat);
  545. }
  546. # Polygons -- you are only allowed to create one polygon at a time.
  547. # You will be returned a "handle" which contains the growing polygon
  548. # structure.  The "handle" is actually the NAME of the scalar
  549. sub OpenPoly {
  550.     $_polyName++;
  551.     undef $polySave;            # close one if it was already defined
  552.     *polySave = $_polyName;
  553.     @polySave = (10,0,0,0,0); # initialize it to empty size and rectangle
  554.     return $_polyName;
  555. }
  556.  
  557. sub ClosePoly {
  558.     *polySave = 'scratch';
  559.     undef @polySave;
  560. }
  561. # Kill the poly -- really a no-op in perl
  562. sub KillPoly {
  563.     local(*poly) = @_;
  564.     undef @poly;
  565. }
  566. # Polygon drawing
  567. sub FramePoly {
  568.     local(*poly) = @_;
  569.     return unless @poly;
  570.     $pict .= pack('n*',0x0070,@poly);
  571. }
  572. sub PaintPoly {
  573.     local(*poly) = @_;
  574.     return unless @poly;
  575.     $pict .= pack('n*',0x0071,@poly);
  576. }
  577. sub ErasePoly {
  578.     local(*poly) = @_;
  579.     return unless @poly;
  580.     $pict .= pack('n*',0x0072,@poly);
  581. }
  582. sub InvertPoly {
  583.     local(*poly) = @_;
  584.     return unless @poly;
  585.     $pict .= pack('n*',0x0073,@poly);
  586. }
  587. sub FillPoly {
  588.     local(*poly,$pattern) = @_;
  589.     return unless @poly;
  590.     local($oldpat) = $_PnPattern;
  591.     &PenPat($pattern);
  592.     &PaintPoly(*poly);
  593.     &PenPat($oldpat);
  594. }
  595. sub OffsetPoly {
  596.     local(*poly,$dh,$dv) = @_; 
  597.   return unless @poly;
  598.     local($size,@vertices) = @poly;
  599.     local($i);
  600.     for ($i=0;$i<@vertices;$i+=2) {
  601.         $vertices[$i] += $dv;
  602.         $vertices[$i+1] += $dh;
  603.     }
  604.     @poly = ($size,@vertices);
  605. }
  606. sub MapPoly {
  607.     local(*poly,$srcRect,$destRect) = @_;
  608.     return unless @poly;
  609.     local($size,@vertices) = @poly;
  610.     local(@src) = unpack('n4',$srcRect);
  611.     local(@dest) = unpack('n4',$destRect);
  612.     local($factorV) = ($dest[2]-$dest[0])/($src[2]-$src[0]);
  613.     local($factorH) = ($dest[3]-$dest[1])/($src[3]-$src[1]);
  614.     for ($i=0;$i<@vertices;$i+=2) {
  615.         $vertices[$i] = int($dest[0] + ($vertices[$i] - $src[0]) * $factorV);
  616.         $vertices[$i+1] = int($dest[1] + ($vertices[$i+1] - $src[1]) * $factorH);
  617.     }
  618.     @poly = ($size,@vertices);
  619. }
  620. # A utility routine to add a vertex to the growing polygon structure
  621. # We need to grow both the size of the polygon and increase the bounding
  622. # rectangle.  A special case occurs when we add the first vertex:
  623. # we store both the current position 
  624. sub _addVertex {
  625.     local(*polygon,$h,$v) = @_;
  626.     local($size,$top,$left,$bottom,$right,@vertices) = @polygon;
  627.     # Special case for empty vertices -- add the current point
  628.     unless (@vertices) {
  629.         push(@vertices,$currV,$currH);
  630.         $size += 4;
  631.         $top = $bottom = $currV;
  632.         $left = $right = $currH;
  633.     }
  634.     # IM V1 implies that all vertices are stored relative to
  635.     # the first point -- I don't know if this is really the case
  636.     push (@vertices,$v,$h);
  637.     $size += 4;
  638.     $top = $v if $v < $top;
  639.     $bottom = $v if $v > $bottom;
  640.     $left = $h if $h < $left;
  641.     $right = $h if $h > $right;
  642.     @polygon=($size,$top,$left,$bottom,$right,@vertices);
  643. }
  644. # We try to get the metrics from an X11 bdf font file, if possible.
  645. sub TextWidth {
  646.     local($text) = @_;
  647.     # See if we can derive the character widths from a metrics file
  648.     local($face) = 0xFB & $textFace; # underlining don't count
  649.     local($metric_name) = &_getFontMetrics($textFont,$textSize,$face);
  650.     if ($metric_name && (*metrics = $metric_name) && defined(%metrics)) {
  651.         local($length);
  652.         foreach (split('',$text)) {
  653.             $length += $metrics{ord($_)};
  654.         }
  655.         return $length;
  656.     } else {                    # we get here if we don't have any metrics - make it up
  657.         local($extra);
  658.         $extra += $ITALICEXTRA if vec($textFace,$ITALIC,1);
  659.         $extra += $BOLDEXTRA if vec($textFace,$BOLD,1);
  660.         return length($text) * $textSize * ($fudgefactor+$extra);
  661.     }
  662. }
  663. # Utility routine to read text widths out of bdf files.  We create a metrics
  664. # array on the fly.  The names of the metrics files are stored in an array
  665. # called _metricsArrays.  We return the name of the array, or undef if inapplicable.
  666. sub _getFontMetrics {
  667.     local($font,$size,$face) = @_;
  668.     local($key) = "$font $size $face";
  669.     return $_metricsArrays{$key} if $_metricsArrays{$key};
  670.     # If we get here, we don't have a metrics array to return.  See if we can
  671.     # construct one from a bdf file.
  672.     # Don't bother unless this font is defined.
  673.     return undef unless $font_metric_files{$key};
  674.     # Don't bother if we tried before and failed
  675.     return undef if $_failed_metric{$key};
  676.     # Try to open up the bdf file.  Remember if we fail
  677.     unless (open(BDF,"$font_metric_files{$key}")) {
  678.         $_failed_metric_files{$key}++;
  679.         return undef;
  680.     }
  681.     # Wow! We're golden.  Create a new metrics array
  682.     $next_metric++;             # bump up the name
  683.     local(*metrics) = $next_metric; local($char);
  684.     while (<BDF>) {
  685.         next unless /^STARTCHAR/../^ENDCHAR/;
  686.         if (/^ENCODINGs+(d+)/) { $char = $1; }
  687.         elsif (/^DWIDTHs+(d+)/)   { $metrics{$char}=$1; }
  688.     }
  689.     close(BDF);
  690.     
  691.     # Remember the name of the metrics array and return it
  692.     return $_metricsArrays{$key} = $next_metric;
  693. }
  694. # Ugly stuff that I want to hide at the bottom
  695. # For the purposes of mapping from quickdraw fonts to X11fonts, we define
  696. # the following dictionary:
  697. %font_metric_files = (
  698.                       "22 8 1","$X11FONTS/courB08.bdf",
  699.                       "22 10 1","$X11FONTS/courB10.bdf",
  700.                       "22 12 1","$X11FONTS/courB12.bdf",
  701.                       "22 14 1","$X11FONTS/courB14.bdf",
  702.                       "22 18 1","$X11FONTS/courB18.bdf",
  703.                       "22 24 1","$X11FONTS/courB24.bdf",
  704.                       "22 8 2","$X11FONTS/courO08.bdf",
  705.                       "22 10 2","$X11FONTS/courO10.bdf",
  706.                       "22 12 2","$X11FONTS/courO12.bdf",
  707.                       "22 14 2","$X11FONTS/courO14.bdf",
  708.                       "22 18 2","$X11FONTS/courO18.bdf",
  709.                       "22 24 2","$X11FONTS/courO24.bdf",
  710.                       "22 8 0","$X11FONTS/courR08.bdf",
  711.                       "22 10 0","$X11FONTS/courR10.bdf",
  712.                       "22 12 0","$X11FONTS/courR12.bdf",
  713.                       "22 14 0","$X11FONTS/courR14.bdf",
  714.                       "22 18 0","$X11FONTS/courR18.bdf",
  715.                       "22 24 0","$X11FONTS/courR24.bdf",
  716.                       "21 8 1","$X11FONTS/helvB08.bdf",
  717.                       "21 10 1","$X11FONTS/helvB10.bdf",
  718.                       "21 12 1","$X11FONTS/helvB12.bdf",
  719.                       "21 14 1","$X11FONTS/helvB14.bdf",
  720.                       "21 18 1","$X11FONTS/helvB18.bdf",
  721.                       "21 24 1","$X11FONTS/helvB24.bdf",
  722.                       "21 8 2","$X11FONTS/helvO08.bdf",
  723.                       "21 10 2","$X11FONTS/helvO10.bdf",
  724.                       "21 12 2","$X11FONTS/helvO12.bdf",
  725.                       "21 14 2","$X11FONTS/helvO14.bdf",
  726.                       "21 18 2","$X11FONTS/helvO18.bdf",
  727.                       "21 24 2","$X11FONTS/helvO24.bdf",
  728.                       "21 8 0","$X11FONTS/helvR08.bdf",
  729.                       "21 10 0","$X11FONTS/helvR10.bdf",
  730.                       "21 12 0","$X11FONTS/helvR12.bdf",
  731.                       "21 14 0","$X11FONTS/helvR14.bdf",
  732.                       "21 18 0","$X11FONTS/helvR18.bdf",
  733.                       "21 24 0","$X11FONTS/helvR24.bdf",
  734.                       "20 8 1","$X11FONTS/timB08.bdf",
  735.                       "20 10 1","$X11FONTS/timB10.bdf",
  736.                       "20 12 1","$X11FONTS/timB12.bdf",
  737.                       "20 14 1","$X11FONTS/timB14.bdf",
  738.                       "20 18 1","$X11FONTS/timB18.bdf",
  739.                       "20 24 1","$X11FONTS/timB24.bdf",
  740.                       "20 8 3","$X11FONTS/timBI08.bdf",
  741.                       "20 10 3","$X11FONTS/timBI10.bdf",
  742.                       "20 12 3","$X11FONTS/timBI12.bdf",
  743.                       "20 14 3","$X11FONTS/timBI14.bdf",
  744.                       "20 18 3","$X11FONTS/timBI18.bdf",
  745.                       "20 24 3","$X11FONTS/timBI24.bdf",
  746.                       "20 8 2","$X11FONTS/timI08.bdf",
  747.                       "20 10 2","$X11FONTS/timI10.bdf",
  748.                       "20 12 2","$X11FONTS/timI12.bdf",
  749.                       "20 14 2","$X11FONTS/timI14.bdf",
  750.                       "20 18 2","$X11FONTS/timI18.bdf",
  751.                       "20 24 2","$X11FONTS/timI24.bdf",
  752.                       "20 8 0","$X11FONTS/timR08.bdf",
  753.                       "20 10 0","$X11FONTS/timR10.bdf",
  754.                       "20 12 0","$X11FONTS/timR12.bdf",
  755.                       "20 14 0","$X11FONTS/timR14.bdf",
  756.                       "20 18 0","$X11FONTS/timR18.bdf",
  757.                       "20 24 0","$X11FONTS/timR24.bdf",
  758.                       "34 8 1","$X11FONTS/ncenB08.bdf",
  759.                       "34 10 1","$X11FONTS/ncenB10.bdf",
  760.                       "34 12 1","$X11FONTS/ncenB12.bdf",
  761.                       "34 14 1","$X11FONTS/ncenB14.bdf",
  762.                       "34 18 1","$X11FONTS/ncenB18.bdf",
  763.                       "34 24 1","$X11FONTS/ncenB24.bdf",
  764.                       "34 8 3","$X11FONTS/ncenBI08.bdf",
  765.                       "34 10 3","$X11FONTS/ncenBI10.bdf",
  766.                       "34 12 3","$X11FONTS/ncenBI12.bdf",
  767.                       "34 14 3","$X11FONTS/ncenBI14.bdf",
  768.                       "34 18 3","$X11FONTS/ncenBI18.bdf",
  769.                       "34 24 3","$X11FONTS/ncenBI24.bdf",
  770.                       "34 8 2","$X11FONTS/ncenI08.bdf",
  771.                       "34 10 2","$X11FONTS/ncenI10.bdf",
  772.                       "34 12 2","$X11FONTS/ncenI12.bdf",
  773.                       "34 14 2","$X11FONTS/ncenI14.bdf",
  774.                       "34 18 2","$X11FONTS/ncenI18.bdf",
  775.                       "34 24 2","$X11FONTS/ncenI24.bdf",
  776.                       "34 8 0","$X11FONTS/ncenR08.bdf",
  777.                       "34 10 0","$X11FONTS/ncenR10.bdf",
  778.                       "34 12 0","$X11FONTS/ncenR12.bdf",
  779.                       "34 14 0","$X11FONTS/ncenR14.bdf",
  780.                       "34 18 0","$X11FONTS/ncenR18.bdf",
  781.                       "34 24 0","$X11FONTS/ncenR24.bdf"
  782.                       );
  783. $next_metric = "metrics0000";   # name of our metrics arrays - dynamically allocated
  784. 1;
  785. }       #end of package qd