blob: 0e5695aace9fa1763cfedcf9c0ed7c77a083753a [file] [log] [blame]
<?php
/**
* File containing the ezcDocumentDocbookToOdtMediaObjectHandler class.
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package Document
* @version //autogen//
* @copyright Copyright (C) 2005-2010 eZ Systems AS. All rights reserved.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @access private
*/
/**
* Visit media objects.
*
* Visit docbook <mediaobject/> and transform them into ODT image frames.
*
* @package Document
* @version //autogen//
* @access private
* @todo For later versions: Supporting non flat ODT, we can bundle images and
* simply refer to them.
*/
class ezcDocumentDocbookToOdtMediaObjectHandler extends ezcDocumentDocbookToOdtBaseHandler
{
/**
* Counter to generate drawing names.
*
* @var integer
*/
protected $counter = 0;
/**
* Handle a node
*
* Handle / transform a given node, and return the result of the
* conversion.
*
* @param ezcDocumentElementVisitorConverter $converter
* @param DOMElement $node
* @param mixed $root
* @return mixed
*/
public function handle( ezcDocumentElementVisitorConverter $converter, DOMElement $node, $root )
{
$drawingId = ++$this->counter;
if ( ( $imageData = $this->extractImageData( $node ) ) === false )
{
$converter->triggerError(
E_PARSE,
'Missing information in <meadiaobject /> or <inlinemediaobject />.'
);
return $root;
}
$frame = $root->appendChild(
$root->ownerDocument->createElementNS(
ezcDocumentOdt::NS_ODT_DRAWING,
'draw:frame'
)
);
$frame->setAttributeNS(
ezcDocumentOdt::NS_ODT_DRAWING,
'draw:name',
'graphics' . $drawingId
);
$this->styler->applyStyles( $node, $frame );
$anchorType = $this->detectAnchorTye( $node );
$frame->setAttributeNS(
ezcDocumentOdt::NS_ODT_TEXT,
'text:anchor-type',
$anchorType
);
if ( $imageData->hasAttribute( 'width' ) )
{
$frame->setAttributeNS(
ezcDocumentOdt::NS_ODT_SVG,
'svg:width',
$this->correctLengthMeasure( $converter, $imageData->getAttribute( 'width' ) )
);
}
if ( $imageData->hasAttribute( 'depth' ) )
{
$frame->setAttributeNS(
ezcDocumentOdt::NS_ODT_SVG,
'svg:height',
$this->correctLengthMeasure( $converter, $imageData->getAttribute( 'depth' ) )
);
}
$image = $frame->appendChild(
$root->ownerDocument->createElementNS(
ezcDocumentOdt::NS_ODT_DRAWING,
'draw:image'
)
);
$imgPath = $converter->getImageLocator()->locateImage(
( $imgFile = $imageData->getAttribute( 'fileref' ) )
);
if ( $imgPath === false )
{
$converter->triggerError(
E_WARNING, "Could not find image '$imgFile'."
);
return $root;
}
if ( !is_readable( $imgPath ) )
{
$converter->triggerError(
E_WARNING, "Image not readable '$imgFile'."
);
return $root;
}
$binaryData = $image->appendChild(
$root->ownerDocument->createElementNS(
ezcDocumentOdt::NS_ODT_OFFICE,
'office:binary-data',
base64_encode(
file_get_contents(
$imgPath
)
)
)
);
return $root;
}
/**
* Correct length measure value.
*
* ODT does not define a default for length measures. This method checks if
* a valid measure is already given in $length and appends the
* $lengthMeasure given in the converter options otherwise.
*
* @param ezcDocumentElementVisitorConverter $converter
* @param string $length
* @return string
*/
protected function correctLengthMeasure( ezcDocumentElementVisitorConverter $converter, $length )
{
if ( in_array( substr( $length, -2, 2 ), ezcDocumentDocbookToOdtConverterOptions::$validLengthMeasures ) )
{
return $length;
}
// @todo: Validate that number without measure is given
return $length . $converter->options->lengthMeasure;
}
/**
* Extracts the imagedata part of a media object.
*
* @param DOMNode $node
* @return DOMNode
*/
protected function extractImageData( DOMNode $node )
{
$imageDataElems = $node->getElementsByTagName( 'imagedata' );
if ( $imageDataElems->length !== 1 )
{
return false;
}
$imageData = $imageDataElems->item( 0 );
if ( !$imageData->hasAttribute( 'fileref' ) )
{
return false;
}
return $imageData;
}
/**
* Detects and returns the anchortype of the given $node.
*
* Detects the correct ODT anchortype for the given DocBoom mediaobject
* which can be:
*
* - 'page' if the image frame is bound to a specific page
* - 'paragraph' if the frame is bound to a specific paragraph
* - 'char' if the frame is bound to a specific character in a paragraph
*
* @param DOMElement $node
* @return string
*/
protected function detectAnchorTye( DOMElement $node )
{
$anchorType = 'page';
if ( !$this->isInsidePara( $node ) )
{
return $anchorType;
}
$anchorType = 'paragraph';
if ( !$this->isInsideText( $node ) )
{
return $anchorType;
}
$anchorType = 'char';
return $anchorType;
}
/**
* Checks if $node is descendant of a <para/>.
*
* @param DOMNode $node
* @return bool
*/
protected function isInsidePara( DOMNode $node )
{
$parent = $node->parentNode;
if ( $parent === null )
{
return false;
}
if ( $parent->localName === 'para' )
{
return true;
}
return $this->isInsidePara( $parent );
}
/**
* Checks if $node occurs in between plain text.
*
* @param DOMNode $node
* @return bool
*/
protected function isInsideText( DOMNode $node )
{
$prevSib = $node->previousSibling;
if ( $prevSib === null )
{
return false;
}
if ( $prevSib->nodeType === XML_TEXT_NODE && trim( $prevSib->nodeValue ) !== '' )
{
return true;
}
if ( $prevSib->nodeType === XML_ELEMENT_NODE )
{
// Spans or other inline elements
return true;
}
return $this->isInsideText( $prevSib );
}
}
?>