Escher.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <?php
  2. /**
  3. * PHPExcel
  4. *
  5. * Copyright (c) 2006 - 2015 PHPExcel
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * @category PHPExcel
  22. * @package PHPExcel_Writer_Excel5
  23. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  24. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  25. * @version ##VERSION##, ##DATE##
  26. */
  27. /**
  28. * PHPExcel_Shared_Escher_DggContainer_BstoreContainer
  29. *
  30. * @category PHPExcel
  31. * @package PHPExcel_Writer_Excel5
  32. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  33. */
  34. class PHPExcel_Writer_Excel5_Escher
  35. {
  36. /**
  37. * The object we are writing
  38. */
  39. private $object;
  40. /**
  41. * The written binary data
  42. */
  43. private $data;
  44. /**
  45. * Shape offsets. Positions in binary stream where a new shape record begins
  46. *
  47. * @var array
  48. */
  49. private $spOffsets;
  50. /**
  51. * Shape types.
  52. *
  53. * @var array
  54. */
  55. private $spTypes;
  56. /**
  57. * Constructor
  58. *
  59. * @param mixed
  60. */
  61. public function __construct($object)
  62. {
  63. $this->object = $object;
  64. }
  65. /**
  66. * Process the object to be written
  67. */
  68. public function close()
  69. {
  70. // initialize
  71. $this->data = '';
  72. switch (get_class($this->object)) {
  73. case 'PHPExcel_Shared_Escher':
  74. if ($dggContainer = $this->object->getDggContainer()) {
  75. $writer = new PHPExcel_Writer_Excel5_Escher($dggContainer);
  76. $this->data = $writer->close();
  77. } elseif ($dgContainer = $this->object->getDgContainer()) {
  78. $writer = new PHPExcel_Writer_Excel5_Escher($dgContainer);
  79. $this->data = $writer->close();
  80. $this->spOffsets = $writer->getSpOffsets();
  81. $this->spTypes = $writer->getSpTypes();
  82. }
  83. break;
  84. case 'PHPExcel_Shared_Escher_DggContainer':
  85. // this is a container record
  86. // initialize
  87. $innerData = '';
  88. // write the dgg
  89. $recVer = 0x0;
  90. $recInstance = 0x0000;
  91. $recType = 0xF006;
  92. $recVerInstance = $recVer;
  93. $recVerInstance |= $recInstance << 4;
  94. // dgg data
  95. $dggData =
  96. pack(
  97. 'VVVV',
  98. $this->object->getSpIdMax(), // maximum shape identifier increased by one
  99. $this->object->getCDgSaved() + 1, // number of file identifier clusters increased by one
  100. $this->object->getCSpSaved(),
  101. $this->object->getCDgSaved() // count total number of drawings saved
  102. );
  103. // add file identifier clusters (one per drawing)
  104. $IDCLs = $this->object->getIDCLs();
  105. foreach ($IDCLs as $dgId => $maxReducedSpId) {
  106. $dggData .= pack('VV', $dgId, $maxReducedSpId + 1);
  107. }
  108. $header = pack('vvV', $recVerInstance, $recType, strlen($dggData));
  109. $innerData .= $header . $dggData;
  110. // write the bstoreContainer
  111. if ($bstoreContainer = $this->object->getBstoreContainer()) {
  112. $writer = new PHPExcel_Writer_Excel5_Escher($bstoreContainer);
  113. $innerData .= $writer->close();
  114. }
  115. // write the record
  116. $recVer = 0xF;
  117. $recInstance = 0x0000;
  118. $recType = 0xF000;
  119. $length = strlen($innerData);
  120. $recVerInstance = $recVer;
  121. $recVerInstance |= $recInstance << 4;
  122. $header = pack('vvV', $recVerInstance, $recType, $length);
  123. $this->data = $header . $innerData;
  124. break;
  125. case 'PHPExcel_Shared_Escher_DggContainer_BstoreContainer':
  126. // this is a container record
  127. // initialize
  128. $innerData = '';
  129. // treat the inner data
  130. if ($BSECollection = $this->object->getBSECollection()) {
  131. foreach ($BSECollection as $BSE) {
  132. $writer = new PHPExcel_Writer_Excel5_Escher($BSE);
  133. $innerData .= $writer->close();
  134. }
  135. }
  136. // write the record
  137. $recVer = 0xF;
  138. $recInstance = count($this->object->getBSECollection());
  139. $recType = 0xF001;
  140. $length = strlen($innerData);
  141. $recVerInstance = $recVer;
  142. $recVerInstance |= $recInstance << 4;
  143. $header = pack('vvV', $recVerInstance, $recType, $length);
  144. $this->data = $header . $innerData;
  145. break;
  146. case 'PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE':
  147. // this is a semi-container record
  148. // initialize
  149. $innerData = '';
  150. // here we treat the inner data
  151. if ($blip = $this->object->getBlip()) {
  152. $writer = new PHPExcel_Writer_Excel5_Escher($blip);
  153. $innerData .= $writer->close();
  154. }
  155. // initialize
  156. $data = '';
  157. $btWin32 = $this->object->getBlipType();
  158. $btMacOS = $this->object->getBlipType();
  159. $data .= pack('CC', $btWin32, $btMacOS);
  160. $rgbUid = pack('VVVV', 0, 0, 0, 0); // todo
  161. $data .= $rgbUid;
  162. $tag = 0;
  163. $size = strlen($innerData);
  164. $cRef = 1;
  165. $foDelay = 0; //todo
  166. $unused1 = 0x0;
  167. $cbName = 0x0;
  168. $unused2 = 0x0;
  169. $unused3 = 0x0;
  170. $data .= pack('vVVVCCCC', $tag, $size, $cRef, $foDelay, $unused1, $cbName, $unused2, $unused3);
  171. $data .= $innerData;
  172. // write the record
  173. $recVer = 0x2;
  174. $recInstance = $this->object->getBlipType();
  175. $recType = 0xF007;
  176. $length = strlen($data);
  177. $recVerInstance = $recVer;
  178. $recVerInstance |= $recInstance << 4;
  179. $header = pack('vvV', $recVerInstance, $recType, $length);
  180. $this->data = $header;
  181. $this->data .= $data;
  182. break;
  183. case 'PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE_Blip':
  184. // this is an atom record
  185. // write the record
  186. switch ($this->object->getParent()->getBlipType()) {
  187. case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_JPEG:
  188. // initialize
  189. $innerData = '';
  190. $rgbUid1 = pack('VVVV', 0, 0, 0, 0); // todo
  191. $innerData .= $rgbUid1;
  192. $tag = 0xFF; // todo
  193. $innerData .= pack('C', $tag);
  194. $innerData .= $this->object->getData();
  195. $recVer = 0x0;
  196. $recInstance = 0x46A;
  197. $recType = 0xF01D;
  198. $length = strlen($innerData);
  199. $recVerInstance = $recVer;
  200. $recVerInstance |= $recInstance << 4;
  201. $header = pack('vvV', $recVerInstance, $recType, $length);
  202. $this->data = $header;
  203. $this->data .= $innerData;
  204. break;
  205. case PHPExcel_Shared_Escher_DggContainer_BstoreContainer_BSE::BLIPTYPE_PNG:
  206. // initialize
  207. $innerData = '';
  208. $rgbUid1 = pack('VVVV', 0, 0, 0, 0); // todo
  209. $innerData .= $rgbUid1;
  210. $tag = 0xFF; // todo
  211. $innerData .= pack('C', $tag);
  212. $innerData .= $this->object->getData();
  213. $recVer = 0x0;
  214. $recInstance = 0x6E0;
  215. $recType = 0xF01E;
  216. $length = strlen($innerData);
  217. $recVerInstance = $recVer;
  218. $recVerInstance |= $recInstance << 4;
  219. $header = pack('vvV', $recVerInstance, $recType, $length);
  220. $this->data = $header;
  221. $this->data .= $innerData;
  222. break;
  223. }
  224. break;
  225. case 'PHPExcel_Shared_Escher_DgContainer':
  226. // this is a container record
  227. // initialize
  228. $innerData = '';
  229. // write the dg
  230. $recVer = 0x0;
  231. $recInstance = $this->object->getDgId();
  232. $recType = 0xF008;
  233. $length = 8;
  234. $recVerInstance = $recVer;
  235. $recVerInstance |= $recInstance << 4;
  236. $header = pack('vvV', $recVerInstance, $recType, $length);
  237. // number of shapes in this drawing (including group shape)
  238. $countShapes = count($this->object->getSpgrContainer()->getChildren());
  239. $innerData .= $header . pack('VV', $countShapes, $this->object->getLastSpId());
  240. //$innerData .= $header . pack('VV', 0, 0);
  241. // write the spgrContainer
  242. if ($spgrContainer = $this->object->getSpgrContainer()) {
  243. $writer = new PHPExcel_Writer_Excel5_Escher($spgrContainer);
  244. $innerData .= $writer->close();
  245. // get the shape offsets relative to the spgrContainer record
  246. $spOffsets = $writer->getSpOffsets();
  247. $spTypes = $writer->getSpTypes();
  248. // save the shape offsets relative to dgContainer
  249. foreach ($spOffsets as & $spOffset) {
  250. $spOffset += 24; // add length of dgContainer header data (8 bytes) plus dg data (16 bytes)
  251. }
  252. $this->spOffsets = $spOffsets;
  253. $this->spTypes = $spTypes;
  254. }
  255. // write the record
  256. $recVer = 0xF;
  257. $recInstance = 0x0000;
  258. $recType = 0xF002;
  259. $length = strlen($innerData);
  260. $recVerInstance = $recVer;
  261. $recVerInstance |= $recInstance << 4;
  262. $header = pack('vvV', $recVerInstance, $recType, $length);
  263. $this->data = $header . $innerData;
  264. break;
  265. case 'PHPExcel_Shared_Escher_DgContainer_SpgrContainer':
  266. // this is a container record
  267. // initialize
  268. $innerData = '';
  269. // initialize spape offsets
  270. $totalSize = 8;
  271. $spOffsets = array();
  272. $spTypes = array();
  273. // treat the inner data
  274. foreach ($this->object->getChildren() as $spContainer) {
  275. $writer = new PHPExcel_Writer_Excel5_Escher($spContainer);
  276. $spData = $writer->close();
  277. $innerData .= $spData;
  278. // save the shape offsets (where new shape records begin)
  279. $totalSize += strlen($spData);
  280. $spOffsets[] = $totalSize;
  281. $spTypes = array_merge($spTypes, $writer->getSpTypes());
  282. }
  283. // write the record
  284. $recVer = 0xF;
  285. $recInstance = 0x0000;
  286. $recType = 0xF003;
  287. $length = strlen($innerData);
  288. $recVerInstance = $recVer;
  289. $recVerInstance |= $recInstance << 4;
  290. $header = pack('vvV', $recVerInstance, $recType, $length);
  291. $this->data = $header . $innerData;
  292. $this->spOffsets = $spOffsets;
  293. $this->spTypes = $spTypes;
  294. break;
  295. case 'PHPExcel_Shared_Escher_DgContainer_SpgrContainer_SpContainer':
  296. // initialize
  297. $data = '';
  298. // build the data
  299. // write group shape record, if necessary?
  300. if ($this->object->getSpgr()) {
  301. $recVer = 0x1;
  302. $recInstance = 0x0000;
  303. $recType = 0xF009;
  304. $length = 0x00000010;
  305. $recVerInstance = $recVer;
  306. $recVerInstance |= $recInstance << 4;
  307. $header = pack('vvV', $recVerInstance, $recType, $length);
  308. $data .= $header . pack('VVVV', 0, 0, 0, 0);
  309. }
  310. $this->spTypes[] = ($this->object->getSpType());
  311. // write the shape record
  312. $recVer = 0x2;
  313. $recInstance = $this->object->getSpType(); // shape type
  314. $recType = 0xF00A;
  315. $length = 0x00000008;
  316. $recVerInstance = $recVer;
  317. $recVerInstance |= $recInstance << 4;
  318. $header = pack('vvV', $recVerInstance, $recType, $length);
  319. $data .= $header . pack('VV', $this->object->getSpId(), $this->object->getSpgr() ? 0x0005 : 0x0A00);
  320. // the options
  321. if ($this->object->getOPTCollection()) {
  322. $optData = '';
  323. $recVer = 0x3;
  324. $recInstance = count($this->object->getOPTCollection());
  325. $recType = 0xF00B;
  326. foreach ($this->object->getOPTCollection() as $property => $value) {
  327. $optData .= pack('vV', $property, $value);
  328. }
  329. $length = strlen($optData);
  330. $recVerInstance = $recVer;
  331. $recVerInstance |= $recInstance << 4;
  332. $header = pack('vvV', $recVerInstance, $recType, $length);
  333. $data .= $header . $optData;
  334. }
  335. // the client anchor
  336. if ($this->object->getStartCoordinates()) {
  337. $clientAnchorData = '';
  338. $recVer = 0x0;
  339. $recInstance = 0x0;
  340. $recType = 0xF010;
  341. // start coordinates
  342. list($column, $row) = PHPExcel_Cell::coordinateFromString($this->object->getStartCoordinates());
  343. $c1 = PHPExcel_Cell::columnIndexFromString($column) - 1;
  344. $r1 = $row - 1;
  345. // start offsetX
  346. $startOffsetX = $this->object->getStartOffsetX();
  347. // start offsetY
  348. $startOffsetY = $this->object->getStartOffsetY();
  349. // end coordinates
  350. list($column, $row) = PHPExcel_Cell::coordinateFromString($this->object->getEndCoordinates());
  351. $c2 = PHPExcel_Cell::columnIndexFromString($column) - 1;
  352. $r2 = $row - 1;
  353. // end offsetX
  354. $endOffsetX = $this->object->getEndOffsetX();
  355. // end offsetY
  356. $endOffsetY = $this->object->getEndOffsetY();
  357. $clientAnchorData = pack('vvvvvvvvv', $this->object->getSpFlag(), $c1, $startOffsetX, $r1, $startOffsetY, $c2, $endOffsetX, $r2, $endOffsetY);
  358. $length = strlen($clientAnchorData);
  359. $recVerInstance = $recVer;
  360. $recVerInstance |= $recInstance << 4;
  361. $header = pack('vvV', $recVerInstance, $recType, $length);
  362. $data .= $header . $clientAnchorData;
  363. }
  364. // the client data, just empty for now
  365. if (!$this->object->getSpgr()) {
  366. $clientDataData = '';
  367. $recVer = 0x0;
  368. $recInstance = 0x0;
  369. $recType = 0xF011;
  370. $length = strlen($clientDataData);
  371. $recVerInstance = $recVer;
  372. $recVerInstance |= $recInstance << 4;
  373. $header = pack('vvV', $recVerInstance, $recType, $length);
  374. $data .= $header . $clientDataData;
  375. }
  376. // write the record
  377. $recVer = 0xF;
  378. $recInstance = 0x0000;
  379. $recType = 0xF004;
  380. $length = strlen($data);
  381. $recVerInstance = $recVer;
  382. $recVerInstance |= $recInstance << 4;
  383. $header = pack('vvV', $recVerInstance, $recType, $length);
  384. $this->data = $header . $data;
  385. break;
  386. }
  387. return $this->data;
  388. }
  389. /**
  390. * Gets the shape offsets
  391. *
  392. * @return array
  393. */
  394. public function getSpOffsets()
  395. {
  396. return $this->spOffsets;
  397. }
  398. /**
  399. * Gets the shape types
  400. *
  401. * @return array
  402. */
  403. public function getSpTypes()
  404. {
  405. return $this->spTypes;
  406. }
  407. }