/protected/components/ezcomponents/Document/src/converters/element_visitor/docbook/odt/element_handlers/media_object.php

https://github.com/kamarulismail/kamarul-playground · PHP · 262 lines · 154 code · 28 blank · 80 comment · 16 complexity · e8ab5323b53653d8fceed6eaa46923f7 MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the ezcDocumentDocbookToOdtMediaObjectHandler class.
  4. *
  5. * @package Document
  6. * @version 1.3.1
  7. * @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
  8. * @license http://ez.no/licenses/new_bsd New BSD License
  9. * @access private
  10. */
  11. /**
  12. * Visit media objects.
  13. *
  14. * Visit docbook <mediaobject/> and transform them into ODT image frames.
  15. *
  16. * @package Document
  17. * @version 1.3.1
  18. * @access private
  19. * @todo For later versions: Supporting non flat ODT, we can bundle images and
  20. * simply refer to them.
  21. */
  22. class ezcDocumentDocbookToOdtMediaObjectHandler extends ezcDocumentDocbookToOdtBaseHandler
  23. {
  24. /**
  25. * Counter to generate drawing names.
  26. *
  27. * @var integer
  28. */
  29. protected $counter = 0;
  30. /**
  31. * Handle a node
  32. *
  33. * Handle / transform a given node, and return the result of the
  34. * conversion.
  35. *
  36. * @param ezcDocumentElementVisitorConverter $converter
  37. * @param DOMElement $node
  38. * @param mixed $root
  39. * @return mixed
  40. */
  41. public function handle( ezcDocumentElementVisitorConverter $converter, DOMElement $node, $root )
  42. {
  43. $drawingId = ++$this->counter;
  44. if ( ( $imageData = $this->extractImageData( $node ) ) === false )
  45. {
  46. $converter->triggerError(
  47. E_PARSE,
  48. 'Missing information in <meadiaobject /> or <inlinemediaobject />.'
  49. );
  50. return $root;
  51. }
  52. $frame = $root->appendChild(
  53. $root->ownerDocument->createElementNS(
  54. ezcDocumentOdt::NS_ODT_DRAWING,
  55. 'draw:frame'
  56. )
  57. );
  58. $frame->setAttributeNS(
  59. ezcDocumentOdt::NS_ODT_DRAWING,
  60. 'draw:name',
  61. 'graphics' . $drawingId
  62. );
  63. $this->styler->applyStyles( $node, $frame );
  64. $anchorType = $this->detectAnchorTye( $node );
  65. $frame->setAttributeNS(
  66. ezcDocumentOdt::NS_ODT_TEXT,
  67. 'text:anchor-type',
  68. $anchorType
  69. );
  70. if ( $imageData->hasAttribute( 'width' ) )
  71. {
  72. $frame->setAttributeNS(
  73. ezcDocumentOdt::NS_ODT_SVG,
  74. 'svg:width',
  75. $this->correctLengthMeasure( $converter, $imageData->getAttribute( 'width' ) )
  76. );
  77. }
  78. if ( $imageData->hasAttribute( 'depth' ) )
  79. {
  80. $frame->setAttributeNS(
  81. ezcDocumentOdt::NS_ODT_SVG,
  82. 'svg:height',
  83. $this->correctLengthMeasure( $converter, $imageData->getAttribute( 'depth' ) )
  84. );
  85. }
  86. $image = $frame->appendChild(
  87. $root->ownerDocument->createElementNS(
  88. ezcDocumentOdt::NS_ODT_DRAWING,
  89. 'draw:image'
  90. )
  91. );
  92. $imgPath = $converter->getImageLocator()->locateImage(
  93. ( $imgFile = $imageData->getAttribute( 'fileref' ) )
  94. );
  95. if ( $imgPath === false )
  96. {
  97. $converter->triggerError(
  98. E_WARNING, "Could not find image '$imgFile'."
  99. );
  100. return $root;
  101. }
  102. if ( !is_readable( $imgPath ) )
  103. {
  104. $converter->triggerError(
  105. E_WARNING, "Image not readable '$imgFile'."
  106. );
  107. return $root;
  108. }
  109. $binaryData = $image->appendChild(
  110. $root->ownerDocument->createElementNS(
  111. ezcDocumentOdt::NS_ODT_OFFICE,
  112. 'office:binary-data',
  113. base64_encode(
  114. file_get_contents(
  115. $imgPath
  116. )
  117. )
  118. )
  119. );
  120. return $root;
  121. }
  122. /**
  123. * Correct length measure value.
  124. *
  125. * ODT does not define a default for length measures. This method checks if
  126. * a valid measure is already given in $length and appends the
  127. * $lengthMeasure given in the converter options otherwise.
  128. *
  129. * @param ezcDocumentElementVisitorConverter $converter
  130. * @param string $length
  131. * @return string
  132. */
  133. protected function correctLengthMeasure( ezcDocumentElementVisitorConverter $converter, $length )
  134. {
  135. if ( in_array( substr( $length, -2, 2 ), ezcDocumentDocbookToOdtConverterOptions::$validLengthMeasures ) )
  136. {
  137. return $length;
  138. }
  139. // @todo: Validate that number without measure is given
  140. return $length . $converter->options->lengthMeasure;
  141. }
  142. /**
  143. * Extracts the imagedata part of a media object.
  144. *
  145. * @param DOMNode $node
  146. * @return DOMNode
  147. */
  148. protected function extractImageData( DOMNode $node )
  149. {
  150. $imageDataElems = $node->getElementsByTagName( 'imagedata' );
  151. if ( $imageDataElems->length !== 1 )
  152. {
  153. return false;
  154. }
  155. $imageData = $imageDataElems->item( 0 );
  156. if ( !$imageData->hasAttribute( 'fileref' ) )
  157. {
  158. return false;
  159. }
  160. return $imageData;
  161. }
  162. /**
  163. * Detects and returns the anchortype of the given $node.
  164. *
  165. * Detects the correct ODT anchortype for the given DocBoom mediaobject
  166. * which can be:
  167. *
  168. * - 'page' if the image frame is bound to a specific page
  169. * - 'paragraph' if the frame is bound to a specific paragraph
  170. * - 'char' if the frame is bound to a specific character in a paragraph
  171. *
  172. * @param DOMElement $node
  173. * @return string
  174. */
  175. protected function detectAnchorTye( DOMElement $node )
  176. {
  177. $anchorType = 'page';
  178. if ( !$this->isInsidePara( $node ) )
  179. {
  180. return $anchorType;
  181. }
  182. $anchorType = 'paragraph';
  183. if ( !$this->isInsideText( $node ) )
  184. {
  185. return $anchorType;
  186. }
  187. $anchorType = 'char';
  188. return $anchorType;
  189. }
  190. /**
  191. * Checks if $node is descendant of a <para/>.
  192. *
  193. * @param DOMNode $node
  194. * @return bool
  195. */
  196. protected function isInsidePara( DOMNode $node )
  197. {
  198. $parent = $node->parentNode;
  199. if ( $parent === null )
  200. {
  201. return false;
  202. }
  203. if ( $parent->localName === 'para' )
  204. {
  205. return true;
  206. }
  207. return $this->isInsidePara( $parent );
  208. }
  209. /**
  210. * Checks if $node occurs in between plain text.
  211. *
  212. * @param DOMNode $node
  213. * @return bool
  214. */
  215. protected function isInsideText( DOMNode $node )
  216. {
  217. $prevSib = $node->previousSibling;
  218. if ( $prevSib === null )
  219. {
  220. return false;
  221. }
  222. if ( $prevSib->nodeType === XML_TEXT_NODE && trim( $prevSib->nodeValue ) !== '' )
  223. {
  224. return true;
  225. }
  226. if ( $prevSib->nodeType === XML_ELEMENT_NODE )
  227. {
  228. // Spans or other inline elements
  229. return true;
  230. }
  231. return $this->isInsideText( $prevSib );
  232. }
  233. }
  234. ?>