Escher.php 18 KB

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