wmf.php 6.6 KB

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