You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
6.8KB

  1. <?php
  2. class wmf
  3. {
  4. var $mpdf = null;
  5. var $gdiObjectArray;
  6. public function __construct(mPDF $mpdf)
  7. {
  8. $this->mpdf = $mpdf;
  9. }
  10. function _getWMFimage($data)
  11. {
  12. $k = _MPDFK;
  13. $this->gdiObjectArray = array();
  14. $a = unpack('stest', "\1\0");
  15. if ($a['test'] != 1)
  16. return array(0, 'Error parsing WMF image - Big-endian architecture not supported');
  17. // check for Aldus placeable metafile header
  18. $key = unpack('Lmagic', substr($data, 0, 4));
  19. $p = 18; // WMF header
  20. if ($key['magic'] == (int) 0x9AC6CDD7) {
  21. $p +=22;
  22. } // Aldus header
  23. // define some state variables
  24. $wo = null; // window origin
  25. $we = null; // window extent
  26. $polyFillMode = 0;
  27. $nullPen = false;
  28. $nullBrush = false;
  29. $endRecord = false;
  30. $wmfdata = '';
  31. while ($p < strlen($data) && !$endRecord) {
  32. $recordInfo = unpack('Lsize/Sfunc', substr($data, $p, 6));
  33. $p += 6;
  34. // size of record given in WORDs (= 2 bytes)
  35. $size = $recordInfo['size'];
  36. // func is number of GDI function
  37. $func = $recordInfo['func'];
  38. if ($size > 3) {
  39. $parms = substr($data, $p, 2 * ($size - 3));
  40. $p += 2 * ($size - 3);
  41. }
  42. switch ($func) {
  43. case 0x020b: // SetWindowOrg
  44. // do not allow window origin to be changed
  45. // after drawing has begun
  46. if (!$wmfdata)
  47. $wo = array_reverse(unpack('s2', $parms));
  48. break;
  49. case 0x020c: // SetWindowExt
  50. // do not allow window extent to be changed
  51. // after drawing has begun
  52. if (!$wmfdata)
  53. $we = array_reverse(unpack('s2', $parms));
  54. break;
  55. case 0x02fc: // CreateBrushIndirect
  56. $brush = unpack('sstyle/Cr/Cg/Cb/Ca/Shatch', $parms);
  57. $brush['type'] = 'B';
  58. $this->_AddGDIObject($brush);
  59. break;
  60. case 0x02fa: // CreatePenIndirect
  61. $pen = unpack('Sstyle/swidth/sdummy/Cr/Cg/Cb/Ca', $parms);
  62. // convert width from twips to user unit
  63. $pen['width'] /= (20 * $k);
  64. $pen['type'] = 'P';
  65. $this->_AddGDIObject($pen);
  66. break;
  67. // MUST create other GDI objects even if we don't handle them
  68. case 0x06fe: // CreateBitmap
  69. case 0x02fd: // CreateBitmapIndirect
  70. case 0x00f8: // CreateBrush
  71. case 0x02fb: // CreateFontIndirect
  72. case 0x00f7: // CreatePalette
  73. case 0x01f9: // CreatePatternBrush
  74. case 0x06ff: // CreateRegion
  75. case 0x0142: // DibCreatePatternBrush
  76. $dummyObject = array('type' => 'D');
  77. $this->_AddGDIObject($dummyObject);
  78. break;
  79. case 0x0106: // SetPolyFillMode
  80. $polyFillMode = unpack('smode', $parms);
  81. $polyFillMode = $polyFillMode['mode'];
  82. break;
  83. case 0x01f0: // DeleteObject
  84. $idx = unpack('Sidx', $parms);
  85. $idx = $idx['idx'];
  86. $this->_DeleteGDIObject($idx);
  87. break;
  88. case 0x012d: // SelectObject
  89. $idx = unpack('Sidx', $parms);
  90. $idx = $idx['idx'];
  91. $obj = $this->_GetGDIObject($idx);
  92. switch ($obj['type']) {
  93. case 'B':
  94. $nullBrush = false;
  95. if ($obj['style'] == 1) {
  96. $nullBrush = true;
  97. } else {
  98. $wmfdata .= $this->mpdf->SetFColor($this->mpdf->ConvertColor('rgb(' . $obj['r'] . ',' . $obj['g'] . ',' . $obj['b'] . ')'), true) . "\n";
  99. }
  100. break;
  101. case 'P':
  102. $nullPen = false;
  103. $dashArray = array();
  104. // dash parameters are custom
  105. switch ($obj['style']) {
  106. case 0: // PS_SOLID
  107. break;
  108. case 1: // PS_DASH
  109. $dashArray = array(3, 1);
  110. break;
  111. case 2: // PS_DOT
  112. $dashArray = array(0.5, 0.5);
  113. break;
  114. case 3: // PS_DASHDOT
  115. $dashArray = array(2, 1, 0.5, 1);
  116. break;
  117. case 4: // PS_DASHDOTDOT
  118. $dashArray = array(2, 1, 0.5, 1, 0.5, 1);
  119. break;
  120. case 5: // PS_NULL
  121. $nullPen = true;
  122. break;
  123. }
  124. if (!$nullPen) {
  125. $wmfdata .= $this->mpdf->SetDColor($this->mpdf->ConvertColor('rgb(' . $obj['r'] . ',' . $obj['g'] . ',' . $obj['b'] . ')'), true) . "\n";
  126. $wmfdata .= sprintf("%.3F w\n", $obj['width'] * $k);
  127. }
  128. if (!empty($dashArray)) {
  129. $s = '[';
  130. for ($i = 0; $i < count($dashArray); $i++) {
  131. $s .= $dashArray[$i] * $k;
  132. if ($i != count($dashArray) - 1) {
  133. $s .= ' ';
  134. }
  135. }
  136. $s .= '] 0 d';
  137. $wmfdata .= $s . "\n";
  138. }
  139. break;
  140. }
  141. break;
  142. case 0x0325: // Polyline
  143. case 0x0324: // Polygon
  144. $coords = unpack('s' . ($size - 3), $parms);
  145. $numpoints = $coords[1];
  146. for ($i = $numpoints; $i > 0; $i--) {
  147. $px = $coords[2 * $i];
  148. $py = $coords[2 * $i + 1];
  149. if ($i < $numpoints) {
  150. $wmfdata .= $this->_LineTo($px, $py);
  151. } else {
  152. $wmfdata .= $this->_MoveTo($px, $py);
  153. }
  154. }
  155. if ($func == 0x0325) {
  156. $op = 's';
  157. } else if ($func == 0x0324) {
  158. if ($nullPen) {
  159. if ($nullBrush) {
  160. $op = 'n';
  161. } // no op
  162. else {
  163. $op = 'f';
  164. } // fill
  165. } else {
  166. if ($nullBrush) {
  167. $op = 's';
  168. } // stroke
  169. else {
  170. $op = 'b';
  171. } // stroke and fill
  172. }
  173. if ($polyFillMode == 1 && ($op == 'b' || $op == 'f')) {
  174. $op .= '*';
  175. } // use even-odd fill rule
  176. }
  177. $wmfdata .= $op . "\n";
  178. break;
  179. case 0x0538: // PolyPolygon
  180. $coords = unpack('s' . ($size - 3), $parms);
  181. $numpolygons = $coords[1];
  182. $adjustment = $numpolygons;
  183. for ($j = 1; $j <= $numpolygons; $j++) {
  184. $numpoints = $coords[$j + 1];
  185. for ($i = $numpoints; $i > 0; $i--) {
  186. $px = $coords[2 * $i + $adjustment];
  187. $py = $coords[2 * $i + 1 + $adjustment];
  188. if ($i == $numpoints) {
  189. $wmfdata .= $this->_MoveTo($px, $py);
  190. } else {
  191. $wmfdata .= $this->_LineTo($px, $py);
  192. }
  193. }
  194. $adjustment += $numpoints * 2;
  195. }
  196. if ($nullPen) {
  197. if ($nullBrush) {
  198. $op = 'n';
  199. } // no op
  200. else {
  201. $op = 'f';
  202. } // fill
  203. } else {
  204. if ($nullBrush) {
  205. $op = 's';
  206. } // stroke
  207. else {
  208. $op = 'b';
  209. } // stroke and fill
  210. }
  211. if ($polyFillMode == 1 && ($op == 'b' || $op == 'f')) {
  212. $op .= '*';
  213. } // use even-odd fill rule
  214. $wmfdata .= $op . "\n";
  215. break;
  216. case 0x0000:
  217. $endRecord = true;
  218. break;
  219. }
  220. }
  221. return array(1, $wmfdata, $wo, $we);
  222. }
  223. function _MoveTo($x, $y)
  224. {
  225. return "$x $y m\n";
  226. }
  227. // a line must have been started using _MoveTo() first
  228. function _LineTo($x, $y)
  229. {
  230. return "$x $y l\n";
  231. }
  232. function _AddGDIObject($obj)
  233. {
  234. // find next available slot
  235. $idx = 0;
  236. if (!empty($this->gdiObjectArray)) {
  237. $empty = false;
  238. $i = 0;
  239. while (!$empty) {
  240. $empty = !isset($this->gdiObjectArray[$i]);
  241. $i++;
  242. }
  243. $idx = $i - 1;
  244. }
  245. $this->gdiObjectArray[$idx] = $obj;
  246. }
  247. function _GetGDIObject($idx)
  248. {
  249. return $this->gdiObjectArray[$idx];
  250. }
  251. function _DeleteGDIObject($idx)
  252. {
  253. unset($this->gdiObjectArray[$idx]);
  254. }
  255. }