mirror of
https://github.com/Karaka-Management/Resources.git
synced 2026-01-11 05:18:40 +00:00
add mpdf and dependencies
This commit is contained in:
parent
37e01938fa
commit
d541fd1bc7
298
DeepCopy/DeepCopy.php
Normal file
298
DeepCopy/DeepCopy.php
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy;
|
||||
|
||||
use ArrayObject;
|
||||
use DateInterval;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use DeepCopy\Exception\CloneException;
|
||||
use DeepCopy\Filter\Filter;
|
||||
use DeepCopy\Matcher\Matcher;
|
||||
use DeepCopy\Reflection\ReflectionHelper;
|
||||
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
|
||||
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
|
||||
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
|
||||
use DeepCopy\TypeFilter\TypeFilter;
|
||||
use DeepCopy\TypeMatcher\TypeMatcher;
|
||||
use ReflectionObject;
|
||||
use ReflectionProperty;
|
||||
use SplDoublyLinkedList;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class DeepCopy
|
||||
{
|
||||
/**
|
||||
* @var object[] List of objects copied.
|
||||
*/
|
||||
private $hashMap = [];
|
||||
|
||||
/**
|
||||
* Filters to apply.
|
||||
*
|
||||
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
||||
*/
|
||||
private $filters = [];
|
||||
|
||||
/**
|
||||
* Type Filters to apply.
|
||||
*
|
||||
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
||||
*/
|
||||
private $typeFilters = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $skipUncloneable = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $useCloneMethod;
|
||||
|
||||
/**
|
||||
* @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will be used
|
||||
* instead of the regular deep cloning.
|
||||
*/
|
||||
public function __construct($useCloneMethod = false)
|
||||
{
|
||||
$this->useCloneMethod = $useCloneMethod;
|
||||
|
||||
$this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
|
||||
$this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
|
||||
$this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* If enabled, will not throw an exception when coming across an uncloneable property.
|
||||
*
|
||||
* @param $skipUncloneable
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function skipUncloneable($skipUncloneable = true)
|
||||
{
|
||||
$this->skipUncloneable = $skipUncloneable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep copies the given object.
|
||||
*
|
||||
* @param mixed $object
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function copy($object)
|
||||
{
|
||||
$this->hashMap = [];
|
||||
|
||||
return $this->recursiveCopy($object);
|
||||
}
|
||||
|
||||
public function addFilter(Filter $filter, Matcher $matcher)
|
||||
{
|
||||
$this->filters[] = [
|
||||
'matcher' => $matcher,
|
||||
'filter' => $filter,
|
||||
];
|
||||
}
|
||||
|
||||
public function prependFilter(Filter $filter, Matcher $matcher)
|
||||
{
|
||||
array_unshift($this->filters, [
|
||||
'matcher' => $matcher,
|
||||
'filter' => $filter,
|
||||
]);
|
||||
}
|
||||
|
||||
public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
|
||||
{
|
||||
$this->typeFilters[] = [
|
||||
'matcher' => $matcher,
|
||||
'filter' => $filter,
|
||||
];
|
||||
}
|
||||
|
||||
private function recursiveCopy($var)
|
||||
{
|
||||
// Matches Type Filter
|
||||
if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) {
|
||||
return $filter->apply($var);
|
||||
}
|
||||
|
||||
// Resource
|
||||
if (is_resource($var)) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
// Array
|
||||
if (is_array($var)) {
|
||||
return $this->copyArray($var);
|
||||
}
|
||||
|
||||
// Scalar
|
||||
if (! is_object($var)) {
|
||||
return $var;
|
||||
}
|
||||
|
||||
// Object
|
||||
return $this->copyObject($var);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an array
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
private function copyArray(array $array)
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
$array[$key] = $this->recursiveCopy($value);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies an object.
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @throws CloneException
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
private function copyObject($object)
|
||||
{
|
||||
$objectHash = spl_object_hash($object);
|
||||
|
||||
if (isset($this->hashMap[$objectHash])) {
|
||||
return $this->hashMap[$objectHash];
|
||||
}
|
||||
|
||||
$reflectedObject = new ReflectionObject($object);
|
||||
$isCloneable = $reflectedObject->isCloneable();
|
||||
|
||||
if (false === $isCloneable) {
|
||||
if ($this->skipUncloneable) {
|
||||
$this->hashMap[$objectHash] = $object;
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
throw new CloneException(
|
||||
sprintf(
|
||||
'The class "%s" is not cloneable.',
|
||||
$reflectedObject->getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$newObject = clone $object;
|
||||
$this->hashMap[$objectHash] = $newObject;
|
||||
|
||||
if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) {
|
||||
return $newObject;
|
||||
}
|
||||
|
||||
if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) {
|
||||
return $newObject;
|
||||
}
|
||||
|
||||
foreach (ReflectionHelper::getProperties($reflectedObject) as $property) {
|
||||
$this->copyObjectProperty($newObject, $property);
|
||||
}
|
||||
|
||||
return $newObject;
|
||||
}
|
||||
|
||||
private function copyObjectProperty($object, ReflectionProperty $property)
|
||||
{
|
||||
// Ignore static properties
|
||||
if ($property->isStatic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply the filters
|
||||
foreach ($this->filters as $item) {
|
||||
/** @var Matcher $matcher */
|
||||
$matcher = $item['matcher'];
|
||||
/** @var Filter $filter */
|
||||
$filter = $item['filter'];
|
||||
|
||||
if ($matcher->matches($object, $property->getName())) {
|
||||
$filter->apply(
|
||||
$object,
|
||||
$property->getName(),
|
||||
function ($object) {
|
||||
return $this->recursiveCopy($object);
|
||||
}
|
||||
);
|
||||
|
||||
// If a filter matches, we stop processing this property
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$property->setAccessible(true);
|
||||
|
||||
// Ignore uninitialized properties (for PHP >7.4)
|
||||
if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$propertyValue = $property->getValue($object);
|
||||
|
||||
// Copy the property
|
||||
$property->setValue($object, $this->recursiveCopy($propertyValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first filter that matches variable, `null` if no such filter found.
|
||||
*
|
||||
* @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and
|
||||
* 'matcher' with value of type {@see TypeMatcher}
|
||||
* @param mixed $var
|
||||
*
|
||||
* @return TypeFilter|null
|
||||
*/
|
||||
private function getFirstMatchedTypeFilter(array $filterRecords, $var)
|
||||
{
|
||||
$matched = $this->first(
|
||||
$filterRecords,
|
||||
function (array $record) use ($var) {
|
||||
/* @var TypeMatcher $matcher */
|
||||
$matcher = $record['matcher'];
|
||||
|
||||
return $matcher->matches($var);
|
||||
}
|
||||
);
|
||||
|
||||
return isset($matched) ? $matched['filter'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first element that matches predicate, `null` if no such element found.
|
||||
*
|
||||
* @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
||||
* @param callable $predicate Predicate arguments are: element.
|
||||
*
|
||||
* @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher'
|
||||
* with value of type {@see TypeMatcher} or `null`.
|
||||
*/
|
||||
private function first(array $elements, callable $predicate)
|
||||
{
|
||||
foreach ($elements as $element) {
|
||||
if (call_user_func($predicate, $element)) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
9
DeepCopy/Exception/CloneException.php
Normal file
9
DeepCopy/Exception/CloneException.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Exception;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
class CloneException extends UnexpectedValueException
|
||||
{
|
||||
}
|
||||
9
DeepCopy/Exception/PropertyException.php
Normal file
9
DeepCopy/Exception/PropertyException.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Exception;
|
||||
|
||||
use ReflectionException;
|
||||
|
||||
class PropertyException extends ReflectionException
|
||||
{
|
||||
}
|
||||
33
DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
Normal file
33
DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter\Doctrine;
|
||||
|
||||
use DeepCopy\Filter\Filter;
|
||||
use DeepCopy\Reflection\ReflectionHelper;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class DoctrineCollectionFilter implements Filter
|
||||
{
|
||||
/**
|
||||
* Copies the object property doctrine collection.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier)
|
||||
{
|
||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$oldCollection = $reflectionProperty->getValue($object);
|
||||
|
||||
$newCollection = $oldCollection->map(
|
||||
function ($item) use ($objectCopier) {
|
||||
return $objectCopier($item);
|
||||
}
|
||||
);
|
||||
|
||||
$reflectionProperty->setValue($object, $newCollection);
|
||||
}
|
||||
}
|
||||
28
DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
Normal file
28
DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter\Doctrine;
|
||||
|
||||
use DeepCopy\Filter\Filter;
|
||||
use DeepCopy\Reflection\ReflectionHelper;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class DoctrineEmptyCollectionFilter implements Filter
|
||||
{
|
||||
/**
|
||||
* Sets the object property to an empty doctrine collection.
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $property
|
||||
* @param callable $objectCopier
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier)
|
||||
{
|
||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||
$reflectionProperty->setAccessible(true);
|
||||
|
||||
$reflectionProperty->setValue($object, new ArrayCollection());
|
||||
}
|
||||
}
|
||||
22
DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php
Normal file
22
DeepCopy/Filter/Doctrine/DoctrineProxyFilter.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter\Doctrine;
|
||||
|
||||
use DeepCopy\Filter\Filter;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class DoctrineProxyFilter implements Filter
|
||||
{
|
||||
/**
|
||||
* Triggers the magic method __load() on a Doctrine Proxy class to load the
|
||||
* actual entity from the database.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier)
|
||||
{
|
||||
$object->__load();
|
||||
}
|
||||
}
|
||||
18
DeepCopy/Filter/Filter.php
Normal file
18
DeepCopy/Filter/Filter.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter;
|
||||
|
||||
/**
|
||||
* Filter to apply to a property while copying an object
|
||||
*/
|
||||
interface Filter
|
||||
{
|
||||
/**
|
||||
* Applies the filter to the object.
|
||||
*
|
||||
* @param object $object
|
||||
* @param string $property
|
||||
* @param callable $objectCopier
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier);
|
||||
}
|
||||
16
DeepCopy/Filter/KeepFilter.php
Normal file
16
DeepCopy/Filter/KeepFilter.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter;
|
||||
|
||||
class KeepFilter implements Filter
|
||||
{
|
||||
/**
|
||||
* Keeps the value of the object property.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
39
DeepCopy/Filter/ReplaceFilter.php
Normal file
39
DeepCopy/Filter/ReplaceFilter.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter;
|
||||
|
||||
use DeepCopy\Reflection\ReflectionHelper;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class ReplaceFilter implements Filter
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* @param callable $callable Will be called to get the new value for each property to replace
|
||||
*/
|
||||
public function __construct(callable $callable)
|
||||
{
|
||||
$this->callback = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the object property by the result of the callback called with the object property.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier)
|
||||
{
|
||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||
$reflectionProperty->setAccessible(true);
|
||||
|
||||
$value = call_user_func($this->callback, $reflectionProperty->getValue($object));
|
||||
|
||||
$reflectionProperty->setValue($object, $value);
|
||||
}
|
||||
}
|
||||
24
DeepCopy/Filter/SetNullFilter.php
Normal file
24
DeepCopy/Filter/SetNullFilter.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Filter;
|
||||
|
||||
use DeepCopy\Reflection\ReflectionHelper;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class SetNullFilter implements Filter
|
||||
{
|
||||
/**
|
||||
* Sets the object property to null.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($object, $property, $objectCopier)
|
||||
{
|
||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||
|
||||
$reflectionProperty->setAccessible(true);
|
||||
$reflectionProperty->setValue($object, null);
|
||||
}
|
||||
}
|
||||
20
DeepCopy/LICENSE
Normal file
20
DeepCopy/LICENSE
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 My C-Sense
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
22
DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php
Normal file
22
DeepCopy/Matcher/Doctrine/DoctrineProxyMatcher.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Matcher\Doctrine;
|
||||
|
||||
use DeepCopy\Matcher\Matcher;
|
||||
use Doctrine\Common\Persistence\Proxy;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class DoctrineProxyMatcher implements Matcher
|
||||
{
|
||||
/**
|
||||
* Matches a Doctrine Proxy class.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function matches($object, $property)
|
||||
{
|
||||
return $object instanceof Proxy;
|
||||
}
|
||||
}
|
||||
14
DeepCopy/Matcher/Matcher.php
Normal file
14
DeepCopy/Matcher/Matcher.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Matcher;
|
||||
|
||||
interface Matcher
|
||||
{
|
||||
/**
|
||||
* @param object $object
|
||||
* @param string $property
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function matches($object, $property);
|
||||
}
|
||||
39
DeepCopy/Matcher/PropertyMatcher.php
Normal file
39
DeepCopy/Matcher/PropertyMatcher.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Matcher;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class PropertyMatcher implements Matcher
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $property;
|
||||
|
||||
/**
|
||||
* @param string $class Class name
|
||||
* @param string $property Property name
|
||||
*/
|
||||
public function __construct($class, $property)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->property = $property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a specific property of a specific class.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function matches($object, $property)
|
||||
{
|
||||
return ($object instanceof $this->class) && $property == $this->property;
|
||||
}
|
||||
}
|
||||
32
DeepCopy/Matcher/PropertyNameMatcher.php
Normal file
32
DeepCopy/Matcher/PropertyNameMatcher.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Matcher;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class PropertyNameMatcher implements Matcher
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $property;
|
||||
|
||||
/**
|
||||
* @param string $property Property name
|
||||
*/
|
||||
public function __construct($property)
|
||||
{
|
||||
$this->property = $property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a property by its name.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function matches($object, $property)
|
||||
{
|
||||
return $property == $this->property;
|
||||
}
|
||||
}
|
||||
46
DeepCopy/Matcher/PropertyTypeMatcher.php
Normal file
46
DeepCopy/Matcher/PropertyTypeMatcher.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Matcher;
|
||||
|
||||
use DeepCopy\Reflection\ReflectionHelper;
|
||||
use ReflectionException;
|
||||
|
||||
/**
|
||||
* Matches a property by its type.
|
||||
*
|
||||
* It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences
|
||||
* of given type in copied context (eg. array elements), not just on object properties.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class PropertyTypeMatcher implements Matcher
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $propertyType;
|
||||
|
||||
/**
|
||||
* @param string $propertyType Property type
|
||||
*/
|
||||
public function __construct($propertyType)
|
||||
{
|
||||
$this->propertyType = $propertyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function matches($object, $property)
|
||||
{
|
||||
try {
|
||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
||||
} catch (ReflectionException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$reflectionProperty->setAccessible(true);
|
||||
|
||||
return $reflectionProperty->getValue($object) instanceof $this->propertyType;
|
||||
}
|
||||
}
|
||||
78
DeepCopy/Reflection/ReflectionHelper.php
Normal file
78
DeepCopy/Reflection/ReflectionHelper.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\Reflection;
|
||||
|
||||
use DeepCopy\Exception\PropertyException;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionObject;
|
||||
use ReflectionProperty;
|
||||
|
||||
class ReflectionHelper
|
||||
{
|
||||
/**
|
||||
* Retrieves all properties (including private ones), from object and all its ancestors.
|
||||
*
|
||||
* Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes.
|
||||
*
|
||||
* @author muratyaman@gmail.com
|
||||
* @see http://php.net/manual/en/reflectionclass.getproperties.php
|
||||
*
|
||||
* @param ReflectionClass $ref
|
||||
*
|
||||
* @return ReflectionProperty[]
|
||||
*/
|
||||
public static function getProperties(ReflectionClass $ref)
|
||||
{
|
||||
$props = $ref->getProperties();
|
||||
$propsArr = array();
|
||||
|
||||
foreach ($props as $prop) {
|
||||
$propertyName = $prop->getName();
|
||||
$propsArr[$propertyName] = $prop;
|
||||
}
|
||||
|
||||
if ($parentClass = $ref->getParentClass()) {
|
||||
$parentPropsArr = self::getProperties($parentClass);
|
||||
foreach ($propsArr as $key => $property) {
|
||||
$parentPropsArr[$key] = $property;
|
||||
}
|
||||
|
||||
return $parentPropsArr;
|
||||
}
|
||||
|
||||
return $propsArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves property by name from object and all its ancestors.
|
||||
*
|
||||
* @param object|string $object
|
||||
* @param string $name
|
||||
*
|
||||
* @throws PropertyException
|
||||
* @throws ReflectionException
|
||||
*
|
||||
* @return ReflectionProperty
|
||||
*/
|
||||
public static function getProperty($object, $name)
|
||||
{
|
||||
$reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object);
|
||||
|
||||
if ($reflection->hasProperty($name)) {
|
||||
return $reflection->getProperty($name);
|
||||
}
|
||||
|
||||
if ($parentClass = $reflection->getParentClass()) {
|
||||
return self::getProperty($parentClass->getName(), $name);
|
||||
}
|
||||
|
||||
throw new PropertyException(
|
||||
sprintf(
|
||||
'The class "%s" doesn\'t have a property with the given name: "%s".',
|
||||
is_object($object) ? get_class($object) : $object,
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
33
DeepCopy/TypeFilter/Date/DateIntervalFilter.php
Normal file
33
DeepCopy/TypeFilter/Date/DateIntervalFilter.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeFilter\Date;
|
||||
|
||||
use DateInterval;
|
||||
use DeepCopy\TypeFilter\TypeFilter;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*
|
||||
* @deprecated Will be removed in 2.0. This filter will no longer be necessary in PHP 7.1+.
|
||||
*/
|
||||
class DateIntervalFilter implements TypeFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param DateInterval $element
|
||||
*
|
||||
* @see http://news.php.net/php.bugs/205076
|
||||
*/
|
||||
public function apply($element)
|
||||
{
|
||||
$copy = new DateInterval('P0D');
|
||||
|
||||
foreach ($element as $propertyName => $propertyValue) {
|
||||
$copy->{$propertyName} = $propertyValue;
|
||||
}
|
||||
|
||||
return $copy;
|
||||
}
|
||||
}
|
||||
30
DeepCopy/TypeFilter/ReplaceFilter.php
Normal file
30
DeepCopy/TypeFilter/ReplaceFilter.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeFilter;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class ReplaceFilter implements TypeFilter
|
||||
{
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* @param callable $callable Will be called to get the new value for each element to replace
|
||||
*/
|
||||
public function __construct(callable $callable)
|
||||
{
|
||||
$this->callback = $callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($element)
|
||||
{
|
||||
return call_user_func($this->callback, $element);
|
||||
}
|
||||
}
|
||||
17
DeepCopy/TypeFilter/ShallowCopyFilter.php
Normal file
17
DeepCopy/TypeFilter/ShallowCopyFilter.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeFilter;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class ShallowCopyFilter implements TypeFilter
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($element)
|
||||
{
|
||||
return clone $element;
|
||||
}
|
||||
}
|
||||
36
DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php
Normal file
36
DeepCopy/TypeFilter/Spl/ArrayObjectFilter.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
namespace DeepCopy\TypeFilter\Spl;
|
||||
|
||||
use DeepCopy\DeepCopy;
|
||||
use DeepCopy\TypeFilter\TypeFilter;
|
||||
|
||||
/**
|
||||
* In PHP 7.4 the storage of an ArrayObject isn't returned as
|
||||
* ReflectionProperty. So we deep copy its array copy.
|
||||
*/
|
||||
final class ArrayObjectFilter implements TypeFilter
|
||||
{
|
||||
/**
|
||||
* @var DeepCopy
|
||||
*/
|
||||
private $copier;
|
||||
|
||||
public function __construct(DeepCopy $copier)
|
||||
{
|
||||
$this->copier = $copier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($arrayObject)
|
||||
{
|
||||
$clone = clone $arrayObject;
|
||||
foreach ($arrayObject->getArrayCopy() as $k => $v) {
|
||||
$clone->offsetSet($k, $this->copier->copy($v));
|
||||
}
|
||||
|
||||
return $clone;
|
||||
}
|
||||
}
|
||||
|
||||
10
DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php
Normal file
10
DeepCopy/TypeFilter/Spl/SplDoublyLinkedList.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeFilter\Spl;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@see SplDoublyLinkedListFilter} instead.
|
||||
*/
|
||||
class SplDoublyLinkedList extends SplDoublyLinkedListFilter
|
||||
{
|
||||
}
|
||||
51
DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php
Normal file
51
DeepCopy/TypeFilter/Spl/SplDoublyLinkedListFilter.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeFilter\Spl;
|
||||
|
||||
use Closure;
|
||||
use DeepCopy\DeepCopy;
|
||||
use DeepCopy\TypeFilter\TypeFilter;
|
||||
use SplDoublyLinkedList;
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
class SplDoublyLinkedListFilter implements TypeFilter
|
||||
{
|
||||
private $copier;
|
||||
|
||||
public function __construct(DeepCopy $copier)
|
||||
{
|
||||
$this->copier = $copier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply($element)
|
||||
{
|
||||
$newElement = clone $element;
|
||||
|
||||
$copy = $this->createCopyClosure();
|
||||
|
||||
return $copy($newElement);
|
||||
}
|
||||
|
||||
private function createCopyClosure()
|
||||
{
|
||||
$copier = $this->copier;
|
||||
|
||||
$copy = function (SplDoublyLinkedList $list) use ($copier) {
|
||||
// Replace each element in the list with a deep copy of itself
|
||||
for ($i = 1; $i <= $list->count(); $i++) {
|
||||
$copy = $copier->recursiveCopy($list->shift());
|
||||
|
||||
$list->push($copy);
|
||||
}
|
||||
|
||||
return $list;
|
||||
};
|
||||
|
||||
return Closure::bind($copy, null, DeepCopy::class);
|
||||
}
|
||||
}
|
||||
13
DeepCopy/TypeFilter/TypeFilter.php
Normal file
13
DeepCopy/TypeFilter/TypeFilter.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeFilter;
|
||||
|
||||
interface TypeFilter
|
||||
{
|
||||
/**
|
||||
* Applies the filter to the object.
|
||||
*
|
||||
* @param mixed $element
|
||||
*/
|
||||
public function apply($element);
|
||||
}
|
||||
29
DeepCopy/TypeMatcher/TypeMatcher.php
Normal file
29
DeepCopy/TypeMatcher/TypeMatcher.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy\TypeMatcher;
|
||||
|
||||
class TypeMatcher
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
public function __construct($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $element
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function matches($element)
|
||||
{
|
||||
return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type;
|
||||
}
|
||||
}
|
||||
20
DeepCopy/deep_copy.php
Normal file
20
DeepCopy/deep_copy.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace DeepCopy;
|
||||
|
||||
use function function_exists;
|
||||
|
||||
if (false === function_exists('DeepCopy\deep_copy')) {
|
||||
/**
|
||||
* Deep copies the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param bool $useCloneMethod
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function deep_copy($value, $useCloneMethod = false)
|
||||
{
|
||||
return (new DeepCopy($useCloneMethod))->copy($value);
|
||||
}
|
||||
}
|
||||
153
Mpdf/Barcode.php
Normal file
153
Mpdf/Barcode.php
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class Barcode
|
||||
{
|
||||
|
||||
public function getBarcodeArray($code, $type, $pr = '')
|
||||
{
|
||||
$barcode = $this->getBarcode($code, $type, $pr);
|
||||
return $barcode ? $barcode->getData() : false;
|
||||
}
|
||||
|
||||
public function getChecksum($code, $type)
|
||||
{
|
||||
$barcode = $this->getBarcode($code, $type);
|
||||
return $barcode ? $barcode->getChecksum() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param string $type
|
||||
* @param float $pr
|
||||
*
|
||||
* @return \Mpdf\Barcode\BarcodeInterface
|
||||
*/
|
||||
public function getBarcode($code, $type, $pr = 0.0)
|
||||
{
|
||||
switch (strtoupper($type)) {
|
||||
case 'ISBN':
|
||||
case 'ISSN':
|
||||
case 'EAN13': // EAN 13
|
||||
return new Barcode\EanUpc($code, 13, 11, 7, 0.33, 25.93);
|
||||
|
||||
case 'UPCA': // UPC-A
|
||||
return new Barcode\EanUpc($code, 12, 9, 9, 0.33, 25.91);
|
||||
|
||||
case 'UPCE': // UPC-E
|
||||
return new Barcode\EanUpc($code, 6, 9, 7, 0.33, 25.93);
|
||||
|
||||
case 'EAN8': // EAN 8
|
||||
return new Barcode\EanUpc($code, 8, 7, 7, 0.33, 21.64);
|
||||
|
||||
case 'EAN2': // 2-Digits UPC-Based Extention
|
||||
return new Barcode\EanExt($code, 2, 7, 7, 0.33, 20, 9);
|
||||
|
||||
case 'EAN5': // 5-Digits UPC-Based Extention
|
||||
return new Barcode\EanExt($code, 5, 7, 7, 0.33, 20, 9);
|
||||
|
||||
case 'IMB': // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
|
||||
$xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.)
|
||||
$bpi = 22; // Bars per inch
|
||||
return new Barcode\Imb($code, $xdim, ((25.4 / $bpi) - $xdim) / $xdim, ['D' => 2, 'A' => 2, 'F' => 3, 'T' => 1]);
|
||||
|
||||
case 'RM4SCC': // RM4SCC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
|
||||
$xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.)
|
||||
$bpi = 22; // Bars per inch
|
||||
return new Barcode\Rm4Scc($code, $xdim, ((25.4 / $bpi) - $xdim) / $xdim, ['D' => 5, 'A' => 5, 'F' => 8, 'T' => 2]);
|
||||
|
||||
case 'KIX': // KIX (Klant index - Customer index)
|
||||
$xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.)
|
||||
$bpi = 22; // Bars per inch
|
||||
return new Barcode\Rm4Scc($code, $xdim, ((25.4 / $bpi) - $xdim) / $xdim, ['D' => 5, 'A' => 5, 'F' => 8, 'T' => 2], true);
|
||||
|
||||
case 'POSTNET': // POSTNET
|
||||
$xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.)
|
||||
$bpi = 22; // Bars per inch
|
||||
return new Barcode\Postnet($code, $xdim, ((25.4 / $bpi) - $xdim) / $xdim, false);
|
||||
|
||||
case 'PLANET': // PLANET
|
||||
$xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.)
|
||||
$bpi = 22; // Bars per inch
|
||||
return new Barcode\Postnet($code, $xdim, ((25.4 / $bpi) - $xdim) / $xdim, true);
|
||||
|
||||
case 'C93': // CODE 93 - USS-93
|
||||
return new Barcode\Code93($code);
|
||||
|
||||
case 'CODE11': // CODE 11
|
||||
return new Barcode\Code11($code, ($pr > 0) ? $pr : 3);
|
||||
|
||||
case 'MSI': // MSI (Variation of Plessey code)
|
||||
return new Barcode\Msi($code, false);
|
||||
|
||||
case 'MSI+': // MSI + CHECKSUM (modulo 11)
|
||||
return new Barcode\Msi($code, true);
|
||||
|
||||
case 'CODABAR': // CODABAR
|
||||
return new Barcode\Codabar($code, ($pr > 0) ? $pr : 2.5);
|
||||
|
||||
case 'C128A': // CODE 128 A
|
||||
return new Barcode\Code128($code, 'A');
|
||||
|
||||
case 'C128B': // CODE 128 B
|
||||
return new Barcode\Code128($code, 'B');
|
||||
|
||||
case 'C128C': // CODE 128 C
|
||||
return new Barcode\Code128($code, 'C');
|
||||
|
||||
case 'C128RAW': // CODE 128 RAW -- code is a space separated list of codes with startcode but without checkdigit,stop,end ex: "105 12 34"
|
||||
return new Barcode\Code128($code, 'RAW');
|
||||
|
||||
case 'EAN128A': // EAN 128 A
|
||||
return new Barcode\Code128($code, 'A', true);
|
||||
|
||||
case 'EAN128B': // EAN 128 B
|
||||
return new Barcode\Code128($code, 'B', true);
|
||||
|
||||
case 'EAN128C': // EAN 128 C
|
||||
return new Barcode\Code128($code, 'C', true);
|
||||
|
||||
case 'C39': // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
|
||||
return new Barcode\Code39($this->sanitizeCode($code), ($pr > 0) ? $pr : 2.5, false, false);
|
||||
|
||||
case 'C39+': // CODE 39 with checksum
|
||||
return new Barcode\Code39($this->sanitizeCode($code), ($pr > 0) ? $pr : 2.5, false, true);
|
||||
|
||||
case 'C39E': // CODE 39 EXTENDED
|
||||
return new Barcode\Code39($this->sanitizeCode($code), ($pr > 0) ? $pr : 2.5, true, false);
|
||||
|
||||
case 'C39E+': // CODE 39 EXTENDED + CHECKSUM
|
||||
return new Barcode\Code39($this->sanitizeCode($code), ($pr > 0) ? $pr : 2.5, true, true);
|
||||
|
||||
case 'S25': // Standard 2 of 5
|
||||
return new Barcode\S25($code, false);
|
||||
|
||||
case 'S25+': // Standard 2 of 5 + CHECKSUM
|
||||
return new Barcode\S25($code, true);
|
||||
|
||||
case 'I25': // Interleaved 2 of 5
|
||||
return new Barcode\I25($code, 0, ($pr > 0) ? $pr : 2.5, false);
|
||||
|
||||
case 'I25+': // Interleaved 2 of 5 + CHECKSUM
|
||||
return new Barcode\I25($code, 0, ($pr > 0) ? $pr : 2.5, true);
|
||||
|
||||
case 'I25B': // Interleaved 2 of 5 + Bearer bars
|
||||
return new Barcode\I25($code, 2, ($pr > 0) ? $pr : 2.5, false);
|
||||
|
||||
case 'I25B+': // Interleaved 2 of 5 + CHECKSUM + Bearer bars
|
||||
return new Barcode\I25($code, 2, ($pr > 0) ? $pr : 2.5, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function sanitizeCode($code)
|
||||
{
|
||||
$code = str_replace(chr(194) . chr(160), ' ', $code); // mPDF 5.3.95 (for utf-8 encoded)
|
||||
$code = str_replace(chr(160), ' ', $code); // mPDF 5.3.95 (for win-1252)
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
}
|
||||
69
Mpdf/Barcode/AbstractBarcode.php
Normal file
69
Mpdf/Barcode/AbstractBarcode.php
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
abstract class AbstractBarcode
|
||||
{
|
||||
|
||||
/**
|
||||
* @var mixed[]
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getKey($key)
|
||||
{
|
||||
return isset($this->data[$key]) ? $this->data[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChecksum()
|
||||
{
|
||||
return $this->getKey('checkdigit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert binary barcode sequence to barcode array
|
||||
*
|
||||
* @param string $seq
|
||||
* @param mixed[] $barcodeData
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
protected function binseqToArray($seq, array $barcodeData)
|
||||
{
|
||||
$len = strlen($seq);
|
||||
$w = 0;
|
||||
$k = 0;
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
$w += 1;
|
||||
if (($i == ($len - 1)) or (($i < ($len - 1)) and ($seq[$i] != $seq[($i + 1)]))) {
|
||||
if ($seq[$i] == '1') {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$barcodeData['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$barcodeData['maxw'] += $w;
|
||||
++$k;
|
||||
$w = 0;
|
||||
}
|
||||
}
|
||||
return $barcodeData;
|
||||
}
|
||||
|
||||
}
|
||||
8
Mpdf/Barcode/BarcodeException.php
Normal file
8
Mpdf/Barcode/BarcodeException.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
class BarcodeException extends \Mpdf\MpdfException
|
||||
{
|
||||
|
||||
}
|
||||
30
Mpdf/Barcode/BarcodeInterface.php
Normal file
30
Mpdf/Barcode/BarcodeInterface.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
interface BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getData();
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getKey($key);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getChecksum();
|
||||
|
||||
}
|
||||
93
Mpdf/Barcode/Codabar.php
Normal file
93
Mpdf/Barcode/Codabar.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* CODABAR barcodes.
|
||||
* Older code often used in library systems, sometimes in blood banks
|
||||
*/
|
||||
class Codabar extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
*/
|
||||
public function __construct($code, $printRatio)
|
||||
{
|
||||
$this->init($code, $printRatio);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
*/
|
||||
private function init($code, $printRatio)
|
||||
{
|
||||
$chr = [
|
||||
'0' => '11111221',
|
||||
'1' => '11112211',
|
||||
'2' => '11121121',
|
||||
'3' => '22111111',
|
||||
'4' => '11211211',
|
||||
'5' => '21111211',
|
||||
'6' => '12111121',
|
||||
'7' => '12112111',
|
||||
'8' => '12211111',
|
||||
'9' => '21121111',
|
||||
'-' => '11122111',
|
||||
'$' => '11221111',
|
||||
':' => '21112121',
|
||||
'/' => '21211121',
|
||||
'.' => '21212111',
|
||||
'+' => '11222221',
|
||||
'A' => '11221211',
|
||||
'B' => '12121121',
|
||||
'C' => '11121221',
|
||||
'D' => '11122211'
|
||||
];
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$k = 0;
|
||||
|
||||
$code = strtoupper($code);
|
||||
$len = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
if (!isset($chr[$code[$i]])) {
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" CODABAR barcode value', $code[$i]));
|
||||
}
|
||||
$seq = $chr[$code[$i]];
|
||||
for ($j = 0; $j < 8; ++$j) {
|
||||
if (($j % 2) == 0) {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$x = $seq[$j];
|
||||
if ($x == 2) {
|
||||
$w = $printRatio;
|
||||
} else {
|
||||
$w = 1;
|
||||
}
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
}
|
||||
}
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return 'CODABAR';
|
||||
}
|
||||
|
||||
}
|
||||
143
Mpdf/Barcode/Code11.php
Normal file
143
Mpdf/Barcode/Code11.php
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* CODE11 barcodes.
|
||||
* Used primarily for labeling telecommunications equipment
|
||||
*/
|
||||
class Code11 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
*/
|
||||
public function __construct($code, $printRatio)
|
||||
{
|
||||
$this->init($code, $printRatio);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
*/
|
||||
private function init($code, $printRatio)
|
||||
{
|
||||
$chr = [
|
||||
'0' => '111121',
|
||||
'1' => '211121',
|
||||
'2' => '121121',
|
||||
'3' => '221111',
|
||||
'4' => '112121',
|
||||
'5' => '212111',
|
||||
'6' => '122111',
|
||||
'7' => '111221',
|
||||
'8' => '211211',
|
||||
'9' => '211111',
|
||||
'-' => '112111',
|
||||
'S' => '112211'
|
||||
];
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
|
||||
$k = 0;
|
||||
|
||||
$len = strlen($code);
|
||||
// calculate check digit C
|
||||
|
||||
$p = 1;
|
||||
$check = 0;
|
||||
|
||||
for ($i = ($len - 1); $i >= 0; --$i) {
|
||||
$digit = $code[$i];
|
||||
if ($digit == '-') {
|
||||
$dval = 10;
|
||||
} else {
|
||||
$dval = (int) $digit;
|
||||
}
|
||||
$check += ($dval * $p);
|
||||
++$p;
|
||||
if ($p > 10) {
|
||||
$p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$check %= 11;
|
||||
|
||||
if ($check == 10) {
|
||||
$check = '-';
|
||||
}
|
||||
|
||||
$code .= $check;
|
||||
$checkdigit = $check;
|
||||
|
||||
if ($len > 10) {
|
||||
// calculate check digit K
|
||||
$p = 1;
|
||||
$check = 0;
|
||||
for ($i = $len; $i >= 0; --$i) {
|
||||
$digit = $code[$i];
|
||||
if ($digit == '-') {
|
||||
$dval = 10;
|
||||
} else {
|
||||
$dval = (int) $digit;
|
||||
}
|
||||
$check += ($dval * $p);
|
||||
++$p;
|
||||
if ($p > 9) {
|
||||
$p = 1;
|
||||
}
|
||||
}
|
||||
$check %= 11;
|
||||
$code .= $check;
|
||||
$checkdigit .= $check;
|
||||
++$len;
|
||||
}
|
||||
|
||||
$code = 'S' . $code . 'S';
|
||||
$len += 3;
|
||||
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
if (!isset($chr[$code[$i]])) {
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in CODE11 barcode value', $code[$i]));
|
||||
}
|
||||
$seq = $chr[$code[$i]];
|
||||
for ($j = 0; $j < 6; ++$j) {
|
||||
if (($j % 2) == 0) {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$x = $seq[$j];
|
||||
if ($x == 2) {
|
||||
$w = $printRatio;
|
||||
} else {
|
||||
$w = 1;
|
||||
}
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
}
|
||||
}
|
||||
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'CODE11';
|
||||
}
|
||||
|
||||
}
|
||||
277
Mpdf/Barcode/Code128.php
Normal file
277
Mpdf/Barcode/Code128.php
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
use Mpdf\Utils\UtfString;
|
||||
|
||||
/**
|
||||
* C128 barcodes.
|
||||
* Very capable code, excellent density, high reliability; in very wide use world-wide
|
||||
*/
|
||||
class Code128 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param string $type
|
||||
* @param bool $ean
|
||||
*/
|
||||
public function __construct($code, $type = 'B', $ean = false)
|
||||
{
|
||||
$this->init($code, $type, $ean);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param string $type
|
||||
* @param bool $ean
|
||||
*/
|
||||
protected function init($code, $type, $ean)
|
||||
{
|
||||
$code = UtfString::strcode2utf($code); // mPDF 5.7.1 Allows e.g. <barcode code="5432
1068" type="C128A" />
|
||||
|
||||
$chr = [
|
||||
'212222', /* 00 */
|
||||
'222122', /* 01 */
|
||||
'222221', /* 02 */
|
||||
'121223', /* 03 */
|
||||
'121322', /* 04 */
|
||||
'131222', /* 05 */
|
||||
'122213', /* 06 */
|
||||
'122312', /* 07 */
|
||||
'132212', /* 08 */
|
||||
'221213', /* 09 */
|
||||
'221312', /* 10 */
|
||||
'231212', /* 11 */
|
||||
'112232', /* 12 */
|
||||
'122132', /* 13 */
|
||||
'122231', /* 14 */
|
||||
'113222', /* 15 */
|
||||
'123122', /* 16 */
|
||||
'123221', /* 17 */
|
||||
'223211', /* 18 */
|
||||
'221132', /* 19 */
|
||||
'221231', /* 20 */
|
||||
'213212', /* 21 */
|
||||
'223112', /* 22 */
|
||||
'312131', /* 23 */
|
||||
'311222', /* 24 */
|
||||
'321122', /* 25 */
|
||||
'321221', /* 26 */
|
||||
'312212', /* 27 */
|
||||
'322112', /* 28 */
|
||||
'322211', /* 29 */
|
||||
'212123', /* 30 */
|
||||
'212321', /* 31 */
|
||||
'232121', /* 32 */
|
||||
'111323', /* 33 */
|
||||
'131123', /* 34 */
|
||||
'131321', /* 35 */
|
||||
'112313', /* 36 */
|
||||
'132113', /* 37 */
|
||||
'132311', /* 38 */
|
||||
'211313', /* 39 */
|
||||
'231113', /* 40 */
|
||||
'231311', /* 41 */
|
||||
'112133', /* 42 */
|
||||
'112331', /* 43 */
|
||||
'132131', /* 44 */
|
||||
'113123', /* 45 */
|
||||
'113321', /* 46 */
|
||||
'133121', /* 47 */
|
||||
'313121', /* 48 */
|
||||
'211331', /* 49 */
|
||||
'231131', /* 50 */
|
||||
'213113', /* 51 */
|
||||
'213311', /* 52 */
|
||||
'213131', /* 53 */
|
||||
'311123', /* 54 */
|
||||
'311321', /* 55 */
|
||||
'331121', /* 56 */
|
||||
'312113', /* 57 */
|
||||
'312311', /* 58 */
|
||||
'332111', /* 59 */
|
||||
'314111', /* 60 */
|
||||
'221411', /* 61 */
|
||||
'431111', /* 62 */
|
||||
'111224', /* 63 */
|
||||
'111422', /* 64 */
|
||||
'121124', /* 65 */
|
||||
'121421', /* 66 */
|
||||
'141122', /* 67 */
|
||||
'141221', /* 68 */
|
||||
'112214', /* 69 */
|
||||
'112412', /* 70 */
|
||||
'122114', /* 71 */
|
||||
'122411', /* 72 */
|
||||
'142112', /* 73 */
|
||||
'142211', /* 74 */
|
||||
'241211', /* 75 */
|
||||
'221114', /* 76 */
|
||||
'413111', /* 77 */
|
||||
'241112', /* 78 */
|
||||
'134111', /* 79 */
|
||||
'111242', /* 80 */
|
||||
'121142', /* 81 */
|
||||
'121241', /* 82 */
|
||||
'114212', /* 83 */
|
||||
'124112', /* 84 */
|
||||
'124211', /* 85 */
|
||||
'411212', /* 86 */
|
||||
'421112', /* 87 */
|
||||
'421211', /* 88 */
|
||||
'212141', /* 89 */
|
||||
'214121', /* 90 */
|
||||
'412121', /* 91 */
|
||||
'111143', /* 92 */
|
||||
'111341', /* 93 */
|
||||
'131141', /* 94 */
|
||||
'114113', /* 95 */
|
||||
'114311', /* 96 */
|
||||
'411113', /* 97 */
|
||||
'411311', /* 98 */
|
||||
'113141', /* 99 */
|
||||
'114131', /* 100 */
|
||||
'311141', /* 101 */
|
||||
'411131', /* 102 */
|
||||
'211412', /* 103 START A */
|
||||
'211214', /* 104 START B */
|
||||
'211232', /* 105 START C */
|
||||
'233111', /* STOP */
|
||||
'200000' /* END */
|
||||
];
|
||||
|
||||
switch (strtoupper($type)) {
|
||||
case 'RAW':
|
||||
$newCode='';
|
||||
$startid = false;
|
||||
foreach (explode(" ", $code) as $v) {
|
||||
if (is_numeric($v) && round($v, 0) == $v) {
|
||||
if ($v>=0 && $v<=105) {
|
||||
if ($startid===false) {
|
||||
$startid=$v;
|
||||
} else {
|
||||
$newCode.=chr($v);
|
||||
}
|
||||
} else {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE128RAW barcode value. 0-105 needed');
|
||||
}
|
||||
} else {
|
||||
//double spaces generates empty $v any other is not allowed
|
||||
if ($v!='') {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE128RAW barcode value. 0-105 needed');
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($startid<103 || $startid>105) {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE128RAW startid value. Must 103,104 or 105 (for A,B or C)');
|
||||
}
|
||||
$keys='';
|
||||
for ($i = 0; $i <= 105; ++$i) {
|
||||
$keys .= chr($i);
|
||||
}
|
||||
$code=$newCode;
|
||||
break;
|
||||
case 'A':
|
||||
$startid = 103;
|
||||
$keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
|
||||
for ($i = 0; $i < 32; ++$i) {
|
||||
$keys .= chr($i);
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
$startid = 104;
|
||||
$keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~' . chr(127);
|
||||
break;
|
||||
case 'C':
|
||||
$startid = 105;
|
||||
$keys = '';
|
||||
if ((strlen($code) % 2) != 0) {
|
||||
// The length of barcode value must be even ($code). You must pad the number with zeros
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE128C barcode value');
|
||||
}
|
||||
for ($i = 0; $i <= 99; ++$i) {
|
||||
$keys .= chr($i);
|
||||
}
|
||||
$newCode = '';
|
||||
$hclen = (strlen($code) / 2);
|
||||
for ($i = 0; $i < $hclen; ++$i) {
|
||||
if ($code[2 * $i]<"0" || $code[2 * $i]>"9" || $code[2 * $i + 1]<"0" || $code[2 * $i + 1]>"9") {
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in CODE128C barcode value', $code[$i]));
|
||||
}
|
||||
$newCode .= chr((int) ($code[2 * $i] . $code[2 * $i + 1]));
|
||||
}
|
||||
$code = $newCode;
|
||||
break;
|
||||
default:
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE128 barcode type');
|
||||
}
|
||||
|
||||
// calculate check character
|
||||
$sum = $startid;
|
||||
|
||||
// Add FNC 1 - which identifies it as EAN-128
|
||||
if ($ean) {
|
||||
$code = chr(102) . $code;
|
||||
}
|
||||
$clen = strlen($code);
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
if ($ean && $i == 0) {
|
||||
$sum += 102;
|
||||
} else {
|
||||
if (strpos($keys, $code[$i]) === false) {
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in CODE128'.$type.' barcode value', $code[$i]));
|
||||
}
|
||||
$sum += (strpos($keys, $code[$i]) * ($i + 1));
|
||||
}
|
||||
}
|
||||
$check = ($sum % 103);
|
||||
$checkdigit = $check;
|
||||
|
||||
// add start, check and stop codes
|
||||
$code = chr($startid) . $code . chr($check) . chr(106) . chr(107);
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$k = 0;
|
||||
$len = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
|
||||
$ck = strpos($keys, $code[$i]);
|
||||
if (($i == 0) || ($ean && $i == 1) | ($i > ($len - 4))) {
|
||||
$char_num = ord($code[$i]);
|
||||
$seq = $chr[$char_num];
|
||||
} elseif (($ck >= 0) && isset($chr[$ck])) {
|
||||
$seq = $chr[$ck];
|
||||
} else {
|
||||
// invalid character
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in CODE128C barcode value', $code[$i]));
|
||||
}
|
||||
for ($j = 0; $j < 6; ++$j) {
|
||||
if (($j % 2) == 0) {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$w = $seq[$j];
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
}
|
||||
}
|
||||
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return 'CODE128';
|
||||
}
|
||||
|
||||
}
|
||||
235
Mpdf/Barcode/Code39.php
Normal file
235
Mpdf/Barcode/Code39.php
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
|
||||
*/
|
||||
class Code39 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
* @param bool $extended
|
||||
* @param bool $checksum
|
||||
*/
|
||||
public function __construct($code, $printRatio, $extended = false, $checksum = false)
|
||||
{
|
||||
$this->init($code, $printRatio, $extended, $checksum);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
* @param bool $extended
|
||||
* @param bool $checksum
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function init($code, $printRatio, $extended, $checksum)
|
||||
{
|
||||
$chr = [
|
||||
'0' => '111221211',
|
||||
'1' => '211211112',
|
||||
'2' => '112211112',
|
||||
'3' => '212211111',
|
||||
'4' => '111221112',
|
||||
'5' => '211221111',
|
||||
'6' => '112221111',
|
||||
'7' => '111211212',
|
||||
'8' => '211211211',
|
||||
'9' => '112211211',
|
||||
'A' => '211112112',
|
||||
'B' => '112112112',
|
||||
'C' => '212112111',
|
||||
'D' => '111122112',
|
||||
'E' => '211122111',
|
||||
'F' => '112122111',
|
||||
'G' => '111112212',
|
||||
'H' => '211112211',
|
||||
'I' => '112112211',
|
||||
'J' => '111122211',
|
||||
'K' => '211111122',
|
||||
'L' => '112111122',
|
||||
'M' => '212111121',
|
||||
'N' => '111121122',
|
||||
'O' => '211121121',
|
||||
'P' => '112121121',
|
||||
'Q' => '111111222',
|
||||
'R' => '211111221',
|
||||
'S' => '112111221',
|
||||
'T' => '111121221',
|
||||
'U' => '221111112',
|
||||
'V' => '122111112',
|
||||
'W' => '222111111',
|
||||
'X' => '121121112',
|
||||
'Y' => '221121111',
|
||||
'Z' => '122121111',
|
||||
'-' => '121111212',
|
||||
'.' => '221111211',
|
||||
' ' => '122111211',
|
||||
'$' => '121212111',
|
||||
'/' => '121211121',
|
||||
'+' => '121112121',
|
||||
'%' => '111212121',
|
||||
'*' => '121121211',
|
||||
];
|
||||
|
||||
$code = strtoupper($code);
|
||||
$checkdigit = '';
|
||||
|
||||
if ($extended) {
|
||||
// extended mode
|
||||
$code = $this->encodeExt($code);
|
||||
}
|
||||
|
||||
if ($code === false) {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE39 barcode value');
|
||||
}
|
||||
|
||||
if ($checksum) {
|
||||
// checksum
|
||||
$checkdigit = $this->checksum($code);
|
||||
$code .= $checkdigit;
|
||||
}
|
||||
// add star$this->>datat and stop codes
|
||||
$code = '*' . $code . '*';
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$k = 0;
|
||||
$clen = strlen($code);
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
$char = $code[$i];
|
||||
if (!isset($chr[$char])) {
|
||||
// invalid character
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE39 barcode value');
|
||||
}
|
||||
for ($j = 0; $j < 9; ++$j) {
|
||||
if (($j % 2) == 0) {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$x = $chr[$char][$j];
|
||||
if ($x == 2) {
|
||||
$w = $printRatio;
|
||||
} else {
|
||||
$w = 1;
|
||||
}
|
||||
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
}
|
||||
$bararray['bcode'][$k] = ['t' => false, 'w' => 1, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += 1;
|
||||
++$k;
|
||||
}
|
||||
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string to be used for CODE 39 Extended mode.
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
protected function encodeExt($code)
|
||||
{
|
||||
$encode = [
|
||||
chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
|
||||
chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
|
||||
chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
|
||||
chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
|
||||
chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
|
||||
chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
|
||||
chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
|
||||
chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
|
||||
chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
|
||||
chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
|
||||
chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
|
||||
chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
|
||||
chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
|
||||
chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
|
||||
chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
|
||||
chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
|
||||
chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
|
||||
chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
|
||||
chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
|
||||
chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
|
||||
chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
|
||||
chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
|
||||
chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
|
||||
chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
|
||||
chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
|
||||
chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
|
||||
chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
|
||||
chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
|
||||
chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
|
||||
chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
|
||||
chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
|
||||
chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T'
|
||||
];
|
||||
|
||||
$code_ext = '';
|
||||
$clen = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
|
||||
if (ord($code[$i]) > 127) {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE39 barcode value');
|
||||
}
|
||||
|
||||
$code_ext .= $encode[$code[$i]];
|
||||
}
|
||||
|
||||
return $code_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate CODE 39 checksum (modulo 43).
|
||||
*
|
||||
* @param string $code
|
||||
* @return string mixed
|
||||
*/
|
||||
protected function checksum($code)
|
||||
{
|
||||
$chars = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
|
||||
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'
|
||||
];
|
||||
|
||||
$sum = 0;
|
||||
$clen = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
$k = array_keys($chars, $code[$i]);
|
||||
$sum += $k[0];
|
||||
}
|
||||
|
||||
$j = ($sum % 43);
|
||||
|
||||
return $chars[$j];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'CODE39';
|
||||
}
|
||||
|
||||
}
|
||||
226
Mpdf/Barcode/Code93.php
Normal file
226
Mpdf/Barcode/Code93.php
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* CODE 93 - USS-93
|
||||
* Compact code similar to Code 39
|
||||
*/
|
||||
class Code93 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*/
|
||||
public function __construct($code)
|
||||
{
|
||||
$this->init($code);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*/
|
||||
private function init($code)
|
||||
{
|
||||
$chr = [
|
||||
48 => '131112', // 0
|
||||
49 => '111213', // 1
|
||||
50 => '111312', // 2
|
||||
51 => '111411', // 3
|
||||
52 => '121113', // 4
|
||||
53 => '121212', // 5
|
||||
54 => '121311', // 6
|
||||
55 => '111114', // 7
|
||||
56 => '131211', // 8
|
||||
57 => '141111', // 9
|
||||
65 => '211113', // A
|
||||
66 => '211212', // B
|
||||
67 => '211311', // C
|
||||
68 => '221112', // D
|
||||
69 => '221211', // E
|
||||
70 => '231111', // F
|
||||
71 => '112113', // G
|
||||
72 => '112212', // H
|
||||
73 => '112311', // I
|
||||
74 => '122112', // J
|
||||
75 => '132111', // K
|
||||
76 => '111123', // L
|
||||
77 => '111222', // M
|
||||
78 => '111321', // N
|
||||
79 => '121122', // O
|
||||
80 => '131121', // P
|
||||
81 => '212112', // Q
|
||||
82 => '212211', // R
|
||||
83 => '211122', // S
|
||||
84 => '211221', // T
|
||||
85 => '221121', // U
|
||||
86 => '222111', // V
|
||||
87 => '112122', // W
|
||||
88 => '112221', // X
|
||||
89 => '122121', // Y
|
||||
90 => '123111', // Z
|
||||
45 => '121131', // -
|
||||
46 => '311112', // .
|
||||
32 => '311211', //
|
||||
36 => '321111', // $
|
||||
47 => '112131', // /
|
||||
43 => '113121', // +
|
||||
37 => '211131', // %
|
||||
128 => '121221', // ($)
|
||||
129 => '311121', // (/)
|
||||
130 => '122211', // (+)
|
||||
131 => '312111', // (%)
|
||||
42 => '111141', // start-stop
|
||||
];
|
||||
|
||||
$code = strtoupper($code);
|
||||
$encode = [
|
||||
chr(0) => chr(131) . 'U', chr(1) => chr(128) . 'A', chr(2) => chr(128) . 'B', chr(3) => chr(128) . 'C',
|
||||
chr(4) => chr(128) . 'D', chr(5) => chr(128) . 'E', chr(6) => chr(128) . 'F', chr(7) => chr(128) . 'G',
|
||||
chr(8) => chr(128) . 'H', chr(9) => chr(128) . 'I', chr(10) => chr(128) . 'J', chr(11) => '£K',
|
||||
chr(12) => chr(128) . 'L', chr(13) => chr(128) . 'M', chr(14) => chr(128) . 'N', chr(15) => chr(128) . 'O',
|
||||
chr(16) => chr(128) . 'P', chr(17) => chr(128) . 'Q', chr(18) => chr(128) . 'R', chr(19) => chr(128) . 'S',
|
||||
chr(20) => chr(128) . 'T', chr(21) => chr(128) . 'U', chr(22) => chr(128) . 'V', chr(23) => chr(128) . 'W',
|
||||
chr(24) => chr(128) . 'X', chr(25) => chr(128) . 'Y', chr(26) => chr(128) . 'Z', chr(27) => chr(131) . 'A',
|
||||
chr(28) => chr(131) . 'B', chr(29) => chr(131) . 'C', chr(30) => chr(131) . 'D', chr(31) => chr(131) . 'E',
|
||||
chr(32) => ' ', chr(33) => chr(129) . 'A', chr(34) => chr(129) . 'B', chr(35) => chr(129) . 'C',
|
||||
chr(36) => chr(129) . 'D', chr(37) => chr(129) . 'E', chr(38) => chr(129) . 'F', chr(39) => chr(129) . 'G',
|
||||
chr(40) => chr(129) . 'H', chr(41) => chr(129) . 'I', chr(42) => chr(129) . 'J', chr(43) => chr(129) . 'K',
|
||||
chr(44) => chr(129) . 'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129) . 'O',
|
||||
chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
|
||||
chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
|
||||
chr(56) => '8', chr(57) => '9', chr(58) => chr(129) . 'Z', chr(59) => chr(131) . 'F',
|
||||
chr(60) => chr(131) . 'G', chr(61) => chr(131) . 'H', chr(62) => chr(131) . 'I', chr(63) => chr(131) . 'J',
|
||||
chr(64) => chr(131) . 'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
|
||||
chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
|
||||
chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
|
||||
chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
|
||||
chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
|
||||
chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
|
||||
chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131) . 'K',
|
||||
chr(92) => chr(131) . 'L', chr(93) => chr(131) . 'M', chr(94) => chr(131) . 'N', chr(95) => chr(131) . 'O',
|
||||
chr(96) => chr(131) . 'W', chr(97) => chr(130) . 'A', chr(98) => chr(130) . 'B', chr(99) => chr(130) . 'C',
|
||||
chr(100) => chr(130) . 'D', chr(101) => chr(130) . 'E', chr(102) => chr(130) . 'F', chr(103) => chr(130) . 'G',
|
||||
chr(104) => chr(130) . 'H', chr(105) => chr(130) . 'I', chr(106) => chr(130) . 'J', chr(107) => chr(130) . 'K',
|
||||
chr(108) => chr(130) . 'L', chr(109) => chr(130) . 'M', chr(110) => chr(130) . 'N', chr(111) => chr(130) . 'O',
|
||||
chr(112) => chr(130) . 'P', chr(113) => chr(130) . 'Q', chr(114) => chr(130) . 'R', chr(115) => chr(130) . 'S',
|
||||
chr(116) => chr(130) . 'T', chr(117) => chr(130) . 'U', chr(118) => chr(130) . 'V', chr(119) => chr(130) . 'W',
|
||||
chr(120) => chr(130) . 'X', chr(121) => chr(130) . 'Y', chr(122) => chr(130) . 'Z', chr(123) => chr(131) . 'P',
|
||||
chr(124) => chr(131) . 'Q', chr(125) => chr(131) . 'R', chr(126) => chr(131) . 'S', chr(127) => chr(131) . 'T'
|
||||
];
|
||||
|
||||
$code_ext = '';
|
||||
$clen = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
if (ord($code[$i]) > 127) {
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in Code93 barcode value', $code[$i]));
|
||||
}
|
||||
$code_ext .= $encode[$code[$i]];
|
||||
}
|
||||
|
||||
// checksum
|
||||
$code_ext .= $this->checksum($code_ext);
|
||||
|
||||
// add start and stop codes
|
||||
$code = '*' . $code_ext . '*';
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$k = 0;
|
||||
$clen = strlen($code);
|
||||
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
$char = ord($code[$i]);
|
||||
if (!isset($chr[$char])) {
|
||||
// invalid character
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid CODE93 barcode value');
|
||||
}
|
||||
for ($j = 0; $j < 6; ++$j) {
|
||||
if (($j % 2) == 0) {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$w = $chr[$char][$j];
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
}
|
||||
}
|
||||
|
||||
$bararray['bcode'][$k] = ['t' => true, 'w' => 1, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += 1;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate CODE 93 checksum (modulo 47).
|
||||
*
|
||||
* @param string $code
|
||||
* @return string
|
||||
*/
|
||||
protected function checksum($code)
|
||||
{
|
||||
$chars = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
|
||||
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%',
|
||||
'<', '=', '>', '?'
|
||||
];
|
||||
|
||||
// translate special characters
|
||||
$code = strtr($code, chr(128) . chr(131) . chr(129) . chr(130), '<=>?');
|
||||
$len = strlen($code);
|
||||
|
||||
// calculate check digit C
|
||||
$p = 1;
|
||||
$check = 0;
|
||||
for ($i = ($len - 1); $i >= 0; --$i) {
|
||||
$k = array_keys($chars, $code[$i]);
|
||||
$check += ($k[0] * $p);
|
||||
++$p;
|
||||
if ($p > 20) {
|
||||
$p = 1;
|
||||
}
|
||||
}
|
||||
$check %= 47;
|
||||
$c = $chars[$check];
|
||||
$code .= $c;
|
||||
|
||||
// calculate check digit K
|
||||
$p = 1;
|
||||
$check = 0;
|
||||
for ($i = $len; $i >= 0; --$i) {
|
||||
$k = array_keys($chars, $code[$i]);
|
||||
$check += ($k[0] * $p);
|
||||
++$p;
|
||||
if ($p > 15) {
|
||||
$p = 1;
|
||||
}
|
||||
}
|
||||
$check %= 47;
|
||||
$k = $chars[$check];
|
||||
$checksum = $c . $k;
|
||||
|
||||
// resto respecial characters
|
||||
$checksum = strtr($checksum, '<=>?', chr(128) . chr(131) . chr(129) . chr(130));
|
||||
|
||||
return $checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'CODE93';
|
||||
}
|
||||
|
||||
}
|
||||
114
Mpdf/Barcode/EanExt.php
Normal file
114
Mpdf/Barcode/EanExt.php
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* UPC-Based Extentions
|
||||
* 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
|
||||
* 5-Digit Ext.: Used to mark suggested retail price of books
|
||||
*/
|
||||
class EanExt extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param int $length
|
||||
* @param float $leftMargin
|
||||
* @param float $rightMargin
|
||||
* @param float $xDim
|
||||
* @param float $barHeight
|
||||
* @param float $separatorMargin
|
||||
*/
|
||||
public function __construct($code, $length, $leftMargin, $rightMargin, $xDim, $barHeight, $separatorMargin)
|
||||
{
|
||||
$this->init($code, $length);
|
||||
|
||||
$this->data['lightmL'] = $leftMargin; // LEFT light margin = x X-dim (http://www.gs1uk.org)
|
||||
$this->data['lightmR'] = $rightMargin; // RIGHT light margin = x X-dim (http://www.gs1uk.org)
|
||||
$this->data['nom-X'] = $xDim; // Nominal value for X-dim in mm (http://www.gs1uk.org)
|
||||
$this->data['nom-H'] = $barHeight; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org)
|
||||
$this->data['sepM'] = $separatorMargin; // SEPARATION margin = x X-dim (http://web.archive.org/web/19990501035133/http://www.uc-council.org/d36-d.htm)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param int $length
|
||||
*/
|
||||
private function init($code, $length = 5)
|
||||
{
|
||||
// Padding
|
||||
$code = str_pad($code, $length, '0', STR_PAD_LEFT);
|
||||
|
||||
// Calculate check digit
|
||||
if ($length == 2) {
|
||||
$r = $code % 4;
|
||||
} elseif ($length == 5) {
|
||||
$r = (3 * ($code[0] + $code[2] + $code[4])) + (9 * ($code[1] + $code[3]));
|
||||
$r %= 10;
|
||||
} else {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid EAN barcode value');
|
||||
}
|
||||
|
||||
// Convert digits to bars
|
||||
$codes = [
|
||||
'A' => [ // left odd parity
|
||||
'0' => '0001101',
|
||||
'1' => '0011001',
|
||||
'2' => '0010011',
|
||||
'3' => '0111101',
|
||||
'4' => '0100011',
|
||||
'5' => '0110001',
|
||||
'6' => '0101111',
|
||||
'7' => '0111011',
|
||||
'8' => '0110111',
|
||||
'9' => '0001011'],
|
||||
'B' => [ // left even parity
|
||||
'0' => '0100111',
|
||||
'1' => '0110011',
|
||||
'2' => '0011011',
|
||||
'3' => '0100001',
|
||||
'4' => '0011101',
|
||||
'5' => '0111001',
|
||||
'6' => '0000101',
|
||||
'7' => '0010001',
|
||||
'8' => '0001001',
|
||||
'9' => '0010111']
|
||||
];
|
||||
$parities = [];
|
||||
$parities[2] = [
|
||||
'0' => ['A', 'A'],
|
||||
'1' => ['A', 'B'],
|
||||
'2' => ['B', 'A'],
|
||||
'3' => ['B', 'B']
|
||||
];
|
||||
$parities[5] = [
|
||||
'0' => ['B', 'B', 'A', 'A', 'A'],
|
||||
'1' => ['B', 'A', 'B', 'A', 'A'],
|
||||
'2' => ['B', 'A', 'A', 'B', 'A'],
|
||||
'3' => ['B', 'A', 'A', 'A', 'B'],
|
||||
'4' => ['A', 'B', 'B', 'A', 'A'],
|
||||
'5' => ['A', 'A', 'B', 'B', 'A'],
|
||||
'6' => ['A', 'A', 'A', 'B', 'B'],
|
||||
'7' => ['A', 'B', 'A', 'B', 'A'],
|
||||
'8' => ['A', 'B', 'A', 'A', 'B'],
|
||||
'9' => ['A', 'A', 'B', 'A', 'B']
|
||||
];
|
||||
$p = $parities[$length][$r];
|
||||
$seq = '1011'; // left guard bar
|
||||
$seq .= $codes[$p[0]][$code[0]];
|
||||
for ($i = 1; $i < $length; ++$i) {
|
||||
$seq .= '01'; // separator
|
||||
$seq .= $codes[$p[$i]][$code[$i]];
|
||||
}
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
|
||||
$this->data = $this->binseqToArray($seq, $bararray);
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return 'EAN EXT';
|
||||
}
|
||||
|
||||
}
|
||||
270
Mpdf/Barcode/EanUpc.php
Normal file
270
Mpdf/Barcode/EanUpc.php
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* EAN13 and UPC-A barcodes.
|
||||
* EAN13: European Article Numbering international retail product code
|
||||
* UPC-A: Universal product code seen on almost all retail products in the USA and Canada
|
||||
* UPC-E: Short version of UPC symbol
|
||||
*/
|
||||
class EanUpc extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param int $length
|
||||
* @param float $leftMargin
|
||||
* @param float $rightMargin
|
||||
* @param float $xDim
|
||||
* @param float $barHeight
|
||||
*/
|
||||
public function __construct($code, $length, $leftMargin, $rightMargin, $xDim, $barHeight)
|
||||
{
|
||||
$this->init($code, $length);
|
||||
|
||||
$this->data['lightmL'] = $leftMargin; // LEFT light margin = x X-dim (http://www.gs1uk.org)
|
||||
$this->data['lightmR'] = $rightMargin; // RIGHT light margin = x X-dim (http://www.gs1uk.org)
|
||||
$this->data['nom-X'] = $xDim; // Nominal value for X-dim in mm (http://www.gs1uk.org)
|
||||
$this->data['nom-H'] = $barHeight; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param int $length
|
||||
*/
|
||||
private function init($code, $length)
|
||||
{
|
||||
if (preg_match('/[\D]+/', $code)) {
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid EAN UPC barcode value');
|
||||
}
|
||||
|
||||
$upce = false;
|
||||
$checkdigit = false;
|
||||
|
||||
if ($length == 6) {
|
||||
$length = 12; // UPC-A
|
||||
$upce = true; // UPC-E mode
|
||||
}
|
||||
$dataLength = $length - 1;
|
||||
|
||||
// Padding
|
||||
$code = str_pad($code, $dataLength, '0', STR_PAD_LEFT);
|
||||
$codeLength = strlen($code);
|
||||
|
||||
// Calculate check digit
|
||||
$sum_a = 0;
|
||||
for ($i = 1; $i < $dataLength; $i += 2) {
|
||||
$sum_a += $code[$i];
|
||||
}
|
||||
|
||||
if ($length > 12) {
|
||||
$sum_a *= 3;
|
||||
}
|
||||
$sum_b = 0;
|
||||
for ($i = 0; $i < $dataLength; $i += 2) {
|
||||
$sum_b += ($code[$i]);
|
||||
}
|
||||
|
||||
if ($length < 13) {
|
||||
$sum_b *= 3;
|
||||
}
|
||||
|
||||
$r = ($sum_a + $sum_b) % 10;
|
||||
if ($r > 0) {
|
||||
$r = (10 - $r);
|
||||
}
|
||||
|
||||
if ($codeLength == $dataLength) {
|
||||
// Add check digit
|
||||
$code .= $r;
|
||||
$checkdigit = $r;
|
||||
} elseif ($r !== (int) $code[$dataLength]) {
|
||||
// Wrong checkdigit
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid EAN UPC barcode value');
|
||||
}
|
||||
|
||||
if ($length == 12) {
|
||||
// UPC-A
|
||||
$code = '0' . $code;
|
||||
++$length;
|
||||
}
|
||||
|
||||
if ($upce) {
|
||||
// Convert UPC-A to UPC-E
|
||||
$tmp = substr($code, 4, 3);
|
||||
$prodCode = (int) substr($code, 7, 5); // product code
|
||||
$invalidUpce = false;
|
||||
if (($tmp == '000') or ($tmp == '100') or ($tmp == '200')) {
|
||||
// Manufacturer code ends in 000, 100, or 200
|
||||
$upceCode = substr($code, 2, 2) . substr($code, 9, 3) . substr($code, 4, 1);
|
||||
if ($prodCode > 999) {
|
||||
$invalidUpce = true;
|
||||
}
|
||||
} else {
|
||||
$tmp = substr($code, 5, 2);
|
||||
if ($tmp == '00') {
|
||||
// Manufacturer code ends in 00
|
||||
$upceCode = substr($code, 2, 3) . substr($code, 10, 2) . '3';
|
||||
if ($prodCode > 99) {
|
||||
$invalidUpce = true;
|
||||
}
|
||||
} else {
|
||||
$tmp = substr($code, 6, 1);
|
||||
if ($tmp == '0') {
|
||||
// Manufacturer code ends in 0
|
||||
$upceCode = substr($code, 2, 4) . substr($code, 11, 1) . '4';
|
||||
if ($prodCode > 9) {
|
||||
$invalidUpce = true;
|
||||
}
|
||||
} else {
|
||||
// Manufacturer code does not end in zero
|
||||
$upceCode = substr($code, 2, 5) . substr($code, 11, 1);
|
||||
if ($prodCode > 9) {
|
||||
$invalidUpce = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($invalidUpce) {
|
||||
throw new \Mpdf\Barcode\BarcodeException('UPC-A cannot produce a valid UPC-E barcode');
|
||||
}
|
||||
}
|
||||
|
||||
// Convert digits to bars
|
||||
$codes = [
|
||||
'A' => [// left odd parity
|
||||
'0' => '0001101',
|
||||
'1' => '0011001',
|
||||
'2' => '0010011',
|
||||
'3' => '0111101',
|
||||
'4' => '0100011',
|
||||
'5' => '0110001',
|
||||
'6' => '0101111',
|
||||
'7' => '0111011',
|
||||
'8' => '0110111',
|
||||
'9' => '0001011'],
|
||||
'B' => [// left even parity
|
||||
'0' => '0100111',
|
||||
'1' => '0110011',
|
||||
'2' => '0011011',
|
||||
'3' => '0100001',
|
||||
'4' => '0011101',
|
||||
'5' => '0111001',
|
||||
'6' => '0000101',
|
||||
'7' => '0010001',
|
||||
'8' => '0001001',
|
||||
'9' => '0010111'],
|
||||
'C' => [// right
|
||||
'0' => '1110010',
|
||||
'1' => '1100110',
|
||||
'2' => '1101100',
|
||||
'3' => '1000010',
|
||||
'4' => '1011100',
|
||||
'5' => '1001110',
|
||||
'6' => '1010000',
|
||||
'7' => '1000100',
|
||||
'8' => '1001000',
|
||||
'9' => '1110100']
|
||||
];
|
||||
|
||||
$parities = [
|
||||
'0' => ['A', 'A', 'A', 'A', 'A', 'A'],
|
||||
'1' => ['A', 'A', 'B', 'A', 'B', 'B'],
|
||||
'2' => ['A', 'A', 'B', 'B', 'A', 'B'],
|
||||
'3' => ['A', 'A', 'B', 'B', 'B', 'A'],
|
||||
'4' => ['A', 'B', 'A', 'A', 'B', 'B'],
|
||||
'5' => ['A', 'B', 'B', 'A', 'A', 'B'],
|
||||
'6' => ['A', 'B', 'B', 'B', 'A', 'A'],
|
||||
'7' => ['A', 'B', 'A', 'B', 'A', 'B'],
|
||||
'8' => ['A', 'B', 'A', 'B', 'B', 'A'],
|
||||
'9' => ['A', 'B', 'B', 'A', 'B', 'A']
|
||||
];
|
||||
|
||||
$upceParities = [];
|
||||
$upceParities[0] = [
|
||||
'0' => ['B', 'B', 'B', 'A', 'A', 'A'],
|
||||
'1' => ['B', 'B', 'A', 'B', 'A', 'A'],
|
||||
'2' => ['B', 'B', 'A', 'A', 'B', 'A'],
|
||||
'3' => ['B', 'B', 'A', 'A', 'A', 'B'],
|
||||
'4' => ['B', 'A', 'B', 'B', 'A', 'A'],
|
||||
'5' => ['B', 'A', 'A', 'B', 'B', 'A'],
|
||||
'6' => ['B', 'A', 'A', 'A', 'B', 'B'],
|
||||
'7' => ['B', 'A', 'B', 'A', 'B', 'A'],
|
||||
'8' => ['B', 'A', 'B', 'A', 'A', 'B'],
|
||||
'9' => ['B', 'A', 'A', 'B', 'A', 'B']
|
||||
];
|
||||
|
||||
$upceParities[1] = [
|
||||
'0' => ['A', 'A', 'A', 'B', 'B', 'B'],
|
||||
'1' => ['A', 'A', 'B', 'A', 'B', 'B'],
|
||||
'2' => ['A', 'A', 'B', 'B', 'A', 'B'],
|
||||
'3' => ['A', 'A', 'B', 'B', 'B', 'A'],
|
||||
'4' => ['A', 'B', 'A', 'A', 'B', 'B'],
|
||||
'5' => ['A', 'B', 'B', 'A', 'A', 'B'],
|
||||
'6' => ['A', 'B', 'B', 'B', 'A', 'A'],
|
||||
'7' => ['A', 'B', 'A', 'B', 'A', 'B'],
|
||||
'8' => ['A', 'B', 'A', 'B', 'B', 'A'],
|
||||
'9' => ['A', 'B', 'B', 'A', 'B', 'A']
|
||||
];
|
||||
|
||||
$k = 0;
|
||||
$seq = '101'; // left guard bar
|
||||
|
||||
if ($upce && isset($upceCode)) {
|
||||
$bararray = ['code' => $upceCode, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$p = $upceParities[$code[1]][$r];
|
||||
for ($i = 0; $i < 6; ++$i) {
|
||||
$seq .= $codes[$p[$i]][$upceCode[$i]];
|
||||
}
|
||||
$seq .= '010101'; // right guard bar
|
||||
} else {
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$halfLen = ceil($length / 2);
|
||||
if ($length == 8) {
|
||||
for ($i = 0; $i < $halfLen; ++$i) {
|
||||
$seq .= $codes['A'][$code[$i]];
|
||||
}
|
||||
} else {
|
||||
$p = $parities[$code[0]];
|
||||
for ($i = 1; $i < $halfLen; ++$i) {
|
||||
$seq .= $codes[$p[$i - 1]][$code[$i]];
|
||||
}
|
||||
}
|
||||
$seq .= '01010'; // center guard bar
|
||||
for ($i = $halfLen; $i < $length; ++$i) {
|
||||
$seq .= $codes['C'][$code[(int) $i]];
|
||||
}
|
||||
$seq .= '101'; // right guard bar
|
||||
}
|
||||
|
||||
$clen = strlen($seq);
|
||||
$w = 0;
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
$w += 1;
|
||||
if (($i == ($clen - 1)) or (($i < ($clen - 1)) and ($seq[$i] != $seq[($i + 1)]))) {
|
||||
if ($seq[$i] == '1') {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
$w = 0;
|
||||
}
|
||||
}
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'EANUPC';
|
||||
}
|
||||
|
||||
}
|
||||
137
Mpdf/Barcode/I25.php
Normal file
137
Mpdf/Barcode/I25.php
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* Interleaved 2 of 5 barcodes.
|
||||
* Compact numeric code, widely used in industry, air cargo
|
||||
* Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
|
||||
*/
|
||||
class I25 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $topBottomMargin
|
||||
* @param float $printRatio
|
||||
* @param bool $checksum
|
||||
*/
|
||||
public function __construct($code, $topBottomMargin, $printRatio, $checksum = false)
|
||||
{
|
||||
$this->init($code, $printRatio, $checksum);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = $topBottomMargin; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $printRatio
|
||||
* @param bool $checksum
|
||||
*/
|
||||
private function init($code, $printRatio, $checksum)
|
||||
{
|
||||
$chr = [
|
||||
'0' => '11221',
|
||||
'1' => '21112',
|
||||
'2' => '12112',
|
||||
'3' => '22111',
|
||||
'4' => '11212',
|
||||
'5' => '21211',
|
||||
'6' => '12211',
|
||||
'7' => '11122',
|
||||
'8' => '21121',
|
||||
'9' => '12121',
|
||||
'A' => '11',
|
||||
'Z' => '21',
|
||||
];
|
||||
|
||||
$checkdigit = '';
|
||||
if ($checksum) {
|
||||
// add checksum
|
||||
$checkdigit = $this->checksum($code);
|
||||
$code .= $checkdigit;
|
||||
}
|
||||
if ((strlen($code) % 2) != 0) {
|
||||
// add leading zero if code-length is odd
|
||||
$code = '0' . $code;
|
||||
}
|
||||
// add start and stop codes
|
||||
$code = 'AA' . strtolower($code) . 'ZA';
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$k = 0;
|
||||
$clen = strlen($code);
|
||||
for ($i = 0; $i < $clen; $i = ($i + 2)) {
|
||||
$charBar = $code[$i];
|
||||
$charSpace = $code[$i + 1];
|
||||
if ((!isset($chr[$charBar])) or (!isset($chr[$charSpace]))) {
|
||||
// invalid character
|
||||
throw new \Mpdf\Barcode\BarcodeException('Invalid I25 barcode value');
|
||||
}
|
||||
// create a bar-space sequence
|
||||
$seq = '';
|
||||
$chrlen = strlen($chr[$charBar]);
|
||||
for ($s = 0; $s < $chrlen; $s++) {
|
||||
$seq .= $chr[$charBar][$s] . $chr[$charSpace][$s];
|
||||
}
|
||||
$seqlen = strlen($seq);
|
||||
for ($j = 0; $j < $seqlen; ++$j) {
|
||||
if (($j % 2) == 0) {
|
||||
$t = true; // bar
|
||||
} else {
|
||||
$t = false; // space
|
||||
}
|
||||
$x = $seq[$j];
|
||||
if ($x == 2) {
|
||||
$w = $printRatio;
|
||||
} else {
|
||||
$w = 1;
|
||||
}
|
||||
|
||||
$bararray['bcode'][$k] = ['t' => $t, 'w' => $w, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += $w;
|
||||
++$k;
|
||||
}
|
||||
}
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checksum for standard 2 of 5 barcodes.
|
||||
*
|
||||
* @param string $code
|
||||
* @return int
|
||||
*/
|
||||
private function checksum($code)
|
||||
{
|
||||
$len = strlen($code);
|
||||
$sum = 0;
|
||||
for ($i = 0; $i < $len; $i += 2) {
|
||||
$sum += $code[$i];
|
||||
}
|
||||
$sum *= 3;
|
||||
for ($i = 1; $i < $len; $i += 2) {
|
||||
$sum += ($code[$i]);
|
||||
}
|
||||
$r = $sum % 10;
|
||||
if ($r > 0) {
|
||||
$r = (10 - $r);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'I25';
|
||||
}
|
||||
|
||||
}
|
||||
366
Mpdf/Barcode/Imb.php
Normal file
366
Mpdf/Barcode/Imb.php
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
|
||||
*
|
||||
* (requires PHP bcmath extension)
|
||||
*
|
||||
* Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
|
||||
* The fields are described as follows:
|
||||
*
|
||||
* - The Barcode Identifier shall be assigned by USPS to encode the presort identification that is currently
|
||||
* printed in human readable form on the optional endorsement line (OEL) as well as for future USPS use. This
|
||||
* shall be two digits, with the second digit in the range of 0-4. The allowable encoding ranges shall be 00-04,
|
||||
* 10-14, 20-24, 30-34, 40-44, 50-54, 60-64, 70-74, 80-84, and 90-94.
|
||||
*
|
||||
* - The Service Type Identifier shall be assigned by USPS for any combination of services requested on the mailpiece.
|
||||
* The allowable encoding range shall be 000-999. Each 3-digit value shall correspond to a particular mail class
|
||||
* with a particular combination of service(s). Each service program, such as OneCode Confirm and OneCode ACS,
|
||||
* shall provide the list of Service Type Identifier values.
|
||||
*
|
||||
* - The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number that identifies
|
||||
* a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- 899999, while the
|
||||
* allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.
|
||||
*
|
||||
* - The Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces.
|
||||
* The allowable encoding range shall be 000000000-999999999 when used with a 6 digit Mailer ID and 000000-999999
|
||||
* when used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing
|
||||
* the mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may
|
||||
* be 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000-99999, 000000000-999999999,
|
||||
* and 00000000000-99999999999.
|
||||
*/
|
||||
class Imb extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $xDim
|
||||
* @param float $gapWidth
|
||||
* @param int[] $daft
|
||||
*/
|
||||
public function __construct($code, $xDim, $gapWidth, $daft)
|
||||
{
|
||||
if (!function_exists('bcadd')) {
|
||||
throw new \Mpdf\Barcode\BarcodeException('IMB barcodes require bcmath extension to be loaded.');
|
||||
}
|
||||
|
||||
$this->init($code, $gapWidth, $daft);
|
||||
|
||||
$this->data['nom-X'] = $xDim;
|
||||
$this->data['nom-H'] = 3.68; // Nominal value for Height of Full bar in mm (spec.)
|
||||
|
||||
// USPS-B-3200 Revision C = 4.623
|
||||
// USPS-B-3200 Revision E = 3.68
|
||||
$this->data['quietL'] = 3.175; // LEFT Quiet margin = mm (spec.)
|
||||
$this->data['quietR'] = 3.175; // RIGHT Quiet margin = mm (spec.)
|
||||
$this->data['quietTB'] = 0.711; // TOP/BOTTOM Quiet margin = mm (spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $gapWidth
|
||||
* @param int[] $daft
|
||||
*/
|
||||
private function init($code, $gapWidth, $daft)
|
||||
{
|
||||
$asc_chr = [
|
||||
4, 0, 2, 6, 3, 5, 1, 9, 8, 7, 1, 2, 0, 6, 4, 8, 2, 9, 5, 3, 0, 1, 3, 7, 4, 6, 8, 9, 2, 0, 5, 1, 9, 4,
|
||||
3, 8, 6, 7, 1, 2, 4, 3, 9, 5, 7, 8, 3, 0, 2, 1, 4, 0, 9, 1, 7, 0, 2, 4, 6, 3, 7, 1, 9, 5, 8
|
||||
];
|
||||
|
||||
$dsc_chr = [
|
||||
7, 1, 9, 5, 8, 0, 2, 4, 6, 3, 5, 8, 9, 7, 3, 0, 6, 1, 7, 4, 6, 8, 9, 2, 5, 1, 7, 5, 4, 3, 8, 7, 6, 0, 2,
|
||||
5, 4, 9, 3, 0, 1, 6, 8, 2, 0, 4, 5, 9, 6, 7, 5, 2, 6, 3, 8, 5, 1, 9, 8, 7, 4, 0, 2, 6, 3
|
||||
];
|
||||
|
||||
$asc_pos = [
|
||||
3, 0, 8, 11, 1, 12, 8, 11, 10, 6, 4, 12, 2, 7, 9, 6, 7, 9, 2, 8, 4, 0, 12, 7, 10, 9, 0, 7, 10, 5, 7, 9, 6,
|
||||
8, 2, 12, 1, 4, 2, 0, 1, 5, 4, 6, 12, 1, 0, 9, 4, 7, 5, 10, 2, 6, 9, 11, 2, 12, 6, 7, 5, 11, 0, 3, 2
|
||||
];
|
||||
|
||||
$dsc_pos = [
|
||||
2, 10, 12, 5, 9, 1, 5, 4, 3, 9, 11, 5, 10, 1, 6, 3, 4, 1, 10, 0, 2, 11, 8, 6, 1, 12, 3, 8, 6, 4, 4, 11, 0,
|
||||
6, 1, 9, 11, 5, 3, 7, 3, 10, 7, 11, 8, 2, 10, 3, 5, 8, 0, 3, 12, 11, 8, 4, 5, 1, 3, 0, 7, 12, 9, 8, 10
|
||||
];
|
||||
|
||||
$codeArray = explode('-', $code);
|
||||
$trackingNumber = $codeArray[0];
|
||||
|
||||
$routingCode = '';
|
||||
if (isset($codeArray[1])) {
|
||||
$routingCode = $codeArray[1];
|
||||
}
|
||||
|
||||
// Conversion of Routing Code
|
||||
switch (strlen($routingCode)) {
|
||||
case 0:
|
||||
$binaryCode = 0;
|
||||
break;
|
||||
case 5:
|
||||
$binaryCode = bcadd($routingCode, '1');
|
||||
break;
|
||||
case 9:
|
||||
$binaryCode = bcadd($routingCode, '100001');
|
||||
break;
|
||||
case 11:
|
||||
$binaryCode = bcadd($routingCode, '1000100001');
|
||||
break;
|
||||
default:
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid MSI routing code "%s"', $routingCode));
|
||||
}
|
||||
|
||||
$binaryCode = bcmul($binaryCode, 10);
|
||||
$binaryCode = bcadd($binaryCode, $trackingNumber[0]);
|
||||
$binaryCode = bcmul($binaryCode, 5);
|
||||
$binaryCode = bcadd($binaryCode, $trackingNumber[1]);
|
||||
|
||||
$binaryCode .= substr($trackingNumber, 2, 18);
|
||||
|
||||
// convert to hexadecimal
|
||||
$binaryCode = $this->decToHex($binaryCode);
|
||||
|
||||
// pad to get 13 bytes
|
||||
$binaryCode = str_pad($binaryCode, 26, '0', STR_PAD_LEFT);
|
||||
|
||||
// convert string to array of bytes
|
||||
$binaryCodeArray = chunk_split($binaryCode, 2, "\r");
|
||||
$binaryCodeArray = substr($binaryCodeArray, 0, -1);
|
||||
$binaryCodeArray = explode("\r", $binaryCodeArray);
|
||||
|
||||
// calculate frame check sequence
|
||||
$fcs = $this->imbCrc11Fcs($binaryCodeArray);
|
||||
|
||||
// exclude first 2 bits from first byte
|
||||
$first_byte = sprintf('%2s', dechex((hexdec($binaryCodeArray[0]) << 2) >> 2));
|
||||
$binaryCode102bit = $first_byte . substr($binaryCode, 2);
|
||||
|
||||
// convert binary data to codewords
|
||||
$codewords = [];
|
||||
$data = $this->hexToDec($binaryCode102bit);
|
||||
$codewords[0] = bcmod($data, 636) * 2;
|
||||
$data = bcdiv($data, 636);
|
||||
|
||||
for ($i = 1; $i < 9; ++$i) {
|
||||
$codewords[$i] = bcmod($data, 1365);
|
||||
$data = bcdiv($data, 1365);
|
||||
}
|
||||
|
||||
$codewords[9] = $data;
|
||||
if (($fcs >> 10) == 1) {
|
||||
$codewords[9] += 659;
|
||||
}
|
||||
|
||||
// generate lookup tables
|
||||
$table2of13 = $this->imbTables(2, 78);
|
||||
$table5of13 = $this->imbTables(5, 1287);
|
||||
|
||||
// convert codewords to characters
|
||||
$characters = [];
|
||||
$bitmask = 512;
|
||||
|
||||
foreach ($codewords as $k => $val) {
|
||||
if ($val <= 1286) {
|
||||
$chrcode = $table5of13[$val];
|
||||
} else {
|
||||
$chrcode = $table2of13[($val - 1287)];
|
||||
}
|
||||
if (($fcs & $bitmask) > 0) {
|
||||
// bitwise invert
|
||||
$chrcode = ((~$chrcode) & 8191);
|
||||
}
|
||||
$characters[] = $chrcode;
|
||||
$bitmask /= 2;
|
||||
}
|
||||
|
||||
$characters = array_reverse($characters);
|
||||
|
||||
// build bars
|
||||
$k = 0;
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => $daft['F'], 'bcode' => []];
|
||||
for ($i = 0; $i < 65; ++$i) {
|
||||
$asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
|
||||
$dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
|
||||
if ($asc and $dsc) {
|
||||
// full bar (F)
|
||||
$p = 0;
|
||||
$h = $daft['F'];
|
||||
} elseif ($asc) {
|
||||
// ascender (A)
|
||||
$p = 0;
|
||||
$h = $daft['A'];
|
||||
} elseif ($dsc) {
|
||||
// descender (D)
|
||||
$p = $daft['F'] - $daft['D'];
|
||||
$h = $daft['D'];
|
||||
} else {
|
||||
// tracker (T)
|
||||
$p = ($daft['F'] - $daft['T']) / 2;
|
||||
$h = $daft['T'];
|
||||
}
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => $h, 'p' => $p];
|
||||
// Gap
|
||||
$bararray['bcode'][$k++] = ['t' => 0, 'w' => $gapWidth, 'h' => 1, 'p' => 0];
|
||||
$bararray['maxw'] += (1 + $gapWidth);
|
||||
}
|
||||
|
||||
unset($bararray['bcode'][($k - 1)]);
|
||||
$bararray['maxw'] -= $gapWidth;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intelligent Mail Barcode calculation of Frame Check Sequence
|
||||
*
|
||||
* @param string[] $codeArray
|
||||
* @return int
|
||||
*/
|
||||
private function imbCrc11Fcs($codeArray)
|
||||
{
|
||||
$genpoly = 0x0F35; // generator polynomial
|
||||
$fcs = 0x07FF; // Frame Check Sequence
|
||||
|
||||
// do most significant byte skipping the 2 most significant bits
|
||||
$data = hexdec($codeArray[0]) << 5;
|
||||
for ($bit = 2; $bit < 8; ++$bit) {
|
||||
if (($fcs ^ $data) & 0x400) {
|
||||
$fcs = ($fcs << 1) ^ $genpoly;
|
||||
} else {
|
||||
$fcs = ($fcs << 1);
|
||||
}
|
||||
$fcs &= 0x7FF;
|
||||
$data <<= 1;
|
||||
}
|
||||
// do rest of bytes
|
||||
for ($byte = 1; $byte < 13; ++$byte) {
|
||||
$data = hexdec($codeArray[$byte]) << 3;
|
||||
for ($bit = 0; $bit < 8; ++$bit) {
|
||||
if (($fcs ^ $data) & 0x400) {
|
||||
$fcs = ($fcs << 1) ^ $genpoly;
|
||||
} else {
|
||||
$fcs = ($fcs << 1);
|
||||
}
|
||||
$fcs &= 0x7FF;
|
||||
$data <<= 1;
|
||||
}
|
||||
}
|
||||
return $fcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse unsigned short value
|
||||
*
|
||||
* @param int $num
|
||||
* @return int
|
||||
*/
|
||||
private function imbReverseUs($num)
|
||||
{
|
||||
$rev = 0;
|
||||
for ($i = 0; $i < 16; ++$i) {
|
||||
$rev <<= 1;
|
||||
$rev |= ($num & 1);
|
||||
$num >>= 1;
|
||||
}
|
||||
return $rev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Nof13 tables used for Intelligent Mail Barcode
|
||||
*
|
||||
* @param int $n
|
||||
* @param int $size
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
private function imbTables($n, $size)
|
||||
{
|
||||
$table = [];
|
||||
$lli = 0; // LUT lower index
|
||||
$lui = $size - 1; // LUT upper index
|
||||
for ($count = 0; $count < 8192; ++$count) {
|
||||
|
||||
$bitCount = 0;
|
||||
for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
|
||||
$bitCount += (int) (($count & (1 << $bit_index)) != 0);
|
||||
}
|
||||
|
||||
// if we don't have the right number of bits on, go on to the next value
|
||||
if ($bitCount == $n) {
|
||||
$reverse = ($this->imbReverseUs($count) >> 3);
|
||||
// if the reverse is less than count, we have already visited this pair before
|
||||
if ($reverse >= $count) {
|
||||
// If count is symmetric, place it at the first free slot from the end of the list.
|
||||
// Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list
|
||||
if ($reverse == $count) {
|
||||
$table[$lui] = $count;
|
||||
--$lui;
|
||||
} else {
|
||||
$table[$lli] = $count;
|
||||
++$lli;
|
||||
$table[$lli] = $reverse;
|
||||
++$lli;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert large integer number to hexadecimal representation.
|
||||
*
|
||||
* @param int $number
|
||||
* @return string
|
||||
*/
|
||||
private function decToHex($number)
|
||||
{
|
||||
$hex = [];
|
||||
|
||||
if ($number == 0) {
|
||||
return '00';
|
||||
}
|
||||
|
||||
while ($number > 0) {
|
||||
if ($number == 0) {
|
||||
array_push($hex, '0');
|
||||
} else {
|
||||
array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
|
||||
$number = bcdiv($number, '16', 0);
|
||||
}
|
||||
}
|
||||
|
||||
$hex = array_reverse($hex);
|
||||
return implode($hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert large hexadecimal number to decimal representation (string).
|
||||
* (requires PHP bcmath extension)
|
||||
*
|
||||
* @param string $hex
|
||||
* @return int
|
||||
*/
|
||||
private function hexToDec($hex)
|
||||
{
|
||||
$dec = 0;
|
||||
$bitval = 1;
|
||||
$len = strlen($hex);
|
||||
for ($pos = ($len - 1); $pos >= 0; --$pos) {
|
||||
$dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval));
|
||||
$bitval = bcmul($bitval, 16);
|
||||
}
|
||||
return $dec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'IMB';
|
||||
}
|
||||
|
||||
}
|
||||
98
Mpdf/Barcode/Msi.php
Normal file
98
Mpdf/Barcode/Msi.php
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* MSI - Variation of Plessey code, with similar applications
|
||||
* Contains digits (0 to 9) and encodes the data only in the width of bars.
|
||||
*/
|
||||
class Msi extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param int $code
|
||||
* @param bool $checksum
|
||||
*/
|
||||
public function __construct($code, $checksum = false)
|
||||
{
|
||||
$this->init($code, $checksum);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 12; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 12; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $code
|
||||
* @param bool $checksum
|
||||
*/
|
||||
private function init($code, $checksum)
|
||||
{
|
||||
$chr = [
|
||||
'0' => '100100100100',
|
||||
'1' => '100100100110',
|
||||
'2' => '100100110100',
|
||||
'3' => '100100110110',
|
||||
'4' => '100110100100',
|
||||
'5' => '100110100110',
|
||||
'6' => '100110110100',
|
||||
'7' => '100110110110',
|
||||
'8' => '110100100100',
|
||||
'9' => '110100100110',
|
||||
'A' => '110100110100',
|
||||
'B' => '110100110110',
|
||||
'C' => '110110100100',
|
||||
'D' => '110110100110',
|
||||
'E' => '110110110100',
|
||||
'F' => '110110110110',
|
||||
];
|
||||
|
||||
$checkdigit = '';
|
||||
|
||||
if ($checksum) {
|
||||
// add checksum
|
||||
$clen = strlen($code);
|
||||
$p = 2;
|
||||
$check = 0;
|
||||
for ($i = ($clen - 1); $i >= 0; --$i) {
|
||||
$check += (hexdec($code[$i]) * $p);
|
||||
++$p;
|
||||
if ($p > 7) {
|
||||
$p = 2;
|
||||
}
|
||||
}
|
||||
$check %= 11;
|
||||
if ($check > 0) {
|
||||
$check = 11 - $check;
|
||||
}
|
||||
$code .= $check;
|
||||
$checkdigit = $check;
|
||||
}
|
||||
$seq = '110'; // left guard
|
||||
$clen = strlen($code);
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
$digit = $code[$i];
|
||||
if (!isset($chr[$digit])) {
|
||||
// invalid character
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in MSI barcode value', $digit));
|
||||
}
|
||||
$seq .= $chr[$digit];
|
||||
}
|
||||
$seq .= '1001'; // right guard
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $this->binseqToArray($seq, $bararray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'MSI';
|
||||
}
|
||||
|
||||
}
|
||||
124
Mpdf/Barcode/Postnet.php
Normal file
124
Mpdf/Barcode/Postnet.php
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* POSTNET and PLANET barcodes.
|
||||
* Used by U.S. Postal Service for automated mail sorting
|
||||
*/
|
||||
class Postnet extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $xDim
|
||||
* @param float $gapWidth
|
||||
* @param bool $planet
|
||||
*/
|
||||
public function __construct($code, $xDim, $gapWidth, $planet = false)
|
||||
{
|
||||
$this->init($code, $gapWidth, $planet);
|
||||
|
||||
$this->data['nom-X'] = $xDim;
|
||||
$this->data['nom-H'] = 3.175; // Nominal value for Height of Full bar in mm (spec.)
|
||||
$this->data['quietL'] = 3.175; // LEFT Quiet margin = mm (?spec.)
|
||||
$this->data['quietR'] = 3.175; // RIGHT Quiet margin = mm (?spec.)
|
||||
$this->data['quietTB'] = 1.016; // TOP/BOTTOM Quiet margin = mm (?spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $gapWidth
|
||||
* @param bool $planet
|
||||
*/
|
||||
private function init($code, $gapWidth, $planet)
|
||||
{
|
||||
// bar lenght
|
||||
if ($planet) {
|
||||
$barlen = [
|
||||
0 => [1, 1, 2, 2, 2],
|
||||
1 => [2, 2, 2, 1, 1],
|
||||
2 => [2, 2, 1, 2, 1],
|
||||
3 => [2, 2, 1, 1, 2],
|
||||
4 => [2, 1, 2, 2, 1],
|
||||
5 => [2, 1, 2, 1, 2],
|
||||
6 => [2, 1, 1, 2, 2],
|
||||
7 => [1, 2, 2, 2, 1],
|
||||
8 => [1, 2, 2, 1, 2],
|
||||
9 => [1, 2, 1, 2, 2]
|
||||
];
|
||||
} else {
|
||||
$barlen = [
|
||||
0 => [2, 2, 1, 1, 1],
|
||||
1 => [1, 1, 1, 2, 2],
|
||||
2 => [1, 1, 2, 1, 2],
|
||||
3 => [1, 1, 2, 2, 1],
|
||||
4 => [1, 2, 1, 1, 2],
|
||||
5 => [1, 2, 1, 2, 1],
|
||||
6 => [1, 2, 2, 1, 1],
|
||||
7 => [2, 1, 1, 1, 2],
|
||||
8 => [2, 1, 1, 2, 1],
|
||||
9 => [2, 1, 2, 1, 1]
|
||||
];
|
||||
}
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 5, 'bcode' => []];
|
||||
|
||||
$k = 0;
|
||||
$code = str_replace('-', '', $code);
|
||||
$code = str_replace(' ', '', $code);
|
||||
$len = strlen($code);
|
||||
|
||||
// calculate checksum
|
||||
$sum = 0;
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
$sum += (int) $code[$i];
|
||||
}
|
||||
|
||||
$chkd = ($sum % 10);
|
||||
if ($chkd > 0) {
|
||||
$chkd = (10 - $chkd);
|
||||
}
|
||||
|
||||
$code .= $chkd;
|
||||
$checkdigit = $chkd;
|
||||
$len = strlen($code);
|
||||
|
||||
// start bar
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => 5, 'p' => 0];
|
||||
$bararray['bcode'][$k++] = ['t' => 0, 'w' => $gapWidth, 'h' => 5, 'p' => 0];
|
||||
$bararray['maxw'] += (1 + $gapWidth);
|
||||
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
for ($j = 0; $j < 5; ++$j) {
|
||||
$bh = $barlen[$code[$i]][$j];
|
||||
if ($bh == 2) {
|
||||
$h = 5;
|
||||
$p = 0;
|
||||
} else {
|
||||
$h = 2;
|
||||
$p = 3;
|
||||
}
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => $h, 'p' => $p];
|
||||
$bararray['bcode'][$k++] = ['t' => 0, 'w' => $gapWidth, 'h' => 2, 'p' => 0];
|
||||
$bararray['maxw'] += (1 + $gapWidth);
|
||||
}
|
||||
}
|
||||
|
||||
// end bar
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => 5, 'p' => 0];
|
||||
$bararray['maxw'] += 1;
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'POSTNET';
|
||||
}
|
||||
|
||||
}
|
||||
199
Mpdf/Barcode/Rm4Scc.php
Normal file
199
Mpdf/Barcode/Rm4Scc.php
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
class Rm4Scc extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $xDim
|
||||
* @param float $gapWidth
|
||||
* @param int[] $daft
|
||||
* @param bool $kix
|
||||
*/
|
||||
public function __construct($code, $xDim, $gapWidth, $daft, $kix = false)
|
||||
{
|
||||
$this->init($code, $gapWidth, $daft, $kix);
|
||||
|
||||
$this->data['nom-X'] = $xDim;
|
||||
$this->data['nom-H'] = 5.0; // Nominal value for Height of Full bar in mm (spec.)
|
||||
$this->data['quietL'] = 2; // LEFT Quiet margin = mm (spec.)
|
||||
$this->data['quietR'] = 2; // RIGHT Quiet margin = mm (spec.)
|
||||
$this->data['quietTB'] = 2; // TOP/BOTTOM Quiet margin = mm (spec?)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param float $gapWidth
|
||||
* @param int[] $daft
|
||||
* @param bool $kix
|
||||
*/
|
||||
private function init($code, $gapWidth, $daft, $kix)
|
||||
{
|
||||
$notkix = !$kix;
|
||||
|
||||
// bar mode
|
||||
// 1 = pos 1, length 2
|
||||
// 2 = pos 1, length 3
|
||||
// 3 = pos 2, length 1
|
||||
// 4 = pos 2, length 2
|
||||
|
||||
$barmode = [
|
||||
'0' => [3, 3, 2, 2],
|
||||
'1' => [3, 4, 1, 2],
|
||||
'2' => [3, 4, 2, 1],
|
||||
'3' => [4, 3, 1, 2],
|
||||
'4' => [4, 3, 2, 1],
|
||||
'5' => [4, 4, 1, 1],
|
||||
'6' => [3, 1, 4, 2],
|
||||
'7' => [3, 2, 3, 2],
|
||||
'8' => [3, 2, 4, 1],
|
||||
'9' => [4, 1, 3, 2],
|
||||
'A' => [4, 1, 4, 1],
|
||||
'B' => [4, 2, 3, 1],
|
||||
'C' => [3, 1, 2, 4],
|
||||
'D' => [3, 2, 1, 4],
|
||||
'E' => [3, 2, 2, 3],
|
||||
'F' => [4, 1, 1, 4],
|
||||
'G' => [4, 1, 2, 3],
|
||||
'H' => [4, 2, 1, 3],
|
||||
'I' => [1, 3, 4, 2],
|
||||
'J' => [1, 4, 3, 2],
|
||||
'K' => [1, 4, 4, 1],
|
||||
'L' => [2, 3, 3, 2],
|
||||
'M' => [2, 3, 4, 1],
|
||||
'N' => [2, 4, 3, 1],
|
||||
'O' => [1, 3, 2, 4],
|
||||
'P' => [1, 4, 1, 4],
|
||||
'Q' => [1, 4, 2, 3],
|
||||
'R' => [2, 3, 1, 4],
|
||||
'S' => [2, 3, 2, 3],
|
||||
'T' => [2, 4, 1, 3],
|
||||
'U' => [1, 1, 4, 4],
|
||||
'V' => [1, 2, 3, 4],
|
||||
'W' => [1, 2, 4, 3],
|
||||
'X' => [2, 1, 3, 4],
|
||||
'Y' => [2, 1, 4, 3],
|
||||
'Z' => [2, 2, 3, 3]
|
||||
];
|
||||
|
||||
$code = strtoupper($code);
|
||||
$len = strlen($code);
|
||||
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => $daft['F'], 'bcode' => []];
|
||||
|
||||
if ($notkix) {
|
||||
// table for checksum calculation (row,col)
|
||||
$checktable = [
|
||||
'0' => [1, 1],
|
||||
'1' => [1, 2],
|
||||
'2' => [1, 3],
|
||||
'3' => [1, 4],
|
||||
'4' => [1, 5],
|
||||
'5' => [1, 0],
|
||||
'6' => [2, 1],
|
||||
'7' => [2, 2],
|
||||
'8' => [2, 3],
|
||||
'9' => [2, 4],
|
||||
'A' => [2, 5],
|
||||
'B' => [2, 0],
|
||||
'C' => [3, 1],
|
||||
'D' => [3, 2],
|
||||
'E' => [3, 3],
|
||||
'F' => [3, 4],
|
||||
'G' => [3, 5],
|
||||
'H' => [3, 0],
|
||||
'I' => [4, 1],
|
||||
'J' => [4, 2],
|
||||
'K' => [4, 3],
|
||||
'L' => [4, 4],
|
||||
'M' => [4, 5],
|
||||
'N' => [4, 0],
|
||||
'O' => [5, 1],
|
||||
'P' => [5, 2],
|
||||
'Q' => [5, 3],
|
||||
'R' => [5, 4],
|
||||
'S' => [5, 5],
|
||||
'T' => [5, 0],
|
||||
'U' => [0, 1],
|
||||
'V' => [0, 2],
|
||||
'W' => [0, 3],
|
||||
'X' => [0, 4],
|
||||
'Y' => [0, 5],
|
||||
'Z' => [0, 0]
|
||||
];
|
||||
$row = 0;
|
||||
$col = 0;
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
$row += $checktable[$code[$i]][0];
|
||||
$col += $checktable[$code[$i]][1];
|
||||
}
|
||||
$row %= 6;
|
||||
$col %= 6;
|
||||
$chk = array_keys($checktable, [$row, $col]);
|
||||
$code .= $chk[0];
|
||||
$bararray['checkdigit'] = $chk[0];
|
||||
++$len;
|
||||
}
|
||||
|
||||
$k = 0;
|
||||
if ($notkix) {
|
||||
// start bar
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => $daft['A'], 'p' => 0];
|
||||
$bararray['bcode'][$k++] = ['t' => 0, 'w' => $gapWidth, 'h' => $daft['A'], 'p' => 0];
|
||||
$bararray['maxw'] += (1 + $gapWidth);
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $len; ++$i) {
|
||||
|
||||
for ($j = 0; $j < 4; ++$j) {
|
||||
|
||||
switch ($barmode[$code[$i]][$j]) {
|
||||
case 1:
|
||||
// ascender (A)
|
||||
$p = 0;
|
||||
$h = $daft['A'];
|
||||
break;
|
||||
case 2:
|
||||
// full bar (F)
|
||||
$p = 0;
|
||||
$h = $daft['F'];
|
||||
break;
|
||||
case 3:
|
||||
// tracker (T)
|
||||
$p = ($daft['F'] - $daft['T']) / 2;
|
||||
$h = $daft['T'];
|
||||
break;
|
||||
case 4:
|
||||
// descender (D)
|
||||
$p = $daft['F'] - $daft['D'];
|
||||
$h = $daft['D'];
|
||||
break;
|
||||
}
|
||||
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => $h, 'p' => $p];
|
||||
$bararray['bcode'][$k++] = ['t' => 0, 'w' => $gapWidth, 'h' => 2, 'p' => 0];
|
||||
$bararray['maxw'] += (1 + $gapWidth);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($notkix) {
|
||||
// stop bar
|
||||
$bararray['bcode'][$k++] = ['t' => 1, 'w' => 1, 'h' => $daft['F'], 'p' => 0];
|
||||
$bararray['maxw'] += 1;
|
||||
}
|
||||
|
||||
$this->data = $bararray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'RM4SCC';
|
||||
}
|
||||
|
||||
}
|
||||
111
Mpdf/Barcode/S25.php
Normal file
111
Mpdf/Barcode/S25.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Barcode;
|
||||
|
||||
/**
|
||||
* Standard 2 of 5 barcodes.
|
||||
* Used in airline ticket marking, photofinishing
|
||||
* Contains digits (0 to 9) and encodes the data only in the width of bars.
|
||||
*/
|
||||
class S25 extends \Mpdf\Barcode\AbstractBarcode implements \Mpdf\Barcode\BarcodeInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param bool $checksum
|
||||
*/
|
||||
public function __construct($code, $checksum = false)
|
||||
{
|
||||
$this->init($code, $checksum);
|
||||
|
||||
$this->data['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.)
|
||||
$this->data['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.)
|
||||
$this->data['lightmL'] = 10; // LEFT light margin = x X-dim (spec.)
|
||||
$this->data['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.)
|
||||
$this->data['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param bool $checksum
|
||||
*/
|
||||
private function init($code, $checksum)
|
||||
{
|
||||
$chr = [
|
||||
'0' => '10101110111010',
|
||||
'1' => '11101010101110',
|
||||
'2' => '10111010101110',
|
||||
'3' => '11101110101010',
|
||||
'4' => '10101110101110',
|
||||
'5' => '11101011101010',
|
||||
'6' => '10111011101010',
|
||||
'7' => '10101011101110',
|
||||
'8' => '10101110111010',
|
||||
'9' => '10111010111010',
|
||||
];
|
||||
|
||||
$checkdigit = '';
|
||||
|
||||
if ($checksum) {
|
||||
// add checksum
|
||||
$checkdigit = $this->checksum($code);
|
||||
$code .= $checkdigit;
|
||||
}
|
||||
|
||||
if ((strlen($code) % 2) != 0) {
|
||||
// add leading zero if code-length is odd
|
||||
$code = '0' . $code;
|
||||
}
|
||||
|
||||
$seq = '11011010';
|
||||
$clen = strlen($code);
|
||||
for ($i = 0; $i < $clen; ++$i) {
|
||||
$digit = $code[$i];
|
||||
if (!isset($chr[$digit])) {
|
||||
// invalid character
|
||||
throw new \Mpdf\Barcode\BarcodeException(sprintf('Invalid character "%s" in S25 barcode value', $digit));
|
||||
}
|
||||
$seq .= $chr[$digit];
|
||||
}
|
||||
|
||||
$seq .= '1101011';
|
||||
$bararray = ['code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => []];
|
||||
$bararray['checkdigit'] = $checkdigit;
|
||||
|
||||
$this->data = $this->binseqToArray($seq, $bararray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checksum for standard 2 of 5 barcodes.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function checksum($code)
|
||||
{
|
||||
$len = strlen($code);
|
||||
$sum = 0;
|
||||
for ($i = 0; $i < $len; $i += 2) {
|
||||
$sum += $code[$i];
|
||||
}
|
||||
$sum *= 3;
|
||||
for ($i = 1; $i < $len; $i += 2) {
|
||||
$sum += ($code[$i]);
|
||||
}
|
||||
$r = $sum % 10;
|
||||
if ($r > 0) {
|
||||
$r = (10 - $r);
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return 'S25';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,9 +21,9 @@ CREDITS From HTML2FPDF:
|
|||
|
||||
-Olivier Plathey for the fpdf.php class [http://www.fpdf.org]
|
||||
-Damon Kohler for the Flowing Block script [mailto:damonkohler@yahoo.com]
|
||||
-Clément Lavoillotte for HTML-oriented FPDF idea
|
||||
-Clément Lavoillotte for HTML-oriented FPDF idea
|
||||
-Yamasoft for the gif.php class [http://www.yamasoft.com/]
|
||||
-Jérôme Fenal for the _parsegif() function
|
||||
-Jérôme Fenal for the _parsegif() function
|
||||
-"VIETCOM" for the PDFTable code [http://www.freepgs.com/vietcom/tool/pdftable/] [mailto:vncommando@yahoo.com]
|
||||
-Yukihiro O. for the SetDash() function [mailto:yukihiro_o@infoseek.jp]
|
||||
-Ron Korving for the WordWrap() function
|
||||
|
|
@ -69,14 +69,14 @@ CREDITS From HTML2FPDF:
|
|||
* @link http://www.ar-php.org
|
||||
* @author Khaled Al-Shamaa <khaled@ar-php.org>
|
||||
* @desc Set of PHP5 / UTF-8 Classes developed to enhance Arabic web
|
||||
* applications by providing set of tools includes stem-based searching,
|
||||
* applications by providing set of tools includes stem-based searching,
|
||||
* translitiration, soundex, Hijri calendar, charset detection and
|
||||
* converter, spell numbers, keyboard language, Muslim prayer time,
|
||||
* converter, spell numbers, keyboard language, Muslim prayer time,
|
||||
* auto-summarization, and more...
|
||||
* @package Arabic
|
||||
*
|
||||
*
|
||||
* @version 1.8 released in Feb 15, 2009
|
||||
*
|
||||
*
|
||||
* @license LGPL
|
||||
****************************************************************************/
|
||||
|
||||
|
|
@ -89,4 +89,3 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
[http://www.opensource.org/licenses/lgpl-license.php]
|
||||
|
||||
116
Mpdf/Cache.php
Normal file
116
Mpdf/Cache.php
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
use DirectoryIterator;
|
||||
|
||||
class Cache
|
||||
{
|
||||
|
||||
private $basePath;
|
||||
|
||||
private $cleanupInterval;
|
||||
|
||||
public function __construct($basePath, $cleanupInterval = 3600)
|
||||
{
|
||||
if (!$this->createBasePath($basePath)) {
|
||||
throw new \Mpdf\MpdfException(sprintf('Temporary files directory "%s" is not writable', $basePath));
|
||||
}
|
||||
|
||||
$this->basePath = $basePath;
|
||||
$this->cleanupInterval = $cleanupInterval;
|
||||
}
|
||||
|
||||
protected function createBasePath($basePath)
|
||||
{
|
||||
if (!file_exists($basePath)) {
|
||||
if (!$this->createBasePath(dirname($basePath))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->createDirectory($basePath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable($basePath) || !is_dir($basePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function createDirectory($basePath)
|
||||
{
|
||||
if (!mkdir($basePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!chmod($basePath, 0777)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function tempFilename($filename)
|
||||
{
|
||||
return $this->getFilePath($filename);
|
||||
}
|
||||
|
||||
public function has($filename)
|
||||
{
|
||||
return file_exists($this->getFilePath($filename));
|
||||
}
|
||||
|
||||
public function load($filename)
|
||||
{
|
||||
return file_get_contents($this->getFilePath($filename));
|
||||
}
|
||||
|
||||
public function write($filename, $data)
|
||||
{
|
||||
$tempFile = tempnam($this->basePath, 'cache_tmp_');
|
||||
file_put_contents($tempFile, $data);
|
||||
|
||||
$path = $this->getFilePath($filename);
|
||||
rename($tempFile, $path);
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function remove($filename)
|
||||
{
|
||||
return unlink($this->getFilePath($filename));
|
||||
}
|
||||
|
||||
public function clearOld()
|
||||
{
|
||||
$iterator = new DirectoryIterator($this->basePath);
|
||||
|
||||
/** @var \DirectoryIterator $item */
|
||||
foreach ($iterator as $item) {
|
||||
if (!$item->isDot()
|
||||
&& $item->isFile()
|
||||
&& !$this->isDotFile($item)
|
||||
&& $this->isOld($item)) {
|
||||
unlink($item->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getFilePath($filename)
|
||||
{
|
||||
return $this->basePath . '/' . $filename;
|
||||
}
|
||||
|
||||
private function isOld(DirectoryIterator $item)
|
||||
{
|
||||
return $item->getMTime() + $this->cleanupInterval < time();
|
||||
}
|
||||
|
||||
public function isDotFile(DirectoryIterator $item)
|
||||
{
|
||||
return substr($item->getFilename(), 0, 1) === '.';
|
||||
}
|
||||
}
|
||||
337
Mpdf/Color/ColorConverter.php
Normal file
337
Mpdf/Color/ColorConverter.php
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Color;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class ColorConverter
|
||||
{
|
||||
|
||||
const MODE_GRAYSCALE = 1;
|
||||
|
||||
const MODE_SPOT = 2;
|
||||
|
||||
const MODE_RGB = 3;
|
||||
|
||||
const MODE_CMYK = 4;
|
||||
|
||||
const MODE_RGBA = 5;
|
||||
|
||||
const MODE_CMYKA = 6;
|
||||
|
||||
private $mpdf;
|
||||
|
||||
private $colorModeConverter;
|
||||
|
||||
private $colorSpaceRestrictor;
|
||||
|
||||
private $cache;
|
||||
|
||||
public function __construct(Mpdf $mpdf, ColorModeConverter $colorModeConverter, ColorSpaceRestrictor $colorSpaceRestrictor)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->colorModeConverter = $colorModeConverter;
|
||||
$this->colorSpaceRestrictor = $colorSpaceRestrictor;
|
||||
|
||||
$this->cache = [];
|
||||
}
|
||||
|
||||
public function convert($color, array &$PDFAXwarnings = [])
|
||||
{
|
||||
$color = strtolower(trim($color));
|
||||
|
||||
if ($color === 'transparent' || $color === 'inherit') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset(NamedColors::$colors[$color])) {
|
||||
$color = NamedColors::$colors[$color];
|
||||
}
|
||||
|
||||
if (!isset($this->cache[$color])) {
|
||||
$c = $this->convertPlain($color, $PDFAXwarnings);
|
||||
$cstr = '';
|
||||
if (is_array($c)) {
|
||||
$c = array_pad($c, 6, 0);
|
||||
$cstr = pack('a1ccccc', $c[0], $c[1] & 0xFF, $c[2] & 0xFF, $c[3] & 0xFF, $c[4] & 0xFF, $c[5] & 0xFF);
|
||||
}
|
||||
|
||||
$this->cache[$color] = $cstr;
|
||||
}
|
||||
|
||||
return $this->cache[$color];
|
||||
}
|
||||
|
||||
public function lighten($c)
|
||||
{
|
||||
$this->ensureBinaryColorFormat($c);
|
||||
|
||||
if ($c[0] == static::MODE_RGB || $c[0] == static::MODE_RGBA) {
|
||||
list($h, $s, $l) = $this->colorModeConverter->rgb2hsl(ord($c[1]) / 255, ord($c[2]) / 255, ord($c[3]) / 255);
|
||||
$l += ((1 - $l) * 0.8);
|
||||
list($r, $g, $b) = $this->colorModeConverter->hsl2rgb($h, $s, $l);
|
||||
$ret = [3, $r, $g, $b];
|
||||
} elseif ($c[0] == static::MODE_CMYK || $c[0] == static::MODE_CMYKA) {
|
||||
$ret = [4, max(0, ord($c[1]) - 20), max(0, ord($c[2]) - 20), max(0, ord($c[3]) - 20), max(0, ord($c[4]) - 20)];
|
||||
} elseif ($c[0] == static::MODE_GRAYSCALE) {
|
||||
$ret = [1, min(255, ord($c[1]) + 32)];
|
||||
}
|
||||
|
||||
$c = array_pad($ret, 6, 0);
|
||||
$cstr = pack('a1ccccc', $c[0], $c[1] & 0xFF, $c[2] & 0xFF, $c[3] & 0xFF, $c[4] & 0xFF, $c[5] & 0xFF);
|
||||
|
||||
return $cstr;
|
||||
}
|
||||
|
||||
public function darken($c)
|
||||
{
|
||||
$this->ensureBinaryColorFormat($c);
|
||||
|
||||
if ($c[0] == static::MODE_RGB || $c[0] == static::MODE_RGBA) {
|
||||
list($h, $s, $l) = $this->colorModeConverter->rgb2hsl(ord($c[1]) / 255, ord($c[2]) / 255, ord($c[3]) / 255);
|
||||
$s *= 0.25;
|
||||
$l *= 0.75;
|
||||
list($r, $g, $b) = $this->colorModeConverter->hsl2rgb($h, $s, $l);
|
||||
$ret = [3, $r, $g, $b];
|
||||
} elseif ($c[0] == static::MODE_CMYK || $c[0] == static::MODE_CMYKA) {
|
||||
$ret = [4, min(100, ord($c[1]) + 20), min(100, ord($c[2]) + 20), min(100, ord($c[3]) + 20), min(100, ord($c[4]) + 20)];
|
||||
} elseif ($c[0] == static::MODE_GRAYSCALE) {
|
||||
$ret = [1, max(0, ord($c[1]) - 32)];
|
||||
}
|
||||
$c = array_pad($ret, 6, 0);
|
||||
$cstr = pack('a1ccccc', $c[0], $c[1] & 0xFF, $c[2] & 0xFF, $c[3] & 0xFF, $c[4] & 0xFF, $c[5] & 0xFF);
|
||||
|
||||
return $cstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $c
|
||||
* @return float[]
|
||||
*/
|
||||
public function invert($c)
|
||||
{
|
||||
$this->ensureBinaryColorFormat($c);
|
||||
|
||||
if ($c[0] == static::MODE_RGB || $c[0] == static::MODE_RGBA) {
|
||||
return [3, 255 - ord($c[1]), 255 - ord($c[2]), 255 - ord($c[3])];
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_CMYK || $c[0] == static::MODE_CMYKA) {
|
||||
return [4, 100 - ord($c[1]), 100 - ord($c[2]), 100 - ord($c[3]), 100 - ord($c[4])];
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_GRAYSCALE) {
|
||||
return [1, 255 - ord($c[1])];
|
||||
}
|
||||
|
||||
// Cannot cope with non-RGB colors at present
|
||||
throw new \Mpdf\MpdfException('Trying to invert non-RGB color');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $c Binary color string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function colAtoString($c)
|
||||
{
|
||||
if ($c[0] == static::MODE_GRAYSCALE) {
|
||||
return 'rgb(' . ord($c[1]) . ', ' . ord($c[1]) . ', ' . ord($c[1]) . ')';
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_SPOT) {
|
||||
return 'spot(' . ord($c[1]) . ', ' . ord($c[2]) . ')';
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_RGB) {
|
||||
return 'rgb(' . ord($c[1]) . ', ' . ord($c[2]) . ', ' . ord($c[3]) . ')';
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_CMYK) {
|
||||
return 'cmyk(' . ord($c[1]) . ', ' . ord($c[2]) . ', ' . ord($c[3]) . ', ' . ord($c[4]) . ')';
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_RGBA) {
|
||||
return 'rgba(' . ord($c[1]) . ', ' . ord($c[2]) . ', ' . ord($c[3]) . ', ' . sprintf('%0.2F', ord($c[4]) / 100) . ')';
|
||||
}
|
||||
|
||||
if ($c[0] == static::MODE_CMYKA) {
|
||||
return 'cmyka(' . ord($c[1]) . ', ' . ord($c[2]) . ', ' . ord($c[3]) . ', ' . ord($c[4]) . ', ' . sprintf('%0.2F', ord($c[5]) / 100) . ')';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return bool|float[]
|
||||
*/
|
||||
private function convertPlain($color, array &$PDFAXwarnings = [])
|
||||
{
|
||||
$c = false;
|
||||
|
||||
if (preg_match('/^[\d]+$/', $color)) {
|
||||
$c = [static::MODE_GRAYSCALE, $color]; // i.e. integer only
|
||||
} elseif (strpos($color, '#') === 0) { // case of #nnnnnn or #nnn
|
||||
$c = $this->processHashColor($color);
|
||||
} elseif (preg_match('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl|spot)\((.*?)\)/', $color, $m)) {
|
||||
$c = $this->processModeColor($m[1], explode(',', $m[2]));
|
||||
}
|
||||
|
||||
if ($this->mpdf->PDFA || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace) {
|
||||
$c = $this->restrictColorSpace($c, $color, $PDFAXwarnings);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $color
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function processHashColor($color)
|
||||
{
|
||||
// in case of Background: #CCC url() x-repeat etc.
|
||||
$cor = preg_replace('/\s+.*/', '', $color);
|
||||
|
||||
// Turn #RGB into #RRGGBB
|
||||
if (strlen($cor) === 4) {
|
||||
$cor = '#' . $cor[1] . $cor[1] . $cor[2] . $cor[2] . $cor[3] . $cor[3];
|
||||
}
|
||||
|
||||
$r = hexdec(substr($cor, 1, 2));
|
||||
$g = hexdec(substr($cor, 3, 2));
|
||||
$b = hexdec(substr($cor, 5, 2));
|
||||
|
||||
return [3, $r, $g, $b];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $mode
|
||||
* @param mixed[] $cores
|
||||
* @return bool|float[]
|
||||
*/
|
||||
private function processModeColor($mode, array $cores)
|
||||
{
|
||||
$c = false;
|
||||
|
||||
$cores = $this->convertPercentCoreValues($mode, $cores);
|
||||
|
||||
switch ($mode) {
|
||||
case 'rgb':
|
||||
return [static::MODE_RGB, $cores[0], $cores[1], $cores[2]];
|
||||
|
||||
case 'rgba':
|
||||
return [static::MODE_RGBA, $cores[0], $cores[1], $cores[2], $cores[3] * 100];
|
||||
|
||||
case 'cmyk':
|
||||
case 'device-cmyk':
|
||||
return [static::MODE_CMYK, $cores[0], $cores[1], $cores[2], $cores[3]];
|
||||
|
||||
case 'cmyka':
|
||||
case 'device-cmyka':
|
||||
return [static::MODE_CMYKA, $cores[0], $cores[1], $cores[2], $cores[3], $cores[4] * 100];
|
||||
|
||||
case 'hsl':
|
||||
$conv = $this->colorModeConverter->hsl2rgb($cores[0] / 360, $cores[1], $cores[2]);
|
||||
return [static::MODE_RGB, $conv[0], $conv[1], $conv[2]];
|
||||
|
||||
case 'hsla':
|
||||
$conv = $this->colorModeConverter->hsl2rgb($cores[0] / 360, $cores[1], $cores[2]);
|
||||
return [static::MODE_RGBA, $conv[0], $conv[1], $conv[2], $cores[3] * 100];
|
||||
|
||||
case 'spot':
|
||||
$name = strtoupper(trim($cores[0]));
|
||||
|
||||
if (!isset($this->mpdf->spotColors[$name])) {
|
||||
if (isset($cores[5])) {
|
||||
$this->mpdf->AddSpotColor($cores[0], $cores[2], $cores[3], $cores[4], $cores[5]);
|
||||
} else {
|
||||
throw new \Mpdf\MpdfException(sprintf('Undefined spot color "%s"', $name));
|
||||
}
|
||||
}
|
||||
|
||||
return [static::MODE_SPOT, $this->mpdf->spotColors[$name]['i'], $cores[1]];
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mode
|
||||
* @param mixed[] $cores
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function convertPercentCoreValues($mode, array $cores)
|
||||
{
|
||||
$ncores = count($cores);
|
||||
|
||||
if (strpos($cores[0], '%') !== false) {
|
||||
$cores[0] = (float) $cores[0];
|
||||
if ($mode === 'rgb' || $mode === 'rgba') {
|
||||
$cores[0] = (int) ($cores[0] * 255 / 100);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ncores > 1 && strpos($cores[1], '%') !== false) {
|
||||
$cores[1] = (float) $cores[1];
|
||||
if ($mode === 'rgb' || $mode === 'rgba') {
|
||||
$cores[1] = (int) ($cores[1] * 255 / 100);
|
||||
}
|
||||
if ($mode === 'hsl' || $mode === 'hsla') {
|
||||
$cores[1] /= 100;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ncores > 2 && strpos($cores[2], '%') !== false) {
|
||||
$cores[2] = (float) $cores[2];
|
||||
if ($mode === 'rgb' || $mode === 'rgba') {
|
||||
$cores[2] = (int) ($cores[2] * 255 / 100);
|
||||
}
|
||||
if ($mode === 'hsl' || $mode === 'hsla') {
|
||||
$cores[2] /= 100;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ncores > 3 && strpos($cores[3], '%') !== false) {
|
||||
$cores[3] = (float) $cores[3];
|
||||
}
|
||||
|
||||
return $cores;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $c
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function restrictColorSpace($c, $color, &$PDFAXwarnings = [])
|
||||
{
|
||||
return $this->colorSpaceRestrictor->restrictColorSpace($c, $color, $PDFAXwarnings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $color Binary color string
|
||||
*/
|
||||
private function ensureBinaryColorFormat($color)
|
||||
{
|
||||
if (!is_string($color)) {
|
||||
throw new \Mpdf\MpdfException('Invalid color input, binary color string expected');
|
||||
}
|
||||
|
||||
if (strlen($color) !== 6) {
|
||||
throw new \Mpdf\MpdfException('Invalid color input, binary color string expected');
|
||||
}
|
||||
|
||||
if (!in_array($color[0], [static::MODE_GRAYSCALE, static::MODE_SPOT, static::MODE_RGB, static::MODE_CMYK, static::MODE_RGBA, static::MODE_CMYKA])) {
|
||||
throw new \Mpdf\MpdfException('Invalid color input, invalid color mode in binary color string');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
199
Mpdf/Color/ColorModeConverter.php
Normal file
199
Mpdf/Color/ColorModeConverter.php
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Color;
|
||||
|
||||
class ColorModeConverter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param float[] $c
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
public function rgb2gray($c)
|
||||
{
|
||||
if (isset($c[4])) {
|
||||
return [1, ($c[1] * .21) + ($c[2] * .71) + ($c[3] * .07), ord(1), $c[4]];
|
||||
}
|
||||
|
||||
return [1, ($c[1] * .21) + ($c[2] * .71) + ($c[3] * .07)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float[] $c
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
public function cmyk2gray($c)
|
||||
{
|
||||
$rgb = $this->cmyk2rgb($c);
|
||||
return $this->rgb2gray($rgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float[] $c
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
public function rgb2cmyk($c)
|
||||
{
|
||||
$cyan = 1 - ($c[1] / 255);
|
||||
$magenta = 1 - ($c[2] / 255);
|
||||
$yellow = 1 - ($c[3] / 255);
|
||||
$min = min($cyan, $magenta, $yellow);
|
||||
|
||||
if ($min == 1) {
|
||||
if ($c[0] == 5) {
|
||||
return [6, 100, 100, 100, 100, $c[4]];
|
||||
}
|
||||
|
||||
return [4, 100, 100, 100, 100];
|
||||
// For K-Black
|
||||
//if ($c[0]==5) { return array (6,0,0,0,100, $c[4]); }
|
||||
//else { return array (4,0,0,0,100); }
|
||||
}
|
||||
|
||||
$K = $min;
|
||||
$black = 1 - $K;
|
||||
if ($c[0] == 5) {
|
||||
return [6, ($cyan - $K) * 100 / $black, ($magenta - $K) * 100 / $black, ($yellow - $K) * 100 / $black, $K * 100, $c[4]];
|
||||
}
|
||||
|
||||
return [4, ($cyan - $K) * 100 / $black, ($magenta - $K) * 100 / $black, ($yellow - $K) * 100 / $black, $K * 100];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float[] $c
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
public function cmyk2rgb($c)
|
||||
{
|
||||
$rgb = [];
|
||||
$colors = 255 - ($c[4] * 2.55);
|
||||
$rgb[0] = (int) ($colors * (255 - ($c[1] * 2.55)) / 255);
|
||||
$rgb[1] = (int) ($colors * (255 - ($c[2] * 2.55)) / 255);
|
||||
$rgb[2] = (int) ($colors * (255 - ($c[3] * 2.55)) / 255);
|
||||
if ($c[0] == 6) {
|
||||
return [5, $rgb[0], $rgb[1], $rgb[2], $c[5]];
|
||||
}
|
||||
|
||||
return [3, $rgb[0], $rgb[1], $rgb[2]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $r
|
||||
* @param float $g
|
||||
* @param float $b
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
public function rgb2hsl($r, $g, $b)
|
||||
{
|
||||
$h = 0;
|
||||
|
||||
$min = min($r, $g, $b);
|
||||
$max = max($r, $g, $b);
|
||||
|
||||
$diff = $max - $min;
|
||||
$l = ($max + $min) / 2;
|
||||
|
||||
if ($diff == 0) {
|
||||
$h = 0;
|
||||
$s = 0;
|
||||
} else {
|
||||
|
||||
if ($l < 0.5) {
|
||||
$s = $diff / ($max + $min);
|
||||
} else {
|
||||
$s = $diff / (2 - $max - $min);
|
||||
}
|
||||
|
||||
$rDiff = ((($max - $r) / 6) + ($diff / 2)) / $diff;
|
||||
$gDiff = ((($max - $g) / 6) + ($diff / 2)) / $diff;
|
||||
$bDiff = ((($max - $b) / 6) + ($diff / 2)) / $diff;
|
||||
|
||||
if ($r == $max) {
|
||||
$h = $bDiff - $gDiff;
|
||||
} elseif ($g == $max) {
|
||||
$h = (1 / 3) + $rDiff - $bDiff;
|
||||
} elseif ($b == $max) {
|
||||
$h = (2 / 3) + $gDiff - $rDiff;
|
||||
}
|
||||
|
||||
if ($h < 0) {
|
||||
++$h;
|
||||
}
|
||||
|
||||
if ($h > 1) {
|
||||
--$h;
|
||||
}
|
||||
}
|
||||
|
||||
return [$h, $s, $l];
|
||||
}
|
||||
|
||||
/**
|
||||
* Input is HSL value of complementary colour, held in $h2, $s, $l as fractions of 1
|
||||
* Output is RGB in normal 255 255 255 format, held in $r, $g, $b
|
||||
*
|
||||
* @param float $h
|
||||
* @param float $s
|
||||
* @param float $l
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
public function hsl2rgb($h, $s, $l)
|
||||
{
|
||||
if ($s == 0) {
|
||||
$r = $l * 255;
|
||||
$g = $l * 255;
|
||||
$b = $l * 255;
|
||||
} else {
|
||||
if ($l < 0.5) {
|
||||
$tmp = $l * (1 + $s);
|
||||
} else {
|
||||
$tmp = ($l + $s) - ($s * $l);
|
||||
}
|
||||
$tmp2 = 2 * $l - $tmp;
|
||||
$r = round(255 * $this->hue2rgb($tmp2, $tmp, $h + (1 / 3)));
|
||||
$g = round(255 * $this->hue2rgb($tmp2, $tmp, $h));
|
||||
$b = round(255 * $this->hue2rgb($tmp2, $tmp, $h - (1 / 3)));
|
||||
}
|
||||
|
||||
return [$r, $g, $b];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $v1
|
||||
* @param float $v2
|
||||
* @param float $vh
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function hue2rgb($v1, $v2, $vh)
|
||||
{
|
||||
if ($vh < 0) {
|
||||
++$vh;
|
||||
}
|
||||
|
||||
if ($vh > 1) {
|
||||
--$vh;
|
||||
}
|
||||
|
||||
if ((6 * $vh) < 1) {
|
||||
return ($v1 + ($v2 - $v1) * 6 * $vh);
|
||||
}
|
||||
|
||||
if ((2 * $vh) < 1) {
|
||||
return $v2;
|
||||
}
|
||||
|
||||
if ((3 * $vh) < 2) {
|
||||
return ($v1 + ($v2 - $v1) * ((2 / 3 - $vh) * 6));
|
||||
}
|
||||
|
||||
return $v1;
|
||||
}
|
||||
|
||||
}
|
||||
214
Mpdf/Color/ColorSpaceRestrictor.php
Normal file
214
Mpdf/Color/ColorSpaceRestrictor.php
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Color;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class ColorSpaceRestrictor
|
||||
{
|
||||
|
||||
const RESTRICT_TO_GRAYSCALE = 1;
|
||||
|
||||
const RESTRICT_TO_RGB_SPOT_GRAYSCALE = 2;
|
||||
|
||||
const RESTRICT_TO_CMYK_SPOT_GRAYSCALE = 3;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Color\ColorModeConverter
|
||||
*/
|
||||
private $colorModeConverter;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* Process $mode settings
|
||||
* 1 - allow GRAYSCALE only [convert CMYK/RGB->gray]
|
||||
* 2 - allow RGB / SPOT COLOR / Grayscale [convert CMYK->RGB]
|
||||
* 3 - allow CMYK / SPOT COLOR / Grayscale [convert RGB->CMYK]
|
||||
*
|
||||
* @param \Mpdf\Mpdf $mpdf
|
||||
* @param \Mpdf\Color\ColorModeConverter $colorModeConverter
|
||||
* @param int $mode
|
||||
*/
|
||||
public function __construct(Mpdf $mpdf, ColorModeConverter $colorModeConverter, $mode)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->colorModeConverter = $colorModeConverter;
|
||||
$this->mode = $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $c
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]|mixed
|
||||
*/
|
||||
public function restrictColorSpace($c, $color, &$PDFAXwarnings = [])
|
||||
{
|
||||
if (!is_array($c)) {
|
||||
return $c;
|
||||
}
|
||||
|
||||
$mode = (int) $c[0];
|
||||
switch ($mode) {
|
||||
case 1:
|
||||
return $c;
|
||||
case 2:
|
||||
return $this->restrictSpotColorSpace($c, $PDFAXwarnings);
|
||||
case 3:
|
||||
return $this->restrictRgbColorSpace($c, $color, $PDFAXwarnings);
|
||||
case 4:
|
||||
return $this->restrictCmykColorSpace($c, $color, $PDFAXwarnings);
|
||||
case 5:
|
||||
return $this->restrictRgbaColorSpace($c, $color, $PDFAXwarnings);
|
||||
case 6:
|
||||
return $this->restrictCmykaColorSpace($c, $color, $PDFAXwarnings);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $c
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function restrictSpotColorSpace($c, &$PDFAXwarnings = [])
|
||||
{
|
||||
if (!isset($this->mpdf->spotColorIDs[$c[1]])) {
|
||||
throw new \Mpdf\MpdfException('Error: Spot colour has not been defined - ' . $this->mpdf->spotColorIDs[$c[1]]);
|
||||
}
|
||||
|
||||
if ($this->mpdf->PDFA) {
|
||||
if ($this->mpdf->PDFA && !$this->mpdf->PDFAauto) {
|
||||
$PDFAXwarnings[] = "Spot color specified '" . $this->mpdf->spotColorIDs[$c[1]] . "' (converted to process color)";
|
||||
}
|
||||
if ($this->mode != 3) {
|
||||
$sp = $this->mpdf->spotColors[$this->mpdf->spotColorIDs[$c[1]]];
|
||||
$c = $this->colorModeConverter->cmyk2rgb([4, $sp['c'], $sp['m'], $sp['y'], $sp['k']]);
|
||||
}
|
||||
} elseif ($this->mode == 1) {
|
||||
$sp = $this->mpdf->spotColors[$this->mpdf->spotColorIDs[$c[1]]];
|
||||
$c = $this->colorModeConverter->cmyk2gray([4, $sp['c'], $sp['m'], $sp['y'], $sp['k']]);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $c
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function restrictRgbColorSpace($c, $color, &$PDFAXwarnings = [])
|
||||
{
|
||||
if ($this->mpdf->PDFX || ($this->mpdf->PDFA && $this->mode == 3)) {
|
||||
if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
|
||||
$PDFAXwarnings[] = "RGB color specified '" . $color . "' (converted to CMYK)";
|
||||
}
|
||||
$c = $this->colorModeConverter->rgb2cmyk($c);
|
||||
} elseif ($this->mode == 1) {
|
||||
$c = $this->colorModeConverter->rgb2gray($c);
|
||||
} elseif ($this->mode == 3) {
|
||||
$c = $this->colorModeConverter->rgb2cmyk($c);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $c
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function restrictCmykColorSpace($c, $color, &$PDFAXwarnings = [])
|
||||
{
|
||||
if ($this->mpdf->PDFA && $this->mode != 3) {
|
||||
if ($this->mpdf->PDFA && !$this->mpdf->PDFAauto) {
|
||||
$PDFAXwarnings[] = "CMYK color specified '" . $color . "' (converted to RGB)";
|
||||
}
|
||||
$c = $this->colorModeConverter->cmyk2rgb($c);
|
||||
} elseif ($this->mode == 1) {
|
||||
$c = $this->colorModeConverter->cmyk2gray($c);
|
||||
} elseif ($this->mode == 2) {
|
||||
$c = $this->colorModeConverter->cmyk2rgb($c);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $c
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function restrictRgbaColorSpace($c, $color, &$PDFAXwarnings = [])
|
||||
{
|
||||
if ($this->mpdf->PDFX || ($this->mpdf->PDFA && $this->mode == 3)) {
|
||||
if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
|
||||
$PDFAXwarnings[] = "RGB color with transparency specified '" . $color . "' (converted to CMYK without transparency)";
|
||||
}
|
||||
$c = $this->colorModeConverter->rgb2cmyk($c);
|
||||
$c = [4, $c[1], $c[2], $c[3], $c[4]];
|
||||
} elseif ($this->mpdf->PDFA && $this->mode != 3) {
|
||||
if (!$this->mpdf->PDFAauto) {
|
||||
$PDFAXwarnings[] = "RGB color with transparency specified '" . $color . "' (converted to RGB without transparency)";
|
||||
}
|
||||
$c = $this->colorModeConverter->rgb2cmyk($c);
|
||||
$c = [4, $c[1], $c[2], $c[3], $c[4]];
|
||||
} elseif ($this->mode == 1) {
|
||||
$c = $this->colorModeConverter->rgb2gray($c);
|
||||
} elseif ($this->mode == 3) {
|
||||
$c = $this->colorModeConverter->rgb2cmyk($c);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $c
|
||||
* @param string $color
|
||||
* @param string[] $PDFAXwarnings
|
||||
*
|
||||
* @return float[]
|
||||
*/
|
||||
private function restrictCmykaColorSpace($c, $color, &$PDFAXwarnings = [])
|
||||
{
|
||||
if ($this->mpdf->PDFA && $this->mode != 3) {
|
||||
if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
|
||||
$PDFAXwarnings[] = "CMYK color with transparency specified '" . $color . "' (converted to RGB without transparency)";
|
||||
}
|
||||
$c = $this->colorModeConverter->cmyk2rgb($c);
|
||||
$c = [3, $c[1], $c[2], $c[3]];
|
||||
} elseif ($this->mpdf->PDFX || ($this->mpdf->PDFA && $this->mode == 3)) {
|
||||
if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
|
||||
$PDFAXwarnings[] = "CMYK color with transparency specified '" . $color . "' (converted to CMYK without transparency)";
|
||||
}
|
||||
$c = $this->colorModeConverter->cmyk2rgb($c);
|
||||
$c = [3, $c[1], $c[2], $c[3]];
|
||||
} elseif ($this->mode == 1) {
|
||||
$c = $this->colorModeConverter->cmyk2gray($c);
|
||||
} elseif ($this->mode == 2) {
|
||||
$c = $this->colorModeConverter->cmyk2rgb($c);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
}
|
||||
158
Mpdf/Color/NamedColors.php
Normal file
158
Mpdf/Color/NamedColors.php
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Color;
|
||||
|
||||
class NamedColors
|
||||
{
|
||||
|
||||
public static $colors = [
|
||||
'aliceblue' => '#f0f8ff',
|
||||
'antiquewhite' => '#faebd7',
|
||||
'aqua' => '#00ffff',
|
||||
'aquamarine' => '#7fffd4',
|
||||
'azure' => '#f0ffff',
|
||||
'beige' => '#f5f5dc',
|
||||
'bisque' => '#ffe4c4',
|
||||
'black' => '#000000',
|
||||
'blanchedalmond' => '#ffebcd',
|
||||
'blue' => '#0000ff',
|
||||
'blueviolet' => '#8a2be2',
|
||||
'brown' => '#a52a2a',
|
||||
'burlywood' => '#deb887',
|
||||
'cadetblue' => '#5f9ea0',
|
||||
'chartreuse' => '#7fff00',
|
||||
'chocolate' => '#d2691e',
|
||||
'coral' => '#ff7f50',
|
||||
'cornflowerblue' => '#6495ed',
|
||||
'cornsilk' => '#fff8dc',
|
||||
'crimson' => '#dc143c',
|
||||
'cyan' => '#00ffff',
|
||||
'darkblue' => '#00008b',
|
||||
'darkcyan' => '#008b8b',
|
||||
'darkgoldenrod' => '#b8860b',
|
||||
'darkgray' => '#a9a9a9',
|
||||
'darkgreen' => '#006400',
|
||||
'darkgrey' => '#a9a9a9',
|
||||
'darkkhaki' => '#bdb76b',
|
||||
'darkmagenta' => '#8b008b',
|
||||
'darkolivegreen' => '#556b2f',
|
||||
'darkorange' => '#ff8c00',
|
||||
'darkorchid' => '#9932cc',
|
||||
'darkred' => '#8b0000',
|
||||
'darksalmon' => '#e9967a',
|
||||
'darkseagreen' => '#8fbc8f',
|
||||
'darkslateblue' => '#483d8b',
|
||||
'darkslategray' => '#2f4f4f',
|
||||
'darkslategrey' => '#2f4f4f',
|
||||
'darkturquoise' => '#00ced1',
|
||||
'darkviolet' => '#9400d3',
|
||||
'deeppink' => '#ff1493',
|
||||
'deepskyblue' => '#00bfff',
|
||||
'dimgray' => '#696969',
|
||||
'dimgrey' => '#696969',
|
||||
'dodgerblue' => '#1e90ff',
|
||||
'firebrick' => '#b22222',
|
||||
'floralwhite' => '#fffaf0',
|
||||
'forestgreen' => '#228b22',
|
||||
'fuchsia' => '#ff00ff',
|
||||
'gainsboro' => '#dcdcdc',
|
||||
'ghostwhite' => '#f8f8ff',
|
||||
'gold' => '#ffd700',
|
||||
'goldenrod' => '#daa520',
|
||||
'gray' => '#808080',
|
||||
'green' => '#008000',
|
||||
'greenyellow' => '#adff2f',
|
||||
'grey' => '#808080',
|
||||
'honeydew' => '#f0fff0',
|
||||
'hotpink' => '#ff69b4',
|
||||
'indianred' => '#cd5c5c',
|
||||
'indigo' => '#4b0082',
|
||||
'ivory' => '#fffff0',
|
||||
'khaki' => '#f0e68c',
|
||||
'lavender' => '#e6e6fa',
|
||||
'lavenderblush' => '#fff0f5',
|
||||
'lawngreen' => '#7cfc00',
|
||||
'lemonchiffon' => '#fffacd',
|
||||
'lightblue' => '#add8e6',
|
||||
'lightcoral' => '#f08080',
|
||||
'lightcyan' => '#e0ffff',
|
||||
'lightgoldenrodyellow' => '#fafad2',
|
||||
'lightgray' => '#d3d3d3',
|
||||
'lightgreen' => '#90ee90',
|
||||
'lightgrey' => '#d3d3d3',
|
||||
'lightpink' => '#ffb6c1',
|
||||
'lightsalmon' => '#ffa07a',
|
||||
'lightseagreen' => '#20b2aa',
|
||||
'lightskyblue' => '#87cefa',
|
||||
'lightslategray' => '#778899',
|
||||
'lightslategrey' => '#778899',
|
||||
'lightsteelblue' => '#b0c4de',
|
||||
'lightyellow' => '#ffffe0',
|
||||
'lime' => '#00ff00',
|
||||
'limegreen' => '#32cd32',
|
||||
'linen' => '#faf0e6',
|
||||
'magenta' => '#ff00ff',
|
||||
'maroon' => '#800000',
|
||||
'mediumaquamarine' => '#66cdaa',
|
||||
'mediumblue' => '#0000cd',
|
||||
'mediumorchid' => '#ba55d3',
|
||||
'mediumpurple' => '#9370db',
|
||||
'mediumseagreen' => '#3cb371',
|
||||
'mediumslateblue' => '#7b68ee',
|
||||
'mediumspringgreen' => '#00fa9a',
|
||||
'mediumturquoise' => '#48d1cc',
|
||||
'mediumvioletred' => '#c71585',
|
||||
'midnightblue' => '#191970',
|
||||
'mintcream' => '#f5fffa',
|
||||
'mistyrose' => '#ffe4e1',
|
||||
'moccasin' => '#ffe4b5',
|
||||
'navajowhite' => '#ffdead',
|
||||
'navy' => '#000080',
|
||||
'oldlace' => '#fdf5e6',
|
||||
'olive' => '#808000',
|
||||
'olivedrab' => '#6b8e23',
|
||||
'orange' => '#ffa500',
|
||||
'orangered' => '#ff4500',
|
||||
'orchid' => '#da70d6',
|
||||
'palegoldenrod' => '#eee8aa',
|
||||
'palegreen' => '#98fb98',
|
||||
'paleturquoise' => '#afeeee',
|
||||
'palevioletred' => '#d87093',
|
||||
'papayawhip' => '#ffefd5',
|
||||
'peachpuff' => '#ffdab9',
|
||||
'peru' => '#cd853f',
|
||||
'pink' => '#ffc0cb',
|
||||
'plum' => '#dda0dd',
|
||||
'powderblue' => '#b0e0e6',
|
||||
'purple' => '#800080',
|
||||
'red' => '#ff0000',
|
||||
'rosybrown' => '#bc8f8f',
|
||||
'royalblue' => '#4169e1',
|
||||
'saddlebrown' => '#8b4513',
|
||||
'salmon' => '#fa8072',
|
||||
'sandybrown' => '#f4a460',
|
||||
'seagreen' => '#2e8b57',
|
||||
'seashell' => '#fff5ee',
|
||||
'sienna' => '#a0522d',
|
||||
'silver' => '#c0c0c0',
|
||||
'skyblue' => '#87ceeb',
|
||||
'slateblue' => '#6a5acd',
|
||||
'slategray' => '#708090',
|
||||
'slategrey' => '#708090',
|
||||
'snow' => '#fffafa',
|
||||
'springgreen' => '#00ff7f',
|
||||
'steelblue' => '#4682b4',
|
||||
'tan' => '#d2b48c',
|
||||
'teal' => '#008080',
|
||||
'thistle' => '#d8bfd8',
|
||||
'tomato' => '#ff6347',
|
||||
'turquoise' => '#40e0d0',
|
||||
'violet' => '#ee82ee',
|
||||
'violetred' => '#d02090',
|
||||
'wheat' => '#f5deb3',
|
||||
'white' => '#ffffff',
|
||||
'whitesmoke' => '#f5f5f5',
|
||||
'yellow' => '#ffff00',
|
||||
'yellowgreen' => '#9acd32',
|
||||
];
|
||||
}
|
||||
527
Mpdf/Config/ConfigVariables.php
Normal file
527
Mpdf/Config/ConfigVariables.php
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Config;
|
||||
|
||||
use Mpdf\Css\DefaultCss;
|
||||
|
||||
use Mpdf\Language\LanguageToFont;
|
||||
use Mpdf\Language\ScriptToLanguage;
|
||||
|
||||
use Mpdf\Ucdn;
|
||||
|
||||
class ConfigVariables
|
||||
{
|
||||
|
||||
private $defaults;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
$this->defaults = [
|
||||
|
||||
// PAGING
|
||||
'mirrorMargins' => 0,
|
||||
'forcePortraitMargins' => false,
|
||||
'displayDefaultOrientation' => false,
|
||||
|
||||
// Adds date and page info for printer when using @page and "marks:crop,"
|
||||
'printers_info' => false,
|
||||
'bleedMargin' => 5,
|
||||
|
||||
// Distance of cross mark from margin in mm
|
||||
'crossMarkMargin' => 5,
|
||||
// Distance of crop mark from margin in mm
|
||||
'cropMarkMargin' => 8,
|
||||
// Default length in mm of crop line
|
||||
'cropMarkLength' => 18,
|
||||
// Non-printable border at edge of paper sheet in mm
|
||||
'nonPrintMargin' => 8,
|
||||
|
||||
// 'slice' or 'cloneall' or 'clonebycss' - for forced pagebreaks using <pagebreak />
|
||||
// Automatic pagebreaks (flow in text) are always 'slice'
|
||||
'defaultPagebreakType' => 'cloneall',
|
||||
|
||||
// Avoid just the border/background-color of the end of a block being moved on to next page
|
||||
// Allows an (empty) end of block to extend beyond the bottom margin by this amount (mm)
|
||||
'margBuffer' => 2,
|
||||
|
||||
// PAGE NUMBERING
|
||||
'pagenumPrefix' => '',
|
||||
'pagenumSuffix' => '',
|
||||
'nbpgPrefix' => '',
|
||||
'nbpgSuffix' => '',
|
||||
// 1:Decimal, A:uppercase alphabetic etc. (as for list-style shorthands)
|
||||
'defaultPageNumStyle' => '1',
|
||||
|
||||
// PAGE NUMBER ALIASES
|
||||
'aliasNbPg' => '{nb}',
|
||||
'aliasNbPgGp' => '{nbpg}',
|
||||
|
||||
// FONTS, LANGUAGES & CHARACTER SETS
|
||||
// Set maximum size of TTF font file to allow non-subsets - in kB
|
||||
// Used to avoid a font e.g. Arial Unicode MS (perhaps used for substitutions) ever being fully embedded
|
||||
// NB Free serif is 1.5MB, most files are <= 600kB (most 200-400KB)
|
||||
'maxTTFFilesize' => 2000,
|
||||
|
||||
// this value determines whether to subset or not
|
||||
// 0 - 100' => percent characters
|
||||
// i.e. if ==40, mPDF will embed whole font if >40% characters in that font
|
||||
// or embed subset if <40% characters
|
||||
// 0 will force whole file to be embedded (NO subsetting)
|
||||
// 100 will force always to subset
|
||||
// This value is overridden if you set new mPDF('s')
|
||||
// and/or Can set at runtime
|
||||
'percentSubset' => 30,
|
||||
|
||||
// Uses Adobe CJK fonts for CJK languages
|
||||
// default TRUE, only set false if you have defined some available fonts that support CJK
|
||||
// If true this will not stop use of other CJK fonts if specified by font-family:
|
||||
// and vice versa i.e. only dictates behaviour when specified by lang="" incl. AutoFont()
|
||||
'useAdobeCJK' => false,
|
||||
|
||||
// When embedding full TTF font files, remakes the font file using only core tables
|
||||
// May improve function with some PostScript printers (GhostScript/GSView)
|
||||
// Does not work with TTC font collections
|
||||
// Slightly smaller file, increased processing time
|
||||
'repackageTTF' => false,
|
||||
|
||||
// Allows automatic character set conversion if "charset=xxx" detected in html header (WriteHTML() )
|
||||
'allow_charset_conversion' => true,
|
||||
// Automatically determine BIDI text in LTR page
|
||||
'biDirectional' => false,
|
||||
|
||||
// AUTOMATIC FONT SELECTION
|
||||
// Based on script and/or language
|
||||
// mPDF 6.0 (similar to previously using function SetAutoFont() )
|
||||
'autoScriptToLang' => false,
|
||||
'baseScript' => Ucdn::SCRIPT_LATIN,
|
||||
'autoVietnamese' => true,
|
||||
'autoArabic' => true,
|
||||
// mPDF 6.0 (similar to old useLang)
|
||||
'autoLangToFont' => false,
|
||||
|
||||
// Substitute missing characters in UTF-8(multibyte) documents - from other fonts
|
||||
'useSubstitutions' => false,
|
||||
// Weight for bold text when using an artificial (outline) bold, value 0 (off) - 10 (rec. max)
|
||||
'falseBoldWeight' => 5,
|
||||
|
||||
// CONFIGURATION
|
||||
'allow_output_buffering' => false,
|
||||
|
||||
// Adding mPDFI functions
|
||||
'enableImports' => false,
|
||||
|
||||
// Allows top and bottom margins to collapse between block elements
|
||||
'collapseBlockMargins' => true,
|
||||
|
||||
// To interpret "px" pixel values in HTML/CSS (see img_dpi below)
|
||||
'dpi' => 96,
|
||||
|
||||
// Automatically correct for tags where HTML specifies optional end tags e.g. P,LI,DD,TD
|
||||
// If you are confident input html is valid XHTML, turning this off may make it more reliable(?)
|
||||
'allow_html_optional_endtags' => true,
|
||||
|
||||
'ignore_invalid_utf8' => false,
|
||||
// Converts all entities in Text inputs to UTF-8 before encoding
|
||||
'text_input_as_HTML' => false,
|
||||
|
||||
// When writing a block element with position:fixed and overflow:auto, mPDF scales it down to fit in the space
|
||||
// by repeatedly rewriting it and making adjustments. These values give the adjustments used, depending how far out
|
||||
// the previous guess was. The lower the number, the quicker it will finish, but the less accurate the fit may be.
|
||||
// FPR1 is for coarse adjustments, and FPR4 for fine adjustments when it is getting closer.
|
||||
'incrementFPR1' => 10, // i.e. will alter by 1/[10]th of width and try again until within closer limits
|
||||
'incrementFPR2' => 20,
|
||||
'incrementFPR3' => 30,
|
||||
'incrementFPR4' => 50, // i.e. will alter by 1/[50]th of width and try again when it nearly fits
|
||||
|
||||
// COLORSPACE
|
||||
// 1 - allow GRAYSCALE only [convert CMYK/RGB->gray]
|
||||
// 2 - allow RGB / SPOT COLOR / Grayscale [convert CMYK->RGB]
|
||||
// 3 - allow CMYK / SPOT COLOR / Grayscale [convert RGB->CMYK]
|
||||
'restrictColorSpace' => 0,
|
||||
|
||||
// PDFX/1-a Compliant files
|
||||
// true=Forces compliance with PDFX-1a spec
|
||||
// Cannot be used with 'restrictColorSpace' (i.e. no RGB)
|
||||
'PDFX' => false,
|
||||
// Overrides warnings making changes when possible to force PDFX1-a compliance
|
||||
'PDFXauto' => false,
|
||||
|
||||
// PDFA1-b Compliant files
|
||||
// true=Forces compliance with PDFA-1b spec
|
||||
// Can use with 'restrictColorSpace'=3 (for a CMYK file)
|
||||
// Any other settings, uses RGB profile
|
||||
'PDFA' => false,
|
||||
// Overrides warnings making changes when possible to force PDFA1-b compliance
|
||||
'PDFAauto' => false,
|
||||
|
||||
// Colour profile OutputIntent
|
||||
// sRGB_IEC61966-2-1 (=default if blank and PDFA), or other added .icc profile
|
||||
// Must be CMYK for PDFX, or appropriate type for PDFA(RGB or CMYK)
|
||||
'ICCProfile' => '',
|
||||
|
||||
'spotColors' => [],
|
||||
'spotColorIDs' => [],
|
||||
|
||||
// DEBUGGING & DEVELOPERS
|
||||
'debug' => false,
|
||||
// Checks and reports on errors when parsing TTF files - adds significantly to processing time
|
||||
'debugfonts' => false,
|
||||
'showImageErrors' => false,
|
||||
// Die and report error if table is too wide to contain whole words
|
||||
'table_error_report' => false,
|
||||
// Parameter which can be passed to show in error report i.e. chapter number being processed
|
||||
'table_error_report_param' => '',
|
||||
|
||||
'title2annots' => false, // Automatically convert title="" properties in tags, to annotations
|
||||
'annotSize' => 0.5, // default mm for Adobe annotations - nominal
|
||||
'annotMargin' => null, // default position for Annotations
|
||||
'annotOpacity' => 0.5, // default opacity for Annotations
|
||||
|
||||
// BOOKMARKS
|
||||
// makes <a name=""> into a bookmark as well as internal link target, 1' => just name, 2' => name (p.34)
|
||||
// Set an optional array to specify appearance of Bookmarks (by level)
|
||||
// Default values are Black and normal style
|
||||
'anchor2Bookmark' => 0,
|
||||
|
||||
/*
|
||||
Example:
|
||||
'bookmarkStyles' => array(
|
||||
0 => array('color'=> array(0,64,128), 'style'=>'B'),
|
||||
1 => array('color'=> array(128,0,0), 'style'=>''),
|
||||
2 => array('color'=> array(0,128,0), 'style'=>'I'),
|
||||
),
|
||||
*/
|
||||
'bookmarkStyles' => [],
|
||||
|
||||
// Specify whether to automatically generate bookmarks from h1 - h6 tags
|
||||
/*
|
||||
Define arrays with e.g. the tag=>Bookmark-level
|
||||
Remember bookmark levels start at 0
|
||||
(does not work inside tables)
|
||||
H1 - H6 must be uppercase
|
||||
'h2bookmarks' => array('H1'=>0, 'H2'=>1, 'H3'=>2),
|
||||
*/
|
||||
'h2bookmarks' => [],
|
||||
|
||||
// TABLE OF CONTENTS
|
||||
|
||||
// Specify whether to automatically generate ToC entries from h1 - h6 tags
|
||||
/*
|
||||
Define arrays with e.g. the tag=>ToC-level
|
||||
Remember ToC levels start at 0
|
||||
(does not work inside tables)
|
||||
Only the default ToC will be used if > 1 ToCs are defined for the document
|
||||
H1 - H6 must be uppercase
|
||||
'h2toc' => array('H1'=>0, 'H2'=>1, 'H3'=>2),
|
||||
*/
|
||||
'h2toc' => [],
|
||||
|
||||
// INDEX
|
||||
/* Specifies whether to repeat the main entry for each subEntry (true suppresses this)
|
||||
e.g. Mammal:dog ... Mammal:elephant ->
|
||||
[true]
|
||||
Mammal
|
||||
- dog
|
||||
- elephant
|
||||
[false]
|
||||
Mammal, dog
|
||||
Mammal, elephant
|
||||
*/
|
||||
'indexUseSubentries' => true,
|
||||
|
||||
// CSS & STYLES
|
||||
// screen, print, or any other CSS @media type (except "all")
|
||||
'CSSselectMedia' => 'print',
|
||||
|
||||
// PAGE HEADERS & FOOTERS
|
||||
'forcePortraitHeaders' => false,
|
||||
|
||||
// Values used if simple FOOTER/HEADER given i.e. not array
|
||||
'defaultheaderfontsize' => 8, // pt
|
||||
'defaultheaderfontstyle' => 'BI', // '', or 'B' or 'I' or 'BI'
|
||||
'defaultheaderline' => 1, // 1 or 0 - line under the header
|
||||
'defaultfooterfontsize' => 8, // pt
|
||||
'defaultfooterfontstyle' => 'BI', // '', or 'B' or 'I' or 'BI'
|
||||
'defaultfooterline' => 1, // 1 or 0 - line over the footer
|
||||
|
||||
// spacing between bottom of header and line (if present) - function of fontsize
|
||||
'header_line_spacing' => 0.25,
|
||||
// spacing between bottom of header and line (if present) - function of fontsize
|
||||
'footer_line_spacing' => 0.25,
|
||||
// If 'pad' margin-top sets fixed distance in mm (padding) between bottom of header and top of text.
|
||||
// If 'stretch' margin-top sets a minimum distance in mm between top of page and top of text, which expands if header is too large to fit.
|
||||
'setAutoTopMargin' => false,
|
||||
'setAutoBottomMargin' => false,
|
||||
// distance in mm used as padding if 'stretch' mode is used
|
||||
'autoMarginPadding' => 2,
|
||||
|
||||
// TABLES
|
||||
// Forces all cells to have same border, background etc. Improves performance
|
||||
'simpleTables' => false,
|
||||
// Reduce memory usage processing tables (but with increased processing time)
|
||||
'packTableData' => false,
|
||||
|
||||
'ignore_table_percents' => false,
|
||||
'ignore_table_widths' => false,
|
||||
// If table width set > page width, force resizing but keep relative sizes
|
||||
// Also forces respect of cell widths set by %
|
||||
'keep_table_proportions' => true,
|
||||
// automatically reduce fontsize in table if words would have to split ( not in CJK)
|
||||
// 0 or false to disable, value (if set) gives maximum factor to reduce fontsize
|
||||
'shrink_tables_to_fit' => 1.4,
|
||||
|
||||
// If page-break-inside:avoid but cannot fit on full page without
|
||||
// exceeding autosize, setting this value to true will force respect for autosize, and disable the page-break-inside:avoid
|
||||
'tableMinSizePriority' => false,
|
||||
|
||||
// "Keep-with-table" Attempts to keep a <h1> to <h6> tagged heading together with a table which comes immediately after it.
|
||||
'use_kwt' => false,
|
||||
// Set to TRUE to use table Head iteration counter
|
||||
'iterationCounter' => false,
|
||||
// Use table border (using this width in mm) when table breaks across pages
|
||||
// Recommended to use small value e.g. 0.01
|
||||
'splitTableBorderWidth' => 0,
|
||||
|
||||
// Allowed characters for text alignment on decimal marks. Additional codes must start with D
|
||||
// DM - middot U+00B7
|
||||
// DA - arabic decimal mark U+066B
|
||||
'decimal_align' => ['DP' => '.', 'DC' => ',', 'DM' => "\xc2\xb7", 'DA' => "\xd9\xab", 'DD' => '-'],
|
||||
|
||||
// IMAGES
|
||||
// if image-rendering=='auto', this defines value for image-rendering
|
||||
// if true, image interpolation shall be performed by a conforming reader
|
||||
'interpolateImages' => false,
|
||||
// Default dpi to output images if size not defined
|
||||
// See also above "dpi"
|
||||
'img_dpi' => 96,
|
||||
// Specify whitelisted PHP streams to be used for images
|
||||
// Useful to add custom streams like `s3`
|
||||
// Note: for security reasons the `phar` stream cannot be used @see https://github.com/mpdf/mpdf/issues/949
|
||||
'whitelistStreamWrappers' => ['http', 'https', 'file'],
|
||||
|
||||
// TEXT SPACING & JUSTIFICATION
|
||||
|
||||
// Specify whether kerning should be used when CSS font-kerning="auto" used for HTML,
|
||||
// Also whether kerning should be used in any direct writing e.g. $mpdf->Text(),
|
||||
'useKerning' => false,
|
||||
// In justified text, <BR> does not cause the preceding text to be justified in browsers
|
||||
// Change to true to force justification (as in MS Word)
|
||||
'justifyB4br' => false,
|
||||
|
||||
// Number of spaces to replace for a TAB in <pre> sections
|
||||
// Notepad uses 6, HTML specification recommends 8
|
||||
'tabSpaces' => 8,
|
||||
// Proportion (/1) of space (when justifying margins) to allocate to Word vs. Character
|
||||
'jSWord' => 0.4,
|
||||
// Maximum spacing to allocate to character spacing. (0' => no maximum)
|
||||
'jSmaxChar' => 2,
|
||||
|
||||
// Maximum character spacing allowed (carried over) when finishing a last line
|
||||
'jSmaxCharLast' => 1,
|
||||
// Maximum word spacing allowed (carried over) when finishing a last line
|
||||
'jSmaxWordLast' => 2,
|
||||
|
||||
// LINE SPACING & TEXT BASELINE
|
||||
// Use the fixed factor ('normalLineheight') when line-height:normal
|
||||
// Compatible with mPDF versions < 6
|
||||
'useFixedNormalLineHeight' => false,
|
||||
|
||||
// Use a fixed ratio ('baselineC') to set the text baseline
|
||||
// Compatible with mPDF versions < 6
|
||||
'useFixedTextBaseline' => false,
|
||||
|
||||
// Default Value used for line-height when CSS specified as 'normal' (default)
|
||||
'normalLineheight' => 1.33,
|
||||
|
||||
// Correction factor applied to lineheight values derived from 'win', 'mac', 'winTypo'
|
||||
'adjustFontDescLineheight' => 1.14,
|
||||
|
||||
// Small Caps
|
||||
// Factor of 1 to scale capital letters
|
||||
'smCapsScale' => 0.75,
|
||||
// % to stretch small caps horizontally (i.e. 100' => no stretch)
|
||||
'smCapsStretch' => 110,
|
||||
|
||||
// Line-breaking
|
||||
// The alternative to these next 2 is the use of U+200B Zero-width space
|
||||
// These are only effective if using OTL for the fonts
|
||||
// Use the dictionaries to determine line-breaking in Lao, Khmer and Thai
|
||||
'useDictionaryLBR' => true,
|
||||
// Use the inbuilt algorithm to determine line-breaking in Tibetan
|
||||
'useTibetanLBR' => true,
|
||||
|
||||
// CJK Line-breaking
|
||||
// FALSE=always wrap to next line, TRUE=squeeze or overflow
|
||||
'allowCJKorphans' => true,
|
||||
// FALSE=squeeze, TRUE=overflow (only some characters, and disabled in tables)
|
||||
'allowCJKoverflow' => false,
|
||||
// Forces overflowng punctuation to hang outside right margin mPDF 5.6.40
|
||||
'CJKforceend' => false,
|
||||
|
||||
// COLUMNS
|
||||
'keepColumns' => false, // Set to go to the second column only when the first is full of text etc.
|
||||
'max_colH_correction' => 1.15, // Maximum ratio to adjust column height when justifying - too large a value can give ugly results
|
||||
'ColGap' => 5,
|
||||
|
||||
// LISTS
|
||||
// mPDF 6
|
||||
// 'mpdf' or 'browser' - Specify whether to use mPDF custom method of automatic
|
||||
'list_auto_mode' => 'browser',
|
||||
// indentation of lists, or standard browser-compatible
|
||||
// custom mPDF method is ignored if list-style-position: inside, or image used for marker (or custom U+)
|
||||
// List Indentation when set to 'auto' if using standard browser-compatible method
|
||||
'list_indent_default' => '40px',
|
||||
// List Indentation when set to 'auto' if using mPDF custom method
|
||||
'list_indent_default_mpdf' => '0em',
|
||||
// 1/0 yes/no to indent first level of list, if using mPDF custom method
|
||||
'list_indent_first_level' => 0,
|
||||
|
||||
// Content to follow a numbered list marker e.g. '.' gives 1. or IV., ')' gives 1) or a)
|
||||
'list_number_suffix' => '.',
|
||||
|
||||
// To specify a bullet size and offset proportional to the list item's font size:
|
||||
// Browsers use a fixed bullet size and offset
|
||||
// Offset (CSS length) of list marker bullets (disc/circle/square)
|
||||
'list_marker_offset' => '5.5pt',
|
||||
// Size (CSS) of list marker bullets (disc/circle/square)
|
||||
'list_symbol_size' => '3.6pt',
|
||||
|
||||
// Hyphenation
|
||||
'SHYlanguages' => ['en', 'de', 'es', 'fi', 'fr', 'it', 'nl', 'pl', 'ru', 'sv'], // existing defined patterns
|
||||
'SHYlang' => "en", // 'en','de','es','fi','fr','it','nl','pl','ru','sv'
|
||||
'SHYleftmin' => 2,
|
||||
'SHYrightmin' => 2,
|
||||
'SHYcharmin' => 2,
|
||||
'SHYcharmax' => 10,
|
||||
|
||||
// ACTIVE FORMS
|
||||
'useActiveForms' => false,
|
||||
|
||||
// WATERMARKS
|
||||
'watermarkImgBehind' => false,
|
||||
'showWatermarkText' => 0,
|
||||
'showWatermarkImage' => 0,
|
||||
'watermarkText' => '',
|
||||
'watermarkAngle' => 45,
|
||||
'watermarkImage' => '',
|
||||
'watermark_font' => '',
|
||||
'watermarkTextAlpha' => 0.2,
|
||||
'watermarkImageAlpha' => 0.2,
|
||||
|
||||
// Accepts any PDF spec. value: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion
|
||||
// "Multiply" works well for watermark image on top
|
||||
'watermarkImgAlphaBlend' => 'Normal',
|
||||
|
||||
// BORDERS
|
||||
'autoPadding' => false, // Automatically increases padding in block elements when border-radius set - if required
|
||||
|
||||
// SVG
|
||||
|
||||
// If you wish to use Automatic Font selection within SVG's. change this definition to true.
|
||||
// This selects different fonts for different scripts used in text.
|
||||
// This can be enabled/disabled independently of the use of Automatic Font selection within mPDF generally.
|
||||
// Choice of font is determined by the LangToFont and ScriptToLang classes, the same as for mPDF generally.
|
||||
'svgAutoFont' => false,
|
||||
|
||||
// Enable a limited use of classes within SVG <text> elements by setting this to true.
|
||||
// This allows recognition of a "class" attribute on a <text> element.
|
||||
// The CSS style for that class should be outside the SVG, and cannot use any other selectors (i.e. only .class {} can be defined)
|
||||
// <style> definitions within the SVG code will be recognised if the SVG is included as an inline item within the HTML code passed to mPDF.
|
||||
// The style property should be pertinent to SVG e.g. use fill:red rather than color:red
|
||||
// Only the properties currently supported for SVG text can be specified:
|
||||
// fill, fill-opacity, stroke, stroke-opacity, stroke-linecap, stroke-linejoin, stroke-width, stroke-dasharray, stroke-dashoffset
|
||||
// font-family, font-size, font-weight, font-variant, font-style, opacity, text-anchor
|
||||
'svgClasses' => false,
|
||||
|
||||
// Default values if no style sheet offered (cf. http://www.w3.org/TR/CSS21/sample.html)
|
||||
'defaultCSS' => DefaultCss::$definition,
|
||||
'defaultCssFile' => __DIR__ . '/..//data/mpdf.css',
|
||||
|
||||
'customProperties' => [],
|
||||
|
||||
'languageToFont' => new LanguageToFont(),
|
||||
'scriptToLanguage' => new ScriptToLanguage(),
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// VALUES ONLY LIKELY TO BE CHANGED BY DEVELOPERS
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
'pdf_version' => '1.4',
|
||||
|
||||
'fontDir' => [
|
||||
__DIR__ . '/..//ttfonts'
|
||||
],
|
||||
|
||||
'tempDir' => __DIR__ . '/..//tmp',
|
||||
|
||||
'allowAnnotationFiles' => false,
|
||||
|
||||
'hyphenationDictionaryFile' => __DIR__ . '/..//data/patterns/dictionary.txt',
|
||||
|
||||
'default_lineheight_correction' => 1.2, // Value 1 sets lineheight=fontsize height,
|
||||
// Value used if line-height not set by CSS (usually is)
|
||||
|
||||
'fontsizes' => ['XX-SMALL' => 0.7, 'X-SMALL' => 0.77, 'SMALL' => 0.86, 'MEDIUM' => 1, 'LARGE' => 1.2, 'X-LARGE' => 1.5, 'XX-LARGE' => 2],
|
||||
|
||||
// CHARACTER PATTERN MATCHES TO DETECT LANGUAGES
|
||||
// pattern used to detect RTL characters -> force RTL
|
||||
'pregRTLchars' => "\x{0590}-\x{06FF}\x{0700}-\x{085F}\x{FB00}-\x{FDFD}\x{FE70}-\x{FEFF}", // 085F to include Mandaic
|
||||
// Chars which distinguish CJK but not between different
|
||||
'pregCJKchars' => "\x{1100}-\x{11FF}\x{2E80}-\x{A4CF}\x{A800}-\x{D7AF}\x{F900}-\x{FAFF}\x{FE30}-\x{FE6F}\x{FF00}-\x{FFEF}\x{20000}-\x{2FA1F}",
|
||||
|
||||
/**
|
||||
* References for CJK line-breaking
|
||||
*
|
||||
* http://en.wikipedia.org/wiki/Line_breaking_rules_in_East_Asian_languages
|
||||
* http://msdn.microsoft.com/en-us/goglobal/bb688158.aspx - listed using charsets
|
||||
* Word wrapping in other langauges - http://msdn.microsoft.com/en-us/goglobal/bb688158.aspx
|
||||
* Word wrapping in Japanese/Korean - http://en.wikipedia.org/wiki/Kinsoku_shori
|
||||
* Unicode character types: http://unicode.org/reports/tr14/
|
||||
* http://xml.ascc.net/en/utf-8/faq/zhl10n-faq-xsl.html#qb1
|
||||
* ECMA-376 4th edition Part 1
|
||||
* http://www.ecma-international.org/publications/standards/Ecma-376.htm
|
||||
*/
|
||||
|
||||
// Leading characters - Not allowed at end of line
|
||||
'CJKleading' => "\$\(\*\[\{\x{00a3}\x{00a5}\x{00ab}\x{00b7}\x{2018}\x{201c}\x{2035}\x{3005}\x{3007}\x{3008}\x{300a}\x{300c}\x{300e}\x{3010}\x{3014}\x{3016}\x{3018}\x{301d}\x{fe34}\x{fe35}\x{fe37}\x{fe39}\x{fe3b}\x{fe3d}\x{fe3f}\x{fe41}\x{fe43}\x{fe57}\x{fe59}\x{fe5b}\x{fe5d}\x{ff04}\x{ff08}\x{ff0e}\x{ff3b}\x{ff5b}\x{ff5f}\x{ff62}\x{ffe1}\x{ffe5}\x{ffe6}",
|
||||
|
||||
// Following characters - Not allowed at start
|
||||
'CJKfollowing' => "!%\),\.:,>\?\]\}\x{00a2}\x{00a8}\x{00b0}\x{00b7}\x{00bb}\x{02c7}\x{02c9}\x{2010}\x{2013}-\x{2016}\x{2019}\x{201d}-\x{201f}\x{2020}-\x{2022}\x{2025}-\x{2027}\x{2030}\x{2032}\x{2033}\x{203a}\x{203c}\x{2047}-\x{2049}\x{2103}\x{2236}\x{2574}\x{3001}-\x{3003}\x{3005}\x{3006}\x{3009}\x{300b}\x{300d}\x{300f}\x{3011}\x{3015}\x{3017}\x{3019}\x{301c}\x{301e}\x{301f}\x{303b}\x{3041}\x{3043}\x{3045}\x{3047}\x{3049}\x{3063}\x{3083}\x{3085}\x{3087}\x{308e}\x{3095}\x{3096}\x{309b}-\x{309e}\x{30a0}\x{30a1}\x{30a3}\x{30a5}\x{30a7}\x{30a9}\x{30c3}\x{30e3}\x{30e5}\x{30e7}\x{30ee}\x{30f5}\x{30f6}\x{30fb}-\x{30fd}\x{30fe}\x{31f0}-\x{31ff}\x{fe30}\x{fe31}-\x{fe34}\x{fe36}\x{fe38}\x{fe3a}\x{fe3c}\x{fe3e}\x{fe40}\x{fe42}\x{fe44}\x{fe4f}\x{fe50}-\x{fe58}\x{fe5a}\x{fe5c}-\x{fe5e}\x{ff01}\x{ff02}\x{ff05}\x{ff07}\x{ff09}\x{ff0c}\x{ff0e}\x{ff1a}\x{ff1b}\x{ff1f}\x{ff3d}\x{ff40}\x{ff5c}-\x{ff5e}\x{ff60}\x{ff61}\x{ff63}-\x{ff65}\x{ff9e}\x{ff9f}\x{ffe0}",
|
||||
|
||||
// Characters which are allowed to overflow the right margin (from CSS3 http://www.w3.org/TR/2012/WD-css3-text-20120814/#hanging-punctuation)
|
||||
'CJKoverflow' => "\.,\x{ff61}\x{ff64}\x{3001}\x{3002}\x{fe50}-\x{fe52}\x{ff0c}\x{ff0e}",
|
||||
|
||||
// Used for preventing letter-spacing in cursive scripts
|
||||
// NB The following scripts in Unicode 6 are considered to be cursive scripts,
|
||||
// and do not allow expansion opportunities between their letters:
|
||||
// Arabic, Syriac, Mandaic, Mongolian, N'Ko, Phags Pa
|
||||
'pregCURSchars' => "\x{0590}-\x{083E}\x{0900}-\x{0DFF}\x{FB00}-\x{FDFD}\x{FE70}-\x{FEFF}",
|
||||
|
||||
'allowedCSStags' => 'DIV|P|H1|H2|H3|H4|H5|H6|FORM|IMG|A|BODY|TABLE|HR|THEAD|TFOOT|TBODY|TH|TR|TD|UL|OL|LI|PRE|BLOCKQUOTE|ADDRESS|DL|DT|DD'
|
||||
. '|ARTICLE|ASIDE|FIGURE|FIGCAPTION|FOOTER|HEADER|HGROUP|NAV|SECTION|MAIN|MARK|DETAILS|SUMMARY|METER|PROGRESS|TIME'
|
||||
. '|SPAN|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|STRIKE|S|U|DEL|INS|Q|FONT'
|
||||
. '|SELECT|INPUT|TEXTAREA|CAPTION|FIELDSET|LEGEND'
|
||||
. '|TEXTCIRCLE|DOTTAB|BDO|BDI',
|
||||
|
||||
'outerblocktags' => ['DIV', 'FORM', 'CENTER', 'DL', 'FIELDSET', 'ARTICLE', 'ASIDE', 'FIGURE', 'FIGCAPTION', 'FOOTER', 'HEADER', 'HGROUP', 'MAIN', 'NAV', 'SECTION', 'DETAILS', 'SUMMARY', 'UL', 'OL', 'LI'],
|
||||
'innerblocktags' => ['P', 'BLOCKQUOTE', 'ADDRESS', 'PRE', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'DT', 'DD', 'CAPTION'],
|
||||
|
||||
// cURL options
|
||||
'curlFollowLocation' => false,
|
||||
'curlAllowUnsafeSslRequests' => false,
|
||||
'curlCaCertificate' => '',
|
||||
'curlTimeout' => 5,
|
||||
'curlProxy' => null,
|
||||
'curlProxyAuth' => null,
|
||||
'curlUserAgent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:13.0) Gecko/20100101 Firefox/13.0.1',
|
||||
|
||||
'exposeVersion' => true,
|
||||
];
|
||||
}
|
||||
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->defaults;
|
||||
}
|
||||
}
|
||||
332
Mpdf/Config/FontVariables.php
Normal file
332
Mpdf/Config/FontVariables.php
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Config;
|
||||
|
||||
class FontVariables
|
||||
{
|
||||
|
||||
private $defaults;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->defaults = [
|
||||
|
||||
// Specify which font metrics to use:
|
||||
// - 'winTypo uses sTypoAscender etc from the OS/2 table and is the one usually recommended - BUT
|
||||
// - 'win' use WinAscent etc from OS/2 and inpractice seems to be used more commonly in Windows environment
|
||||
// - 'mac' uses Ascender etc from hhea table, and is used on Mac/OSX environment
|
||||
'fontDescriptor' => 'win',
|
||||
|
||||
// For custom fonts data folder set config key 'fontDir'. It can also be an array of directories,
|
||||
// first found file will then be returned
|
||||
|
||||
// Optionally set font(s) (names as defined below in 'fontdata') to use for missing characters
|
||||
// when using useSubstitutions. Use a font with wide coverage - dejavusanscondensed is a good start
|
||||
// only works using subsets (otherwise would add very large file)
|
||||
// More than 1 font can be specified but each will add to the processing time of the script
|
||||
|
||||
'backupSubsFont' => ['dejavusanscondensed', 'freesans', 'sun-exta'],
|
||||
|
||||
// Optionally set a font (name as defined below in 'fontdata') to use for CJK characters
|
||||
// in Plane 2 Unicode (> U+20000) when using useSubstitutions.
|
||||
// Use a font like hannomb or sun-extb if available
|
||||
// only works using subsets (otherwise would add very large file)
|
||||
|
||||
'backupSIPFont' => 'sun-extb',
|
||||
|
||||
/*
|
||||
This array defines translations from font-family in CSS or HTML
|
||||
to the internal font-family name used in mPDF.
|
||||
Can include as many as want, regardless of which fonts are installed.
|
||||
By default mPDF will take a CSS/HTML font-family and remove spaces
|
||||
and change to lowercase e.g. "Times New Roman" will be recognised as
|
||||
"timesnewroman"
|
||||
You only need to define additional translations.
|
||||
You can also use it to define specific substitutions e.g.
|
||||
'helvetica' => 'arial'
|
||||
Generic substitutions (i.e. to a sans-serif or serif font) are set
|
||||
by including the font-family in e.g. 'sans_fonts' below
|
||||
*/
|
||||
'fonttrans' => [
|
||||
'times' => 'timesnewroman',
|
||||
'courier' => 'couriernew',
|
||||
'trebuchet' => 'trebuchetms',
|
||||
'comic' => 'comicsansms',
|
||||
'franklin' => 'franklingothicbook',
|
||||
'ocr-b' => 'ocrb',
|
||||
'ocr-b10bt' => 'ocrb',
|
||||
'damase' => 'mph2bdamase',
|
||||
],
|
||||
|
||||
/*
|
||||
This array lists the file names of the TrueType .ttf or .otf font files
|
||||
for each variant of the (internal mPDF) font-family name.
|
||||
['R'] = Regular (Normal), others are Bold, Italic, and Bold-Italic
|
||||
Each entry must contain an ['R'] entry, but others are optional.
|
||||
Only the font (files) entered here will be available to use in mPDF.
|
||||
Put preferred default first in order
|
||||
This will be used if a named font cannot be found in any of
|
||||
'sans_fonts', 'serif_fonts' or 'mono_fonts'
|
||||
|
||||
['sip-ext'] = 'sun-extb', name a related font file containing SIP characters
|
||||
['useOTL'] => 0xFF, Enable use of OTL features.
|
||||
['useKashida'] => 75, Enable use of kashida for text justification in Arabic text
|
||||
|
||||
If a .ttc TrueType collection file is referenced, the number of the font
|
||||
within the collection is required. Fonts in the collection are numbered
|
||||
starting at 1, as they appear in the .ttc file e.g.
|
||||
"cambria" => array(
|
||||
'R' => "cambria.ttc",
|
||||
'B' => "cambriab.ttf",
|
||||
'I' => "cambriai.ttf",
|
||||
'BI' => "cambriaz.ttf",
|
||||
'TTCfontID' => array(
|
||||
'R' => 1,
|
||||
),
|
||||
),
|
||||
"cambriamath" => array(
|
||||
'R' => "cambria.ttc",
|
||||
'TTCfontID' => array(
|
||||
'R' => 2,
|
||||
),
|
||||
),
|
||||
*/
|
||||
|
||||
'fontdata' => [
|
||||
"dejavusanscondensed" => [
|
||||
'R' => "DejaVuSansCondensed.ttf",
|
||||
'B' => "DejaVuSansCondensed-Bold.ttf",
|
||||
'I' => "DejaVuSansCondensed-Oblique.ttf",
|
||||
'BI' => "DejaVuSansCondensed-BoldOblique.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
"dejavusans" => [
|
||||
'R' => "DejaVuSans.ttf",
|
||||
'B' => "DejaVuSans-Bold.ttf",
|
||||
'I' => "DejaVuSans-Oblique.ttf",
|
||||
'BI' => "DejaVuSans-BoldOblique.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
"dejavuserif" => [
|
||||
'R' => "DejaVuSerif.ttf",
|
||||
'B' => "DejaVuSerif-Bold.ttf",
|
||||
'I' => "DejaVuSerif-Italic.ttf",
|
||||
'BI' => "DejaVuSerif-BoldItalic.ttf",
|
||||
],
|
||||
"dejavuserifcondensed" => [
|
||||
'R' => "DejaVuSerifCondensed.ttf",
|
||||
'B' => "DejaVuSerifCondensed-Bold.ttf",
|
||||
'I' => "DejaVuSerifCondensed-Italic.ttf",
|
||||
'BI' => "DejaVuSerifCondensed-BoldItalic.ttf",
|
||||
],
|
||||
"dejavusansmono" => [
|
||||
'R' => "DejaVuSansMono.ttf",
|
||||
'B' => "DejaVuSansMono-Bold.ttf",
|
||||
'I' => "DejaVuSansMono-Oblique.ttf",
|
||||
'BI' => "DejaVuSansMono-BoldOblique.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
"freesans" => [
|
||||
'R' => "FreeSans.ttf",
|
||||
'B' => "FreeSansBold.ttf",
|
||||
'I' => "FreeSansOblique.ttf",
|
||||
'BI' => "FreeSansBoldOblique.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"freeserif" => [
|
||||
'R' => "FreeSerif.ttf",
|
||||
'B' => "FreeSerifBold.ttf",
|
||||
'I' => "FreeSerifItalic.ttf",
|
||||
'BI' => "FreeSerifBoldItalic.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
"freemono" => [
|
||||
'R' => "FreeMono.ttf",
|
||||
'B' => "FreeMonoBold.ttf",
|
||||
'I' => "FreeMonoOblique.ttf",
|
||||
'BI' => "FreeMonoBoldOblique.ttf",
|
||||
],
|
||||
/* OCR-B font for Barcodes */
|
||||
"ocrb" => [
|
||||
'R' => "ocrb10.ttf",
|
||||
],
|
||||
/* Miscellaneous language font(s) */
|
||||
"estrangeloedessa" => [/* Syriac */
|
||||
'R' => "SyrCOMEdessa.otf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"kaputaunicode" => [/* Sinhala */
|
||||
'R' => "kaputaunicode.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"abyssinicasil" => [/* Ethiopic */
|
||||
'R' => "Abyssinica_SIL.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"aboriginalsans" => [/* Cherokee and Canadian */
|
||||
'R' => "AboriginalSansREGULAR.ttf",
|
||||
],
|
||||
"jomolhari" => [/* Tibetan */
|
||||
'R' => "Jomolhari.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"sundaneseunicode" => [/* Sundanese */
|
||||
'R' => "SundaneseUnicode-1.0.5.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"taiheritagepro" => [/* Tai Viet */
|
||||
'R' => "TaiHeritagePro.ttf",
|
||||
],
|
||||
"aegean" => [
|
||||
'R' => "Aegean.otf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"aegyptus" => [
|
||||
'R' => "Aegyptus.otf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"akkadian" => [/* Cuneiform */
|
||||
'R' => "Akkadian.otf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"quivira" => [
|
||||
'R' => "Quivira.otf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"eeyekunicode" => [/* Meetei Mayek */
|
||||
'R' => "Eeyek.ttf",
|
||||
],
|
||||
"lannaalif" => [/* Tai Tham */
|
||||
'R' => "lannaalif-v1-03.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"daibannasilbook" => [/* New Tai Lue */
|
||||
'R' => "DBSILBR.ttf",
|
||||
],
|
||||
"garuda" => [/* Thai */
|
||||
'R' => "Garuda.ttf",
|
||||
'B' => "Garuda-Bold.ttf",
|
||||
'I' => "Garuda-Oblique.ttf",
|
||||
'BI' => "Garuda-BoldOblique.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"khmeros" => [/* Khmer */
|
||||
'R' => "KhmerOS.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"dhyana" => [/* Lao fonts */
|
||||
'R' => "Dhyana-Regular.ttf",
|
||||
'B' => "Dhyana-Bold.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"tharlon" => [/* Myanmar / Burmese */
|
||||
'R' => "Tharlon-Regular.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"padaukbook" => [/* Myanmar / Burmese */
|
||||
'R' => "Padauk-book.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"zawgyi-one" => [/* Myanmar / Burmese */
|
||||
'R' => "ZawgyiOne.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"ayar" => [/* Myanmar / Burmese */
|
||||
'R' => "ayar.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"taameydavidclm" => [/* Hebrew with full Niqud and Cantillation */
|
||||
'R' => "TaameyDavidCLM-Medium.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
/* SMP */
|
||||
"mph2bdamase" => [
|
||||
'R' => "damase_v.2.ttf",
|
||||
],
|
||||
/* Indic */
|
||||
"lohitkannada" => [
|
||||
'R' => "Lohit-Kannada.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
"pothana2000" => [
|
||||
'R' => "Pothana2000.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
],
|
||||
/* Arabic fonts */
|
||||
"xbriyaz" => [
|
||||
'R' => "XB Riyaz.ttf",
|
||||
'B' => "XB RiyazBd.ttf",
|
||||
'I' => "XB RiyazIt.ttf",
|
||||
'BI' => "XB RiyazBdIt.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
"lateef" => [/* Sindhi, Pashto and Urdu */
|
||||
'R' => "LateefRegOT.ttf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
"kfgqpcuthmantahanaskh" => [/* KFGQPC Uthman Taha Naskh - Koranic */
|
||||
'R' => "Uthman.otf",
|
||||
'useOTL' => 0xFF,
|
||||
'useKashida' => 75,
|
||||
],
|
||||
/* CJK fonts */
|
||||
"sun-exta" => [
|
||||
'R' => "Sun-ExtA.ttf",
|
||||
'sip-ext' => 'sun-extb', /* SIP=Plane2 Unicode (extension B) */
|
||||
],
|
||||
"sun-extb" => [
|
||||
'R' => "Sun-ExtB.ttf",
|
||||
],
|
||||
"unbatang" => [/* Korean */
|
||||
'R' => "UnBatang_0613.ttf",
|
||||
],
|
||||
],
|
||||
|
||||
// Add fonts to this array if they contain characters in the SIP or SMP Unicode planes
|
||||
// but you do not require them. This allows a more efficient form of subsetting to be used.
|
||||
'BMPonly' => [
|
||||
"dejavusanscondensed",
|
||||
"dejavusans",
|
||||
"dejavuserifcondensed",
|
||||
"dejavuserif",
|
||||
"dejavusansmono",
|
||||
],
|
||||
|
||||
// These next 3 arrays do two things:
|
||||
// 1. If a font referred to in HTML/CSS is not available to mPDF, these arrays will determine whether
|
||||
// a serif/sans-serif or monospace font is substituted
|
||||
// 2. The first font in each array will be the font which is substituted in circumstances as above
|
||||
// (Otherwise the order is irrelevant)
|
||||
// Use the mPDF font-family names i.e. lowercase and no spaces (after any translations in $fonttrans)
|
||||
// Always include "sans-serif", "serif" and "monospace" etc.
|
||||
'sans_fonts' => ['dejavusanscondensed', 'sans', 'sans-serif', 'cursive', 'fantasy', 'dejavusans', 'freesans', 'liberationsans',
|
||||
'arial', 'helvetica', 'verdana', 'geneva', 'lucida', 'arialnarrow', 'arialblack',
|
||||
'franklin', 'franklingothicbook', 'tahoma', 'garuda', 'calibri', 'trebuchet', 'lucidagrande', 'microsoftsansserif',
|
||||
'trebuchetms', 'lucidasansunicode', 'franklingothicmedium', 'albertusmedium', 'xbriyaz', 'albasuper', 'quillscript',
|
||||
'humanist777', 'humanist777black', 'humanist777light', 'futura', 'hobo', 'segoeprint'
|
||||
],
|
||||
|
||||
'serif_fonts' => ['dejavuserifcondensed', 'serif', 'dejavuserif', 'freeserif', 'liberationserif',
|
||||
'timesnewroman', 'times', 'centuryschoolbookl', 'palatinolinotype', 'centurygothic',
|
||||
'bookmanoldstyle', 'bookantiqua', 'cyberbit', 'cambria',
|
||||
'norasi', 'charis', 'palatino', 'constantia', 'georgia', 'albertus', 'xbzar', 'algerian', 'garamond',
|
||||
],
|
||||
|
||||
'mono_fonts' => ['dejavusansmono', 'mono', 'monospace', 'freemono', 'liberationmono', 'courier', 'ocrb', 'ocr-b', 'lucidaconsole',
|
||||
'couriernew', 'monotypecorsiva'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
}
|
||||
48
Mpdf/Conversion/DecToAlpha.php
Normal file
48
Mpdf/Conversion/DecToAlpha.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Conversion;
|
||||
|
||||
class DecToAlpha
|
||||
{
|
||||
|
||||
public function convert($valor, $toUpper = true)
|
||||
{
|
||||
// returns a string from A-Z to AA-ZZ to AAA-ZZZ
|
||||
// OBS: A = 65 ASCII TABLE VALUE
|
||||
if (($valor < 1) || ($valor > 18278)) {
|
||||
return '?'; //supports 'only' up to 18278
|
||||
}
|
||||
|
||||
$c2 = $c3 = '';
|
||||
|
||||
$c1 = 64 + $valor; // 1 letter (up to 26)
|
||||
if ($valor > 702) { // 3 letters (up to 18278)
|
||||
$c1 = 65 + floor(($valor - 703) / 676);
|
||||
$c2 = 65 + floor((($valor - 703) % 676) / 26);
|
||||
$c3 = 65 + floor((($valor - 703) % 676) % 26);
|
||||
} elseif ($valor > 26) { // 2 letters (up to 702)
|
||||
$c1 = (64 + (int) (($valor - 1) / 26));
|
||||
$c2 = (64 + ($valor % 26));
|
||||
if ($c2 === 64) {
|
||||
$c2 += 26;
|
||||
}
|
||||
}
|
||||
|
||||
$alpha = chr($c1);
|
||||
|
||||
if ($c2 !== '') {
|
||||
$alpha .= chr($c2);
|
||||
}
|
||||
|
||||
if ($c3 !== '') {
|
||||
$alpha .= chr($c3);
|
||||
}
|
||||
|
||||
if (!$toUpper) {
|
||||
$alpha = strtolower($alpha);
|
||||
}
|
||||
|
||||
return $alpha;
|
||||
}
|
||||
|
||||
}
|
||||
22
Mpdf/Conversion/DecToCjk.php
Normal file
22
Mpdf/Conversion/DecToCjk.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Conversion;
|
||||
|
||||
use Mpdf\Utils\UtfString;
|
||||
|
||||
class DecToCjk
|
||||
{
|
||||
|
||||
public function convert($num)
|
||||
{
|
||||
$nstr = (string) $num;
|
||||
$rnum = '';
|
||||
$glyphs = [0x3007, 0x4E00, 0x4E8C, 0x4E09, 0x56DB, 0x4E94, 0x516D, 0x4E03, 0x516B, 0x4E5D];
|
||||
$len = strlen($nstr);
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$rnum .= UtfString::code2utf($glyphs[(int) $nstr[$i]]);
|
||||
}
|
||||
return $rnum;
|
||||
}
|
||||
|
||||
}
|
||||
68
Mpdf/Conversion/DecToHebrew.php
Normal file
68
Mpdf/Conversion/DecToHebrew.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Conversion;
|
||||
|
||||
use Mpdf\Utils\UtfString;
|
||||
|
||||
class DecToHebrew
|
||||
{
|
||||
|
||||
public function convert($in, $reverse = false)
|
||||
{
|
||||
// reverse is used when called from Lists, as these do not pass through bidi-algorithm
|
||||
$i = (int) $in; // I initially be the counter value
|
||||
$s = ''; // S initially be the empty string
|
||||
|
||||
// and glyph list initially be the list of additive tuples.
|
||||
$additive_nums = [400, 300, 200, 100, 90, 80, 70, 60, 50, 40, 30, 20, 19, 18, 17, 16, 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
|
||||
$additive_glyphs = [0x05EA, 0x05E9, 0x05E8, 0x05E7, 0x05E6, 0x05E4, 0x05E2, 0x05E1, 0x05E0, 0x05DE, 0x05DC, 0x05DB,
|
||||
[0x05D9, 0x05D8], [0x05D9, 0x05D7], [0x05D9, 0x05D6], [0x05D8, 0x05D6], [0x05D8, 0x05D5], 0x05D9,
|
||||
0x05D8, 0x05D7, 0x05D6, 0x05D5, 0x05D4, 0x05D3, 0x05D2, 0x05D1, 0x05D0];
|
||||
|
||||
// NB This system manually specifies the values for 19-15 to force the correct display of 15 and 16, which are commonly
|
||||
// rewritten to avoid a close resemblance to the Tetragrammaton.
|
||||
// This function only works up to 1,000
|
||||
if ($i > 999) {
|
||||
return $in;
|
||||
}
|
||||
|
||||
// return as initial numeric string
|
||||
// If I is initially 0, and there is an additive tuple with a weight of 0, append that tuple's counter glyph to S and return S.
|
||||
if ($i === 0) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
// Otherwise, while I is greater than 0 and there are elements left in the glyph list:
|
||||
$additiveNumsCount = count($additive_nums);
|
||||
for ($t = 0; $t < $additiveNumsCount; $t++) {
|
||||
// Pop the first additive tuple from the glyph list. This is the current tuple.
|
||||
$ct = $additive_nums[$t];
|
||||
// Append the current tuple's counter glyph to S x floor( I / current tuple's weight ) times (this may be 0).
|
||||
$n = floor($i / $ct);
|
||||
for ($j = 0; $j < $n; $j++) {
|
||||
if (is_array($additive_glyphs[$t])) {
|
||||
foreach ($additive_glyphs[$t] as $ag) {
|
||||
if ($reverse) {
|
||||
$s = UtfString::code2utf($ag) . $s;
|
||||
} else {
|
||||
$s .= UtfString::code2utf($ag);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($reverse) {
|
||||
$s = UtfString::code2utf($additive_glyphs[$t]) . $s;
|
||||
} else {
|
||||
$s .= UtfString::code2utf($additive_glyphs[$t]);
|
||||
}
|
||||
}
|
||||
$i -= ($ct * $n);
|
||||
}
|
||||
if ($i === .0 || $i === 0) {
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
|
||||
return $in; // return as initial string
|
||||
}
|
||||
|
||||
}
|
||||
69
Mpdf/Conversion/DecToOther.php
Normal file
69
Mpdf/Conversion/DecToOther.php
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Conversion;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
use Mpdf\Utils\UtfString;
|
||||
|
||||
class DecToOther
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
public function __construct(Mpdf $mpdf)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
}
|
||||
|
||||
public function convert($num, $cp, $check = true)
|
||||
{
|
||||
// From printlistbuffer: font is set, so check if character is available
|
||||
// From docPageNum: font is not set, so no check
|
||||
$nstr = (string) $num;
|
||||
$rnum = '';
|
||||
$len = strlen($nstr);
|
||||
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
if (!$check || $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], $cp + ((int) $nstr[$i]))) {
|
||||
$rnum .= UtfString::code2utf($cp + (int) $nstr[$i]);
|
||||
} else {
|
||||
$rnum .= $nstr[$i];
|
||||
}
|
||||
}
|
||||
|
||||
return $rnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $script
|
||||
* @return int
|
||||
*/
|
||||
public function getCodePage($script)
|
||||
{
|
||||
$codePages = [
|
||||
'arabic-indic' => 0x0660,
|
||||
'persian' => 0x06F0,
|
||||
'urdu' => 0x06F0,
|
||||
'bengali' => 0x09E6,
|
||||
'devanagari' => 0x0966,
|
||||
'gujarati' => 0x0AE6,
|
||||
'gurmukhi' => 0x0A66,
|
||||
'kannada' => 0x0CE6,
|
||||
'malayalam' => 0x0D66,
|
||||
'oriya' => 0x0B66,
|
||||
'telugu' => 0x0C66,
|
||||
'tamil' => 0x0BE6,
|
||||
'thai' => 0x0E50,
|
||||
'khmer' => 0x17E0,
|
||||
'cambodian' => 0x17E0,
|
||||
'lao' => 0x0ED0,
|
||||
'myanmar' => 0x1040
|
||||
];
|
||||
|
||||
return isset($codePages[$script]) ? $codePages[$script] : 0;
|
||||
}
|
||||
|
||||
}
|
||||
136
Mpdf/Conversion/DecToRoman.php
Normal file
136
Mpdf/Conversion/DecToRoman.php
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Conversion;
|
||||
|
||||
/**
|
||||
* @link https://github.com/JeroenDeDauw/RomanNumbers
|
||||
* @license GNU GPL v2+
|
||||
*/
|
||||
class DecToRoman
|
||||
{
|
||||
|
||||
private $symbolMap;
|
||||
|
||||
public function __construct(array $symbolMap = [])
|
||||
{
|
||||
if ($symbolMap !== []) {
|
||||
$this->symbolMap = $symbolMap;
|
||||
} else {
|
||||
$this->symbolMap = [['I', 'V'], ['X', 'L'], ['C', 'D'], ['M']];
|
||||
}
|
||||
}
|
||||
|
||||
public function convert($number, $toUpper = true)
|
||||
{
|
||||
$this->ensureNumberIsAnInteger($number);
|
||||
$this->ensureNumberIsWithinBounds($number);
|
||||
|
||||
return $this->constructRomanString($number, $toUpper);
|
||||
}
|
||||
|
||||
private function ensureNumberIsAnInteger($number)
|
||||
{
|
||||
if (!is_int($number)) {
|
||||
throw new \InvalidArgumentException('Can only translate integers to roman');
|
||||
}
|
||||
}
|
||||
|
||||
private function ensureNumberIsWithinBounds($number)
|
||||
{
|
||||
if ($number < 1) {
|
||||
throw new \OutOfRangeException('Numbers under one cannot be translated to roman');
|
||||
}
|
||||
|
||||
if ($number > $this->getUpperBound()) {
|
||||
throw new \OutOfBoundsException('The provided number is to big to be fully translated to roman');
|
||||
}
|
||||
}
|
||||
|
||||
public function getUpperBound()
|
||||
{
|
||||
$symbolGroupCount = count($this->symbolMap);
|
||||
$valueOfOne = 10 ** ($symbolGroupCount - 1);
|
||||
|
||||
$hasFiveSymbol = array_key_exists(1, $this->symbolMap[$symbolGroupCount - 1]);
|
||||
|
||||
return $valueOfOne * ($hasFiveSymbol ? 9 : 4) - 1;
|
||||
}
|
||||
|
||||
private function constructRomanString($number, $toUpper)
|
||||
{
|
||||
$romanNumber = '';
|
||||
|
||||
$symbolMapCount = count($this->symbolMap);
|
||||
for ($i = 0; $i < $symbolMapCount; $i++) {
|
||||
$divisor = 10 ** ($i + 1);
|
||||
$remainder = $number % $divisor;
|
||||
$digit = $remainder / (10 ** $i);
|
||||
|
||||
$number -= $remainder;
|
||||
$romanNumber = $this->formatDigit($digit, $i) . $romanNumber;
|
||||
|
||||
if ($number === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$toUpper) {
|
||||
$romanNumber = strtolower($romanNumber);
|
||||
}
|
||||
|
||||
return $romanNumber;
|
||||
}
|
||||
|
||||
private function formatDigit($digit, $orderOfMagnitude)
|
||||
{
|
||||
if ($digit === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($digit === 4 || $digit === 9) {
|
||||
return $this->formatFourOrNine($digit, $orderOfMagnitude);
|
||||
}
|
||||
|
||||
$romanNumber = '';
|
||||
|
||||
if ($digit >= 5) {
|
||||
$digit -= 5;
|
||||
$romanNumber .= $this->getFiveSymbol($orderOfMagnitude);
|
||||
}
|
||||
|
||||
$romanNumber .= $this->formatOneToThree($orderOfMagnitude, $digit);
|
||||
|
||||
return $romanNumber;
|
||||
}
|
||||
|
||||
private function formatFourOrNine($digit, $orderOfMagnitude)
|
||||
{
|
||||
$firstSymbol = $this->getOneSymbol($orderOfMagnitude);
|
||||
$secondSymbol = $digit === 4
|
||||
? $this->getFiveSymbol($orderOfMagnitude)
|
||||
: $this->getTenSymbol($orderOfMagnitude);
|
||||
|
||||
return $firstSymbol . $secondSymbol;
|
||||
}
|
||||
|
||||
private function formatOneToThree($orderOfMagnitude, $digit)
|
||||
{
|
||||
return str_repeat($this->getOneSymbol($orderOfMagnitude), $digit);
|
||||
}
|
||||
|
||||
private function getOneSymbol($orderOfMagnitude)
|
||||
{
|
||||
return $this->symbolMap[$orderOfMagnitude][0];
|
||||
}
|
||||
|
||||
private function getFiveSymbol($orderOfMagnitude)
|
||||
{
|
||||
return $this->symbolMap[$orderOfMagnitude][1];
|
||||
}
|
||||
|
||||
private function getTenSymbol($orderOfMagnitude)
|
||||
{
|
||||
return $this->symbolMap[$orderOfMagnitude + 1][0];
|
||||
}
|
||||
|
||||
}
|
||||
13
Mpdf/Css/Border.php
Normal file
13
Mpdf/Css/Border.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
class Border
|
||||
{
|
||||
|
||||
const ALL = 15;
|
||||
const TOP = 8;
|
||||
const RIGHT = 4;
|
||||
const BOTTOM = 2;
|
||||
const LEFT = 1;
|
||||
}
|
||||
217
Mpdf/Css/DefaultCss.php
Normal file
217
Mpdf/Css/DefaultCss.php
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
class DefaultCss
|
||||
{
|
||||
|
||||
public static $definition = [
|
||||
'BODY' => [
|
||||
'FONT-FAMILY' => 'serif',
|
||||
'FONT-SIZE' => '11pt',
|
||||
'TEXT-INDENT' => '0pt',
|
||||
'LINE-HEIGHT' => 'normal',
|
||||
'MARGIN-COLLAPSE' => 'collapse', // Custom property to collapse top/bottom margins at top/bottom of page - ignored in tables/lists
|
||||
'HYPHENS' => 'manual',
|
||||
'FONT-KERNING' => 'auto',
|
||||
],
|
||||
'P' => [
|
||||
'MARGIN' => '1.12em 0',
|
||||
],
|
||||
'H1' => [
|
||||
'FONT-SIZE' => '2em',
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'MARGIN' => '0.67em 0',
|
||||
'PAGE-BREAK-AFTER' => 'avoid',
|
||||
],
|
||||
'H2' => [
|
||||
'FONT-SIZE' => '1.5em',
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'MARGIN' => '0.75em 0',
|
||||
'PAGE-BREAK-AFTER' => 'avoid',
|
||||
],
|
||||
'H3' => [
|
||||
'FONT-SIZE' => '1.17em',
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'MARGIN' => '0.83em 0',
|
||||
'PAGE-BREAK-AFTER' => 'avoid',
|
||||
],
|
||||
'H4' => [
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'MARGIN' => '1.12em 0',
|
||||
'PAGE-BREAK-AFTER' => 'avoid',
|
||||
],
|
||||
'H5' => [
|
||||
'FONT-SIZE' => '0.83em',
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'MARGIN' => '1.5em 0',
|
||||
'PAGE-BREAK-AFTER' => 'avoid',
|
||||
],
|
||||
'H6' => [
|
||||
'FONT-SIZE' => '0.75em',
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'MARGIN' => '1.67em 0',
|
||||
'PAGE-BREAK-AFTER' => 'avoid',
|
||||
],
|
||||
'HR' => [
|
||||
'COLOR' => '#888888',
|
||||
'TEXT-ALIGN' => 'center',
|
||||
'WIDTH' => '100%',
|
||||
'HEIGHT' => '0.2mm',
|
||||
'MARGIN-TOP' => '0.83em',
|
||||
'MARGIN-BOTTOM' => '0.83em',
|
||||
],
|
||||
'PRE' => [
|
||||
'MARGIN' => '0.83em 0',
|
||||
'FONT-FAMILY' => 'monospace',
|
||||
],
|
||||
'S' => [
|
||||
'TEXT-DECORATION' => 'line-through',
|
||||
],
|
||||
'STRIKE' => [
|
||||
'TEXT-DECORATION' => 'line-through',
|
||||
],
|
||||
'DEL' => [
|
||||
'TEXT-DECORATION' => 'line-through',
|
||||
],
|
||||
'SUB' => [
|
||||
'VERTICAL-ALIGN' => 'sub',
|
||||
'FONT-SIZE' => '55%', /* Recommended 0.83em */
|
||||
],
|
||||
'SUP' => [
|
||||
'VERTICAL-ALIGN' => 'super',
|
||||
'FONT-SIZE' => '55%', /* Recommended 0.83em */
|
||||
],
|
||||
'U' => [
|
||||
'TEXT-DECORATION' => 'underline',
|
||||
],
|
||||
'INS' => [
|
||||
'TEXT-DECORATION' => 'underline',
|
||||
],
|
||||
'B' => [
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
],
|
||||
'STRONG' => [
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
],
|
||||
'I' => [
|
||||
'FONT-STYLE' => 'italic',
|
||||
],
|
||||
'CITE' => [
|
||||
'FONT-STYLE' => 'italic',
|
||||
],
|
||||
'Q' => [
|
||||
'FONT-STYLE' => 'italic',
|
||||
],
|
||||
'EM' => [
|
||||
'FONT-STYLE' => 'italic',
|
||||
],
|
||||
'VAR' => [
|
||||
'FONT-STYLE' => 'italic',
|
||||
],
|
||||
'SAMP' => [
|
||||
'FONT-FAMILY' => 'monospace',
|
||||
],
|
||||
'CODE' => [
|
||||
'FONT-FAMILY' => 'monospace',
|
||||
],
|
||||
'KBD' => [
|
||||
'FONT-FAMILY' => 'monospace',
|
||||
],
|
||||
'TT' => [
|
||||
'FONT-FAMILY' => 'monospace',
|
||||
],
|
||||
'SMALL' => [
|
||||
'FONT-SIZE' => '83%',
|
||||
],
|
||||
'BIG' => [
|
||||
'FONT-SIZE' => '117%',
|
||||
],
|
||||
'ACRONYM' => [
|
||||
'FONT-SIZE' => '77%',
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
],
|
||||
'ADDRESS' => [
|
||||
'FONT-STYLE' => 'italic',
|
||||
],
|
||||
'BLOCKQUOTE' => [
|
||||
'MARGIN-LEFT' => '40px',
|
||||
'MARGIN-RIGHT' => '40px',
|
||||
'MARGIN-TOP' => '1.12em',
|
||||
'MARGIN-BOTTOM' => '1.12em',
|
||||
],
|
||||
'A' => [
|
||||
'COLOR' => '#0000FF',
|
||||
'TEXT-DECORATION' => 'underline',
|
||||
],
|
||||
'UL' => [
|
||||
'PADDING' => '0 auto',
|
||||
'MARGIN-TOP' => '0.83em',
|
||||
'MARGIN-BOTTOM' => '0.83em',
|
||||
],
|
||||
'OL' => [
|
||||
'PADDING' => '0 auto',
|
||||
'MARGIN-TOP' => '0.83em',
|
||||
'MARGIN-BOTTOM' => '0.83em',
|
||||
],
|
||||
'DL' => [
|
||||
'MARGIN' => '1.67em 0',
|
||||
],
|
||||
'DT' => [],
|
||||
'DD' => [
|
||||
'PADDING-LEFT' => '40px',
|
||||
],
|
||||
'TABLE' => [
|
||||
'MARGIN' => '0',
|
||||
'BORDER-COLLAPSE' => 'separate',
|
||||
'BORDER-SPACING' => '2px',
|
||||
'EMPTY-CELLS' => 'show',
|
||||
'LINE-HEIGHT' => '1.2',
|
||||
'VERTICAL-ALIGN' => 'middle',
|
||||
'HYPHENS' => 'manual',
|
||||
'FONT-KERNING' => 'auto',
|
||||
],
|
||||
'THEAD' => [],
|
||||
'TFOOT' => [],
|
||||
'TH' => [
|
||||
'FONT-WEIGHT' => 'bold',
|
||||
'TEXT-ALIGN' => 'center',
|
||||
'PADDING-LEFT' => '0.1em',
|
||||
'PADDING-RIGHT' => '0.1em',
|
||||
'PADDING-TOP' => '0.1em',
|
||||
'PADDING-BOTTOM' => '0.1em',
|
||||
],
|
||||
'TD' => [
|
||||
'PADDING-LEFT' => '0.1em',
|
||||
'PADDING-RIGHT' => '0.1em',
|
||||
'PADDING-TOP' => '0.1em',
|
||||
'PADDING-BOTTOM' => '0.1em',
|
||||
],
|
||||
'CAPTION' => [
|
||||
'TEXT-ALIGN' => 'center',
|
||||
],
|
||||
'IMG' => [
|
||||
'MARGIN' => '0',
|
||||
'VERTICAL-ALIGN' => 'baseline',
|
||||
'IMAGE-RENDERING' => 'auto',
|
||||
],
|
||||
'INPUT' => [
|
||||
'FONT-FAMILY' => 'sans-serif',
|
||||
'VERTICAL-ALIGN' => 'middle',
|
||||
'FONT-SIZE' => '0.9em',
|
||||
],
|
||||
'SELECT' => [
|
||||
'FONT-FAMILY' => 'sans-serif',
|
||||
'FONT-SIZE' => '0.9em',
|
||||
'VERTICAL-ALIGN' => 'middle',
|
||||
],
|
||||
'TEXTAREA' => [
|
||||
'FONT-FAMILY' => 'monospace',
|
||||
'FONT-SIZE' => '0.9em',
|
||||
'VERTICAL-ALIGN' => 'text-bottom',
|
||||
],
|
||||
'MARK' => [
|
||||
'BACKGROUND-COLOR' => 'yellow',
|
||||
],
|
||||
];
|
||||
}
|
||||
25
Mpdf/Css/TextVars.php
Normal file
25
Mpdf/Css/TextVars.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Css;
|
||||
|
||||
class TextVars
|
||||
{
|
||||
|
||||
// font-decoration
|
||||
const FD_UNDERLINE = 1;
|
||||
const FD_LINETHROUGH = 2;
|
||||
const FD_OVERLINE = 4;
|
||||
|
||||
// font-(vertical)-align
|
||||
const FA_SUPERSCRIPT = 8;
|
||||
const FA_SUBSCRIPT = 16;
|
||||
|
||||
// font-transform
|
||||
const FT_UPPERCASE = 32;
|
||||
const FT_LOWERCASE = 64;
|
||||
const FT_CAPITALIZE = 128;
|
||||
|
||||
// font-(other)-controls
|
||||
const FC_KERNING = 256;
|
||||
const FC_SMALLCAPS = 512;
|
||||
}
|
||||
2328
Mpdf/CssManager.php
Normal file
2328
Mpdf/CssManager.php
Normal file
File diff suppressed because it is too large
Load Diff
515
Mpdf/DirectWrite.php
Normal file
515
Mpdf/DirectWrite.php
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
use Mpdf\Color\ColorConverter;
|
||||
use Mpdf\Css\TextVars;
|
||||
|
||||
class DirectWrite
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Otl
|
||||
*/
|
||||
private $otl;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\SizeConverter
|
||||
*/
|
||||
private $sizeConverter;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Color\ColorConverter
|
||||
*/
|
||||
private $colorConverter;
|
||||
|
||||
public function __construct(Mpdf $mpdf, Otl $otl, SizeConverter $sizeConverter, ColorConverter $colorConverter)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->otl = $otl;
|
||||
$this->sizeConverter = $sizeConverter;
|
||||
$this->colorConverter = $colorConverter;
|
||||
}
|
||||
|
||||
function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '', $fill = 0)
|
||||
{
|
||||
if (!$align) {
|
||||
if ($directionality === 'rtl') {
|
||||
$align = 'R';
|
||||
} else {
|
||||
$align = 'L';
|
||||
}
|
||||
}
|
||||
if ($h == 0) {
|
||||
$this->mpdf->SetLineHeight();
|
||||
$h = $this->mpdf->lineheight;
|
||||
}
|
||||
//Output text in flowing mode
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
|
||||
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
|
||||
$s = str_replace("\r", '', $txt);
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$nb = strlen($s);
|
||||
} else {
|
||||
$nb = mb_strlen($s, $this->mpdf->mb_enc);
|
||||
// handle single space character
|
||||
if (($nb === 1) && $s === ' ') {
|
||||
$this->mpdf->x += $this->mpdf->GetStringWidth($s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$sep = -1;
|
||||
$i = 0;
|
||||
$j = 0;
|
||||
$l = 0;
|
||||
$nl = 1;
|
||||
if (!$this->mpdf->usingCoreFont) {
|
||||
if (preg_match('/([' . $this->mpdf->pregRTLchars . '])/u', $txt)) {
|
||||
$this->mpdf->biDirectional = true;
|
||||
} // *RTL*
|
||||
while ($i < $nb) {
|
||||
//Get next character
|
||||
$c = mb_substr($s, $i, 1, $this->mpdf->mb_enc);
|
||||
if ($c === "\n") {
|
||||
// WORD SPACING
|
||||
$this->mpdf->ResetSpacing();
|
||||
//Explicit line break
|
||||
$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mpdf->mb_enc));
|
||||
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
|
||||
$i++;
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
if ($nl === 1) {
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
|
||||
}
|
||||
$nl++;
|
||||
continue;
|
||||
}
|
||||
if ($c === ' ') {
|
||||
$sep = $i;
|
||||
}
|
||||
$l += $this->mpdf->GetCharWidthNonCore($c); // mPDF 5.3.04
|
||||
if ($l > $wmax) {
|
||||
//Automatic line break (word wrapping)
|
||||
if ($sep == -1) {
|
||||
// WORD SPACING
|
||||
$this->mpdf->ResetSpacing();
|
||||
if ($this->mpdf->x > $this->mpdf->lMargin) {
|
||||
//Move to next line
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
$this->mpdf->y+=$h;
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
|
||||
$i++;
|
||||
$nl++;
|
||||
continue;
|
||||
}
|
||||
if ($i == $j) {
|
||||
$i++;
|
||||
}
|
||||
$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mpdf->mb_enc));
|
||||
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
|
||||
} else {
|
||||
$tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mpdf->mb_enc));
|
||||
|
||||
if ($align === 'J') {
|
||||
//////////////////////////////////////////
|
||||
// JUSTIFY J using Unicode fonts (Word spacing doesn't work)
|
||||
// WORD SPACING
|
||||
// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
|
||||
$tmp = str_replace(chr(194) . chr(160), chr(32), $tmp);
|
||||
$len_ligne = $this->mpdf->GetStringWidth($tmp);
|
||||
$nb_carac = mb_strlen($tmp, $this->mpdf->mb_enc);
|
||||
$nb_spaces = mb_substr_count($tmp, ' ', $this->mpdf->mb_enc);
|
||||
$inclCursive = false;
|
||||
if (!empty($this->mpdf->CurrentFont['useOTL']) && preg_match('/([' . $this->mpdf->pregCURSchars . '])/u', $tmp)) {
|
||||
$inclCursive = true;
|
||||
}
|
||||
list($charspacing, $ws) = $this->mpdf->GetJspacing($nb_carac, $nb_spaces, (($w - 2) - $len_ligne) * Mpdf::SCALE, $inclCursive);
|
||||
$this->mpdf->SetSpacing($charspacing, $ws);
|
||||
//////////////////////////////////////////
|
||||
}
|
||||
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
|
||||
$i = $sep + 1;
|
||||
}
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
if ($nl === 1) {
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
$wmax = ($w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR));
|
||||
}
|
||||
$nl++;
|
||||
} else {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
//Last chunk
|
||||
// WORD SPACING
|
||||
$this->mpdf->ResetSpacing();
|
||||
} else {
|
||||
while ($i < $nb) {
|
||||
//Get next character
|
||||
$c = $s[$i];
|
||||
if ($c === "\n") {
|
||||
//Explicit line break
|
||||
// WORD SPACING
|
||||
$this->mpdf->ResetSpacing();
|
||||
$this->mpdf->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, $align, $fill, $link);
|
||||
$i++;
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
if ($nl === 1) {
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
$wmax = $w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR);
|
||||
}
|
||||
$nl++;
|
||||
continue;
|
||||
}
|
||||
if ($c === ' ') {
|
||||
$sep = $i;
|
||||
}
|
||||
$l += $this->mpdf->GetCharWidthCore($c); // mPDF 5.3.04
|
||||
if ($l > $wmax) {
|
||||
//Automatic line break (word wrapping)
|
||||
if ($sep == -1) {
|
||||
// WORD SPACING
|
||||
$this->mpdf->ResetSpacing();
|
||||
if ($this->mpdf->x > $this->mpdf->lMargin) {
|
||||
//Move to next line
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
$this->mpdf->y+=$h;
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
$wmax = $w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR);
|
||||
$i++;
|
||||
$nl++;
|
||||
continue;
|
||||
}
|
||||
if ($i == $j) {
|
||||
$i++;
|
||||
}
|
||||
$this->mpdf->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, $align, $fill, $link);
|
||||
} else {
|
||||
$tmp = substr($s, $j, $sep - $j);
|
||||
if ($align === 'J') {
|
||||
//////////////////////////////////////////
|
||||
// JUSTIFY J using Unicode fonts
|
||||
// WORD SPACING is not fully supported for complex scripts
|
||||
// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
|
||||
$tmp = str_replace(chr(160), chr(32), $tmp);
|
||||
$len_ligne = $this->mpdf->GetStringWidth($tmp);
|
||||
$nb_carac = strlen($tmp);
|
||||
$nb_spaces = substr_count($tmp, ' ');
|
||||
list($charspacing, $ws) = $this->mpdf->GetJspacing($nb_carac, $nb_spaces, (($w - 2) - $len_ligne) * Mpdf::SCALE, $false);
|
||||
$this->mpdf->SetSpacing($charspacing, $ws);
|
||||
//////////////////////////////////////////
|
||||
}
|
||||
$this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link);
|
||||
$i = $sep + 1;
|
||||
}
|
||||
$sep = -1;
|
||||
$j = $i;
|
||||
$l = 0;
|
||||
if ($nl === 1) {
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
$w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x;
|
||||
$wmax = $w - ($this->mpdf->cMarginL + $this->mpdf->cMarginR);
|
||||
}
|
||||
$nl++;
|
||||
} else {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
// WORD SPACING
|
||||
$this->mpdf->ResetSpacing();
|
||||
}
|
||||
//Last chunk
|
||||
if ($i != $j) {
|
||||
if ($currentx != 0) {
|
||||
$this->mpdf->x = $currentx;
|
||||
} else {
|
||||
$this->mpdf->x = $this->mpdf->lMargin;
|
||||
}
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$tmp = substr($s, $j, $i - $j);
|
||||
} else {
|
||||
$tmp = mb_substr($s, $j, $i - $j, $this->mpdf->mb_enc);
|
||||
}
|
||||
$this->mpdf->Cell($w, $h, $tmp, 0, 0, $align, $fill, $link);
|
||||
}
|
||||
}
|
||||
|
||||
function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily = '', $fontsizePt = 0, $fontstyle = '', $kerning = 120, $fontwidth = 100, $divider = '')
|
||||
{
|
||||
if ($fontfamily || $fontstyle || $fontsizePt) {
|
||||
$this->mpdf->SetFont($fontfamily, $fontstyle, $fontsizePt);
|
||||
}
|
||||
|
||||
$kerning /= 100;
|
||||
$fontwidth /= 100;
|
||||
|
||||
if ($kerning == 0) {
|
||||
throw new \Mpdf\MpdfException('Please use values unequal to zero for kerning (CircularText)');
|
||||
}
|
||||
|
||||
if ($fontwidth == 0) {
|
||||
throw new \Mpdf\MpdfException('Please use values unequal to zero for font width (CircularText)');
|
||||
}
|
||||
|
||||
$text = str_replace("\r", '', $text);
|
||||
|
||||
// circumference
|
||||
$u = ($r * 2) * M_PI;
|
||||
$checking = true;
|
||||
$autoset = false;
|
||||
|
||||
while ($checking) {
|
||||
$t = 0;
|
||||
$w = [];
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$nb = strlen($text);
|
||||
for ($i = 0; $i < $nb; $i++) {
|
||||
$w[$i] = $this->mpdf->GetStringWidth($text[$i]);
|
||||
$w[$i]*=$kerning * $fontwidth;
|
||||
$t+=$w[$i];
|
||||
}
|
||||
} else {
|
||||
$nb = mb_strlen($text, $this->mpdf->mb_enc);
|
||||
$lastchar = '';
|
||||
$unicode = $this->mpdf->UTF8StringToArray($text);
|
||||
for ($i = 0; $i < $nb; $i++) {
|
||||
$c = mb_substr($text, $i, 1, $this->mpdf->mb_enc);
|
||||
$w[$i] = $this->mpdf->GetStringWidth($c);
|
||||
$w[$i]*=$kerning * $fontwidth;
|
||||
$char = $unicode[$i];
|
||||
if ($this->mpdf->useKerning && $lastchar && isset($this->mpdf->CurrentFont['kerninfo'][$lastchar][$char])) {
|
||||
$tk = $this->mpdf->CurrentFont['kerninfo'][$lastchar][$char] * ($this->mpdf->FontSize / 1000) * $kerning * $fontwidth;
|
||||
$w[$i] += $tk / 2;
|
||||
$w[$i - 1] += $tk / 2;
|
||||
$t+=$tk;
|
||||
}
|
||||
$lastchar = $char;
|
||||
$t+=$w[$i];
|
||||
}
|
||||
}
|
||||
if ($fontsizePt >= 0 || $autoset) {
|
||||
$checking = false;
|
||||
} else {
|
||||
$t+=$this->mpdf->GetStringWidth(' ');
|
||||
if ($divider) {
|
||||
$t+=$this->mpdf->GetStringWidth(' ');
|
||||
}
|
||||
if ($fontsizePt == -2) {
|
||||
$fontsizePt = $this->mpdf->FontSizePt * 0.5 * $u / $t;
|
||||
} else {
|
||||
$fontsizePt = $this->mpdf->FontSizePt * $u / $t;
|
||||
}
|
||||
$this->mpdf->SetFontSize($fontsizePt);
|
||||
$autoset = true;
|
||||
}
|
||||
}
|
||||
|
||||
// total width of string in degrees
|
||||
$d = ($t / $u) * 360;
|
||||
|
||||
$this->mpdf->StartTransform();
|
||||
|
||||
// rotate matrix for the first letter to center the text
|
||||
// (half of total degrees)
|
||||
if ($align === 'top') {
|
||||
$this->mpdf->transformRotate(-$d / 2, $x, $y);
|
||||
} else {
|
||||
$this->mpdf->transformRotate($d / 2, $x, $y);
|
||||
}
|
||||
|
||||
// run through the string
|
||||
for ($i = 0; $i < $nb; $i++) {
|
||||
|
||||
if ($align === 'top') {
|
||||
|
||||
// rotate matrix half of the width of current letter + half of the width of preceding letter
|
||||
if ($i === 0) {
|
||||
$this->mpdf->transformRotate((($w[$i] / 2) / $u) * 360, $x, $y);
|
||||
} else {
|
||||
$this->mpdf->transformRotate((($w[$i] / 2 + $w[$i - 1] / 2) / $u) * 360, $x, $y);
|
||||
}
|
||||
|
||||
if ($fontwidth !== 1) {
|
||||
$this->mpdf->StartTransform();
|
||||
$this->mpdf->transformScale($fontwidth * 100, 100, $x, $y);
|
||||
}
|
||||
|
||||
$this->mpdf->SetXY($x - $w[$i] / 2, $y - $r);
|
||||
|
||||
} else {
|
||||
|
||||
// rotate matrix half of the width of current letter + half of the width of preceding letter
|
||||
if ($i === 0) {
|
||||
$this->mpdf->transformRotate(-(($w[$i] / 2) / $u) * 360, $x, $y);
|
||||
} else {
|
||||
$this->mpdf->transformRotate(-(($w[$i] / 2 + $w[$i - 1] / 2) / $u) * 360, $x, $y);
|
||||
}
|
||||
|
||||
if ($fontwidth !== 1) {
|
||||
$this->mpdf->StartTransform();
|
||||
$this->mpdf->transformScale($fontwidth * 100, 100, $x, $y);
|
||||
}
|
||||
$this->mpdf->SetXY($x - $w[$i] / 2, $y + $r - $this->mpdf->FontSize);
|
||||
}
|
||||
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$c = $text[$i];
|
||||
} else {
|
||||
$c = mb_substr($text, $i, 1, $this->mpdf->mb_enc);
|
||||
}
|
||||
|
||||
$this->mpdf->Cell($w[$i], $this->mpdf->FontSize, $c, 0, 0, 'C'); // mPDF 5.3.53
|
||||
|
||||
if ($fontwidth !== 1) {
|
||||
$this->mpdf->StopTransform();
|
||||
}
|
||||
}
|
||||
|
||||
$this->mpdf->StopTransform();
|
||||
|
||||
// mPDF 5.5.23
|
||||
if ($align === 'top' && $divider != '') {
|
||||
$wc = $this->mpdf->GetStringWidth($divider);
|
||||
$wc *= $kerning * $fontwidth;
|
||||
|
||||
$this->mpdf->StartTransform();
|
||||
$this->mpdf->transformRotate(90, $x, $y);
|
||||
$this->mpdf->SetXY($x - $wc / 2, $y - $r);
|
||||
$this->mpdf->Cell($wc, $this->mpdf->FontSize, $divider, 0, 0, 'C');
|
||||
$this->mpdf->StopTransform();
|
||||
|
||||
$this->mpdf->StartTransform();
|
||||
$this->mpdf->transformRotate(-90, $x, $y);
|
||||
$this->mpdf->SetXY($x - $wc / 2, $y - $r);
|
||||
$this->mpdf->Cell($wc, $this->mpdf->FontSize, $divider, 0, 0, 'C');
|
||||
$this->mpdf->StopTransform();
|
||||
}
|
||||
}
|
||||
|
||||
function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '', $width = '70%', $style = 'DF', $radius = 2.5, $fill = '#FFFFFF', $color = '#000000', $pad = 2)
|
||||
{
|
||||
// F (shading - no line),S (line, no shading),DF (both)
|
||||
if (!$font) {
|
||||
$font = $this->mpdf->default_font;
|
||||
}
|
||||
if (!$szfont) {
|
||||
$szfont = $this->mpdf->default_font_size * 1.8;
|
||||
}
|
||||
|
||||
$text = ' ' . $text . ' ';
|
||||
$this->mpdf->SetFont($font, $fontstyle, $szfont, false);
|
||||
|
||||
$text = $this->mpdf->purify_utf8_text($text);
|
||||
|
||||
if ($this->mpdf->text_input_as_HTML) {
|
||||
$text = $this->mpdf->all_entities_to_utf8($text);
|
||||
}
|
||||
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$text = mb_convert_encoding($text, $this->mpdf->mb_enc, 'UTF-8');
|
||||
}
|
||||
|
||||
|
||||
// DIRECTIONALITY
|
||||
if (preg_match('/([' . $this->mpdf->pregRTLchars . '])/u', $text)) {
|
||||
$this->mpdf->biDirectional = true;
|
||||
} // *RTL*
|
||||
|
||||
$textvar = 0;
|
||||
$save_OTLtags = $this->mpdf->OTLtags;
|
||||
$this->mpdf->OTLtags = [];
|
||||
|
||||
if ($this->mpdf->useKerning) {
|
||||
if ($this->mpdf->CurrentFont['haskernGPOS']) {
|
||||
$this->mpdf->OTLtags['Plus'] .= ' kern';
|
||||
} else {
|
||||
$textvar |= TextVars::FC_KERNING;
|
||||
}
|
||||
}
|
||||
// Use OTL OpenType Table Layout - GSUB & GPOS
|
||||
if (!empty($this->mpdf->CurrentFont['useOTL'])) {
|
||||
$text = $this->otl->applyOTL($text, $this->mpdf->CurrentFont['useOTL']);
|
||||
$OTLdata = $this->otl->OTLdata;
|
||||
}
|
||||
$this->mpdf->OTLtags = $save_OTLtags;
|
||||
|
||||
$this->mpdf->magic_reverse_dir($text, $this->mpdf->directionality, $OTLdata);
|
||||
|
||||
if (!$width) {
|
||||
$width = $this->mpdf->pgwidth;
|
||||
} else {
|
||||
$width = $this->sizeConverter->convert($width, $this->mpdf->pgwidth);
|
||||
}
|
||||
$midpt = $this->mpdf->lMargin + ($this->mpdf->pgwidth / 2);
|
||||
$r1 = $midpt - ($width / 2); //($this->mpdf->w / 2) - 40;
|
||||
$r2 = $r1 + $width; //$r1 + 80;
|
||||
$y1 = $this->mpdf->y;
|
||||
|
||||
$loop = 0;
|
||||
|
||||
while ($loop === 0) {
|
||||
$this->mpdf->SetFont($font, $fontstyle, $szfont, false);
|
||||
$sz = $this->mpdf->GetStringWidth($text, true, $OTLdata, $textvar);
|
||||
if (($r1 + $sz) > $r2) {
|
||||
$szfont --;
|
||||
} else {
|
||||
$loop ++;
|
||||
}
|
||||
}
|
||||
$this->mpdf->SetFont($font, $fontstyle, $szfont, true, true);
|
||||
|
||||
$y2 = $this->mpdf->FontSize + ($pad * 2);
|
||||
|
||||
$this->mpdf->SetLineWidth(0.1);
|
||||
$fc = $this->colorConverter->convert($fill, $this->mpdf->PDFAXwarnings);
|
||||
$tc = $this->colorConverter->convert($color, $this->mpdf->PDFAXwarnings);
|
||||
$this->mpdf->SetFColor($fc);
|
||||
$this->mpdf->SetTColor($tc);
|
||||
$this->mpdf->RoundedRect($r1, $y1, $r2 - $r1, $y2, $radius, $style);
|
||||
$this->mpdf->SetX($r1);
|
||||
$this->mpdf->Cell($r2 - $r1, $y2, $text, 0, 1, 'C', 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
|
||||
$this->mpdf->SetY($y1 + $y2 + 2); // +2 = mm margin below shaded box
|
||||
$this->mpdf->Reset();
|
||||
}
|
||||
}
|
||||
8
Mpdf/Exception/FontException.php
Normal file
8
Mpdf/Exception/FontException.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Exception;
|
||||
|
||||
class FontException extends \Mpdf\MpdfException
|
||||
{
|
||||
|
||||
}
|
||||
8
Mpdf/Exception/InvalidArgumentException.php
Normal file
8
Mpdf/Exception/InvalidArgumentException.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Exception;
|
||||
|
||||
class InvalidArgumentException extends \Mpdf\MpdfException
|
||||
{
|
||||
|
||||
}
|
||||
46
Mpdf/File/StreamWrapperChecker.php
Normal file
46
Mpdf/File/StreamWrapperChecker.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\File;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
final class StreamWrapperChecker
|
||||
{
|
||||
|
||||
private $mpdf;
|
||||
|
||||
public function __construct(Mpdf $mpdf)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filename
|
||||
* @return bool
|
||||
* @since 7.1.8
|
||||
*/
|
||||
public function hasBlacklistedStreamWrapper($filename)
|
||||
{
|
||||
if (strpos($filename, '://') > 0) {
|
||||
$wrappers = stream_get_wrappers();
|
||||
$whitelistStreamWrappers = $this->getWhitelistedStreamWrappers();
|
||||
foreach ($wrappers as $wrapper) {
|
||||
if (in_array($wrapper, $whitelistStreamWrappers)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stripos($filename, $wrapper . '://') === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getWhitelistedStreamWrappers()
|
||||
{
|
||||
return array_diff($this->mpdf->whitelistStreamWrappers, ['phar']); // remove 'phar' (security issue)
|
||||
}
|
||||
|
||||
}
|
||||
77
Mpdf/Fonts/FontCache.php
Normal file
77
Mpdf/Fonts/FontCache.php
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Fonts;
|
||||
|
||||
use Mpdf\Cache;
|
||||
|
||||
class FontCache
|
||||
{
|
||||
|
||||
private $memoryCache = [];
|
||||
|
||||
private $cache;
|
||||
|
||||
public function __construct(Cache $cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
public function tempFilename($filename)
|
||||
{
|
||||
return $this->cache->tempFilename($filename);
|
||||
}
|
||||
|
||||
public function has($filename)
|
||||
{
|
||||
return $this->cache->has($filename);
|
||||
}
|
||||
|
||||
public function jsonHas($filename)
|
||||
{
|
||||
return (isset($this->memoryCache[$filename]) || $this->has($filename));
|
||||
}
|
||||
|
||||
public function load($filename)
|
||||
{
|
||||
return $this->cache->load($filename);
|
||||
}
|
||||
|
||||
public function jsonLoad($filename)
|
||||
{
|
||||
if (isset($this->memoryCache[$filename])) {
|
||||
return $this->memoryCache[$filename];
|
||||
}
|
||||
|
||||
$this->memoryCache[$filename] = json_decode($this->load($filename), true);
|
||||
return $this->memoryCache[$filename];
|
||||
}
|
||||
|
||||
public function write($filename, $data)
|
||||
{
|
||||
return $this->cache->write($filename, $data);
|
||||
}
|
||||
|
||||
public function binaryWrite($filename, $data)
|
||||
{
|
||||
return $this->cache->write($filename, $data);
|
||||
}
|
||||
|
||||
public function jsonWrite($filename, $data)
|
||||
{
|
||||
return $this->cache->write($filename, json_encode($data));
|
||||
}
|
||||
|
||||
public function remove($filename)
|
||||
{
|
||||
return $this->cache->remove($filename);
|
||||
}
|
||||
|
||||
public function jsonRemove($filename)
|
||||
{
|
||||
if (isset($this->memoryCache[$filename])) {
|
||||
unset($this->memoryCache[$filename]);
|
||||
}
|
||||
|
||||
$this->remove($filename);
|
||||
}
|
||||
}
|
||||
35
Mpdf/Fonts/FontFileFinder.php
Normal file
35
Mpdf/Fonts/FontFileFinder.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Fonts;
|
||||
|
||||
class FontFileFinder
|
||||
{
|
||||
|
||||
private $directories;
|
||||
|
||||
public function __construct($directories)
|
||||
{
|
||||
$this->setDirectories($directories);
|
||||
}
|
||||
|
||||
public function setDirectories($directories)
|
||||
{
|
||||
if (!is_array($directories)) {
|
||||
$directories = [$directories];
|
||||
}
|
||||
|
||||
$this->directories = $directories;
|
||||
}
|
||||
|
||||
public function findFontFile($name)
|
||||
{
|
||||
foreach ($this->directories as $directory) {
|
||||
$filename = $directory . '/' . $name;
|
||||
if (file_exists($filename)) {
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Mpdf\MpdfException(sprintf('Cannot find TTF TrueType font file "%s" in configured font directories.', $name));
|
||||
}
|
||||
}
|
||||
17
Mpdf/Fonts/GlyphOperator.php
Normal file
17
Mpdf/Fonts/GlyphOperator.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Fonts;
|
||||
|
||||
class GlyphOperator
|
||||
{
|
||||
|
||||
const WORDS = 1 << 0;
|
||||
|
||||
const SCALE = 1 << 3;
|
||||
|
||||
const MORE = 1 << 5;
|
||||
|
||||
const XYSCALE = 1 << 6;
|
||||
|
||||
const TWOBYTWO = 1 << 7;
|
||||
}
|
||||
110
Mpdf/Fonts/MetricsGenerator.php
Normal file
110
Mpdf/Fonts/MetricsGenerator.php
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Fonts;
|
||||
|
||||
use Mpdf\TTFontFile;
|
||||
|
||||
class MetricsGenerator
|
||||
{
|
||||
|
||||
private $fontCache;
|
||||
|
||||
private $fontDescriptor;
|
||||
|
||||
public function __construct(FontCache $fontCache, $fontDescriptor)
|
||||
{
|
||||
$this->fontCache = $fontCache;
|
||||
$this->fontDescriptor = $fontDescriptor;
|
||||
}
|
||||
|
||||
public function generateMetrics($ttffile, $ttfstat, $fontkey, $TTCfontID, $debugfonts, $BMPonly, $useOTL, $fontUseOTL)
|
||||
{
|
||||
$ttf = new TTFontFile($this->fontCache, $this->fontDescriptor);
|
||||
$ttf->getMetrics($ttffile, $fontkey, $TTCfontID, $debugfonts, $BMPonly, $useOTL); // mPDF 5.7.1
|
||||
|
||||
$font = [
|
||||
'name' => $this->getFontName($ttf->fullName),
|
||||
'type' => 'TTF',
|
||||
'desc' => [
|
||||
'CapHeight' => round($ttf->capHeight),
|
||||
'XHeight' => round($ttf->xHeight),
|
||||
'FontBBox' => '[' . round($ttf->bbox[0]) . " " . round($ttf->bbox[1]) . " " . round($ttf->bbox[2]) . " " . round($ttf->bbox[3]) . ']',
|
||||
/* FontBBox from head table */
|
||||
/* 'MaxWidth' => round($ttf->advanceWidthMax), // AdvanceWidthMax from hhea table NB ArialUnicode MS = 31990 ! */
|
||||
'Flags' => $ttf->flags,
|
||||
'Ascent' => round($ttf->ascent),
|
||||
'Descent' => round($ttf->descent),
|
||||
'Leading' => round($ttf->lineGap),
|
||||
'ItalicAngle' => $ttf->italicAngle,
|
||||
'StemV' => round($ttf->stemV),
|
||||
'MissingWidth' => round($ttf->defaultWidth)
|
||||
],
|
||||
'unitsPerEm' => round($ttf->unitsPerEm),
|
||||
'up' => round($ttf->underlinePosition),
|
||||
'ut' => round($ttf->underlineThickness),
|
||||
'strp' => round($ttf->strikeoutPosition),
|
||||
'strs' => round($ttf->strikeoutSize),
|
||||
'ttffile' => $ttffile,
|
||||
'TTCfontID' => $TTCfontID,
|
||||
'originalsize' => $ttfstat['size'] + 0, /* cast ? */
|
||||
'sip' => ($ttf->sipset) ? true : false,
|
||||
'smp' => ($ttf->smpset) ? true : false,
|
||||
'BMPselected' => ($BMPonly) ? true : false,
|
||||
'fontkey' => $fontkey,
|
||||
'panose' => $this->getPanose($ttf),
|
||||
'haskerninfo' => ($ttf->kerninfo) ? true : false,
|
||||
'haskernGPOS' => ($ttf->haskernGPOS) ? true : false,
|
||||
'hassmallcapsGSUB' => ($ttf->hassmallcapsGSUB) ? true : false,
|
||||
'fontmetrics' => $this->fontDescriptor,
|
||||
'useOTL' => ($fontUseOTL) ? $fontUseOTL : 0,
|
||||
'rtlPUAstr' => $ttf->rtlPUAstr,
|
||||
'GSUBScriptLang' => $ttf->GSUBScriptLang,
|
||||
'GSUBFeatures' => $ttf->GSUBFeatures,
|
||||
'GSUBLookups' => $ttf->GSUBLookups,
|
||||
'GPOSScriptLang' => $ttf->GPOSScriptLang,
|
||||
'GPOSFeatures' => $ttf->GPOSFeatures,
|
||||
'GPOSLookups' => $ttf->GPOSLookups,
|
||||
'kerninfo' => $ttf->kerninfo,
|
||||
];
|
||||
|
||||
$this->fontCache->jsonWrite($fontkey . '.mtx.json', $font);
|
||||
$this->fontCache->binaryWrite($fontkey . '.cw.dat', $ttf->charWidths);
|
||||
$this->fontCache->binaryWrite($fontkey . '.gid.dat', $ttf->glyphIDtoUni);
|
||||
|
||||
if ($this->fontCache->has($fontkey . '.cgm')) {
|
||||
$this->fontCache->remove($fontkey . '.cgm');
|
||||
}
|
||||
|
||||
if ($this->fontCache->has($fontkey . '.z')) {
|
||||
$this->fontCache->remove($fontkey . '.z');
|
||||
}
|
||||
|
||||
if ($this->fontCache->jsonHas($fontkey . '.cw127.json')) {
|
||||
$this->fontCache->jsonRemove($fontkey . '.cw127.json');
|
||||
}
|
||||
|
||||
if ($this->fontCache->has($fontkey . '.cw')) {
|
||||
$this->fontCache->remove($fontkey . '.cw');
|
||||
}
|
||||
|
||||
unset($ttf);
|
||||
}
|
||||
|
||||
protected function getFontName($fullName)
|
||||
{
|
||||
return preg_replace('/[ ()]/', '', $fullName);
|
||||
}
|
||||
|
||||
protected function getPanose($ttf)
|
||||
{
|
||||
$panose = '';
|
||||
if (count($ttf->panose)) {
|
||||
$panoseArray = array_merge([$ttf->sFamilyClass, $ttf->sFamilySubClass], $ttf->panose);
|
||||
foreach ($panoseArray as $value) {
|
||||
$panose .= ' ' . dechex($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $panose;
|
||||
}
|
||||
}
|
||||
1828
Mpdf/Form.php
Normal file
1828
Mpdf/Form.php
Normal file
File diff suppressed because it is too large
Load Diff
401
Mpdf/FpdiTrait.php
Normal file
401
Mpdf/FpdiTrait.php
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
use setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException;
|
||||
use setasign\Fpdi\PdfParser\Filter\AsciiHex;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfArray;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfDictionary;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfHexString;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfIndirectObject;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfIndirectObjectReference;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfName;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfNull;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfNumeric;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfStream;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfString;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfType;
|
||||
use setasign\Fpdi\PdfParser\Type\PdfTypeException;
|
||||
use setasign\Fpdi\PdfReader\DataStructure\Rectangle;
|
||||
use setasign\Fpdi\PdfReader\PageBoundaries;
|
||||
|
||||
/**
|
||||
* @mixin Mpdf
|
||||
*/
|
||||
trait FpdiTrait
|
||||
{
|
||||
use \setasign\Fpdi\FpdiTrait {
|
||||
writePdfType as fpdiWritePdfType;
|
||||
useImportedPage as fpdiUseImportedPage;
|
||||
importPage as fpdiImportPage;
|
||||
}
|
||||
|
||||
protected $k = Mpdf::SCALE;
|
||||
|
||||
/**
|
||||
* The currently used object number.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $currentObjectNumber;
|
||||
|
||||
/**
|
||||
* A counter for template ids.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $templateId = 0;
|
||||
|
||||
protected function setPageFormat($format, $orientation)
|
||||
{
|
||||
// in mPDF this needs to be "P" (why ever)
|
||||
$orientation = 'P';
|
||||
$this->_setPageSize([$format['width'], $format['height']], $orientation);
|
||||
|
||||
if ($orientation != $this->DefOrientation) {
|
||||
$this->OrientationChanges[$this->page] = true;
|
||||
}
|
||||
|
||||
$this->wPt = $this->fwPt;
|
||||
$this->hPt = $this->fhPt;
|
||||
$this->w = $this->fw;
|
||||
$this->h = $this->fh;
|
||||
|
||||
$this->CurOrientation = $orientation;
|
||||
$this->ResetMargins();
|
||||
$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
|
||||
$this->PageBreakTrigger = $this->h - $this->bMargin;
|
||||
|
||||
$this->pageDim[$this->page]['w'] = $this->w;
|
||||
$this->pageDim[$this->page]['h'] = $this->h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimal PDF version.
|
||||
*
|
||||
* @param string $pdfVersion
|
||||
*/
|
||||
protected function setMinPdfVersion($pdfVersion)
|
||||
{
|
||||
if (\version_compare($pdfVersion, $this->pdf_version, '>')) {
|
||||
$this->pdf_version = $pdfVersion;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next template id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getNextTemplateId()
|
||||
{
|
||||
return $this->templateId++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an imported page or a template onto the page or another template.
|
||||
*
|
||||
* Omit one of the size parameters (width, height) to calculate the other one automatically in view to the aspect
|
||||
* ratio.
|
||||
*
|
||||
* @param mixed $tpl The template id
|
||||
* @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
|
||||
* with the keys "x", "y", "width", "height", "adjustPageSize".
|
||||
* @param float|int $y The ordinate of upper-left corner.
|
||||
* @param float|int|null $width The width.
|
||||
* @param float|int|null $height The height.
|
||||
* @param bool $adjustPageSize
|
||||
* @return array The size
|
||||
* @see Fpdi::getTemplateSize()
|
||||
*/
|
||||
public function useTemplate($tpl, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
|
||||
{
|
||||
return $this->useImportedPage($tpl, $x, $y, $width, $height, $adjustPageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an imported page onto the page.
|
||||
*
|
||||
* Omit one of the size parameters (width, height) to calculate the other one automatically in view to the aspect
|
||||
* ratio.
|
||||
*
|
||||
* @param mixed $pageId The page id
|
||||
* @param float|int|array $x The abscissa of upper-left corner. Alternatively you could use an assoc array
|
||||
* with the keys "x", "y", "width", "height", "adjustPageSize".
|
||||
* @param float|int $y The ordinate of upper-left corner.
|
||||
* @param float|int|null $width The width.
|
||||
* @param float|int|null $height The height.
|
||||
* @param bool $adjustPageSize
|
||||
* @return array The size.
|
||||
* @see Fpdi::getTemplateSize()
|
||||
*/
|
||||
public function useImportedPage($pageId, $x = 0, $y = 0, $width = null, $height = null, $adjustPageSize = false)
|
||||
{
|
||||
if ($this->state == 0) {
|
||||
$this->AddPage();
|
||||
}
|
||||
|
||||
/* Extract $x if an array */
|
||||
if (is_array($x)) {
|
||||
unset($x['pageId']);
|
||||
extract($x, EXTR_IF_EXISTS);
|
||||
if (is_array($x)) {
|
||||
$x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$newSize = $this->fpdiUseImportedPage($pageId, $x, $y, $width, $height, $adjustPageSize);
|
||||
|
||||
$this->setImportedPageLinks($pageId, $x, $y, $newSize);
|
||||
|
||||
return $newSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a page.
|
||||
*
|
||||
* @param int $pageNumber The page number.
|
||||
* @param string $box The page boundary to import. Default set to PageBoundaries::CROP_BOX.
|
||||
* @param bool $groupXObject Define the form XObject as a group XObject to support transparency (if used).
|
||||
* @return string A unique string identifying the imported page.
|
||||
* @throws CrossReferenceException
|
||||
* @throws FilterException
|
||||
* @throws PdfParserException
|
||||
* @throws PdfTypeException
|
||||
* @throws PdfReaderException
|
||||
* @see PageBoundaries
|
||||
*/
|
||||
public function importPage($pageNumber, $box = PageBoundaries::CROP_BOX, $groupXObject = true)
|
||||
{
|
||||
$pageId = $this->fpdiImportPage($pageNumber, $box, $groupXObject);
|
||||
|
||||
$this->importedPages[$pageId]['externalLinks'] = $this->getImportedExternalPageLinks($pageNumber);
|
||||
|
||||
return $pageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports the external page links
|
||||
*
|
||||
* @param int $pageNumber The page number.
|
||||
* @return array
|
||||
* @throws CrossReferenceException
|
||||
* @throws PdfTypeException
|
||||
* @throws \setasign\Fpdi\PdfParser\PdfParserException
|
||||
*/
|
||||
public function getImportedExternalPageLinks($pageNumber)
|
||||
{
|
||||
$links = [];
|
||||
|
||||
$reader = $this->getPdfReader($this->currentReaderId);
|
||||
$parser = $reader->getParser();
|
||||
|
||||
$page = $reader->getPage($pageNumber);
|
||||
$page->getPageDictionary();
|
||||
|
||||
$annotations = $page->getAttribute('Annots');
|
||||
if ($annotations instanceof PdfIndirectObjectReference) {
|
||||
$annotations = PdfType::resolve($parser->getIndirectObject($annotations->value), $parser);
|
||||
}
|
||||
|
||||
if ($annotations instanceof PdfArray) {
|
||||
$annotations = PdfType::resolve($annotations, $parser);
|
||||
|
||||
foreach ($annotations->value as $annotation) {
|
||||
try {
|
||||
$annotation = PdfType::resolve($annotation, $parser);
|
||||
|
||||
$type = PdfName::ensure(PdfType::resolve(PdfDictionary::get($annotation, 'Type'), $parser));
|
||||
$subtype = PdfName::ensure(PdfType::resolve(PdfDictionary::get($annotation, 'Subtype'), $parser));
|
||||
$link = PdfDictionary::ensure(PdfType::resolve(PdfDictionary::get($annotation, 'A'), $parser));
|
||||
|
||||
/* Skip over annotations that aren't links */
|
||||
if ($type->value !== 'Annot' || $subtype->value !== 'Link') {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Calculate the link positioning */
|
||||
$position = PdfArray::ensure(PdfType::resolve(PdfDictionary::get($annotation, 'Rect'), $parser), 4);
|
||||
$rect = Rectangle::byPdfArray($position, $parser);
|
||||
$uri = PdfString::ensure(PdfType::resolve(PdfDictionary::get($link, 'URI'), $parser));
|
||||
|
||||
$links[] = [
|
||||
'x' => $rect->getLlx() / Mpdf::SCALE,
|
||||
'y' => $rect->getLly() / Mpdf::SCALE,
|
||||
'width' => $rect->getWidth() / Mpdf::SCALE,
|
||||
'height' => $rect->getHeight() / Mpdf::SCALE,
|
||||
'url' => $uri->value
|
||||
];
|
||||
} catch (PdfTypeException $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $pageId The page id
|
||||
* @param int|float $x The abscissa of upper-left corner.
|
||||
* @param int|float $y The ordinate of upper-right corner.
|
||||
* @param array $newSize The size.
|
||||
*/
|
||||
public function setImportedPageLinks($pageId, $x, $y, $newSize)
|
||||
{
|
||||
$originalSize = $this->getTemplateSize($pageId);
|
||||
$pageHeightDifference = $this->h - $newSize['height'];
|
||||
|
||||
/* Handle different aspect ratio */
|
||||
$widthRatio = $newSize['width'] / $originalSize['width'];
|
||||
$heightRatio = $newSize['height'] / $originalSize['height'];
|
||||
|
||||
foreach ($this->importedPages[$pageId]['externalLinks'] as $item) {
|
||||
|
||||
$item['x'] *= $widthRatio;
|
||||
$item['width'] *= $widthRatio;
|
||||
|
||||
$item['y'] *= $heightRatio;
|
||||
$item['height'] *= $heightRatio;
|
||||
|
||||
$this->Link(
|
||||
$item['x'] + $x,
|
||||
/* convert Y to be measured from the top of the page */
|
||||
$this->h - $item['y'] - $item['height'] - $pageHeightDifference + $y,
|
||||
$item['width'],
|
||||
$item['height'],
|
||||
$item['url']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of an imported page or template.
|
||||
*
|
||||
* Omit one of the size parameters (width, height) to calculate the other one automatically in view to the aspect
|
||||
* ratio.
|
||||
*
|
||||
* @param mixed $tpl The template id
|
||||
* @param float|int|null $width The width.
|
||||
* @param float|int|null $height The height.
|
||||
* @return array|bool An array with following keys: width, height, 0 (=width), 1 (=height), orientation (L or P)
|
||||
*/
|
||||
public function getTemplateSize($tpl, $width = null, $height = null)
|
||||
{
|
||||
return $this->getImportedPageSize($tpl, $width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws CrossReferenceException
|
||||
* @throws PdfTypeException
|
||||
* @throws \setasign\Fpdi\PdfParser\PdfParserException
|
||||
*/
|
||||
public function writeImportedPagesAndResolvedObjects()
|
||||
{
|
||||
$this->currentReaderId = null;
|
||||
|
||||
foreach ($this->importedPages as $key => $pageData) {
|
||||
$this->writer->object();
|
||||
$this->importedPages[$key]['objectNumber'] = $this->n;
|
||||
$this->currentReaderId = $pageData['readerId'];
|
||||
$this->writePdfType($pageData['stream']);
|
||||
$this->_put('endobj');
|
||||
}
|
||||
|
||||
foreach (\array_keys($this->readers) as $readerId) {
|
||||
$parser = $this->getPdfReader($readerId)->getParser();
|
||||
$this->currentReaderId = $readerId;
|
||||
|
||||
while (($objectNumber = \array_pop($this->objectsToCopy[$readerId])) !== null) {
|
||||
try {
|
||||
$object = $parser->getIndirectObject($objectNumber);
|
||||
|
||||
} catch (CrossReferenceException $e) {
|
||||
if ($e->getCode() === CrossReferenceException::OBJECT_NOT_FOUND) {
|
||||
$object = PdfIndirectObject::create($objectNumber, 0, new PdfNull());
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$this->writePdfType($object);
|
||||
}
|
||||
}
|
||||
|
||||
$this->currentReaderId = null;
|
||||
}
|
||||
|
||||
public function getImportedPages()
|
||||
{
|
||||
return $this->importedPages;
|
||||
}
|
||||
|
||||
protected function _put($s, $newLine = true)
|
||||
{
|
||||
if ($newLine) {
|
||||
$this->buffer .= $s . "\n";
|
||||
} else {
|
||||
$this->buffer .= $s;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a PdfType object to the resulting buffer.
|
||||
*
|
||||
* @param PdfType $value
|
||||
* @throws PdfTypeException
|
||||
*/
|
||||
public function writePdfType(PdfType $value)
|
||||
{
|
||||
if (!$this->encrypted) {
|
||||
if ($value instanceof PdfIndirectObject) {
|
||||
/**
|
||||
* @var $value PdfIndirectObject
|
||||
*/
|
||||
$n = $this->objectMap[$this->currentReaderId][$value->objectNumber];
|
||||
$this->writer->object($n);
|
||||
$this->writePdfType($value->value);
|
||||
$this->_put('endobj');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fpdiWritePdfType($value);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($value instanceof PdfString) {
|
||||
$string = PdfString::unescape($value->value);
|
||||
$string = $this->protection->rc4($this->protection->objectKey($this->currentObjectNumber), $string);
|
||||
$value->value = $this->writer->escape($string);
|
||||
|
||||
} elseif ($value instanceof PdfHexString) {
|
||||
$filter = new AsciiHex();
|
||||
$string = $filter->decode($value->value);
|
||||
$string = $this->protection->rc4($this->protection->objectKey($this->currentObjectNumber), $string);
|
||||
$value->value = $filter->encode($string, true);
|
||||
|
||||
} elseif ($value instanceof PdfStream) {
|
||||
$stream = $value->getStream();
|
||||
$stream = $this->protection->rc4($this->protection->objectKey($this->currentObjectNumber), $stream);
|
||||
$dictionary = $value->value;
|
||||
$dictionary->value['Length'] = PdfNumeric::create(\strlen($stream));
|
||||
$value = PdfStream::create($dictionary, $stream);
|
||||
|
||||
} elseif ($value instanceof PdfIndirectObject) {
|
||||
/**
|
||||
* @var $value PdfIndirectObject
|
||||
*/
|
||||
$this->currentObjectNumber = $this->objectMap[$this->currentReaderId][$value->objectNumber];
|
||||
/**
|
||||
* @var $value PdfIndirectObject
|
||||
*/
|
||||
$n = $this->objectMap[$this->currentReaderId][$value->objectNumber];
|
||||
$this->writer->object($n);
|
||||
$this->writePdfType($value->value);
|
||||
$this->_put('endobj');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fpdiWritePdfType($value);
|
||||
}
|
||||
}
|
||||
82
Mpdf/Gif/ColorTable.php
Normal file
82
Mpdf/Gif/ColorTable.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Gif;
|
||||
|
||||
/**
|
||||
* GIF Util - (C) 2003 Yamasoft (S/C)
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file can be freely copied, distributed, modified, updated by anyone under the only
|
||||
* condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
|
||||
*
|
||||
* @link http://www.yamasoft.com
|
||||
*/
|
||||
class ColorTable
|
||||
{
|
||||
|
||||
var $m_nColors;
|
||||
|
||||
var $m_arColors;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
unset($this->m_nColors);
|
||||
unset($this->m_arColors);
|
||||
}
|
||||
|
||||
function load($lpData, $num)
|
||||
{
|
||||
$this->m_nColors = 0;
|
||||
$this->m_arColors = [];
|
||||
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
$rgb = substr($lpData, $i * 3, 3);
|
||||
if (strlen($rgb) < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]);
|
||||
$this->m_nColors++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function toString()
|
||||
{
|
||||
$ret = "";
|
||||
|
||||
for ($i = 0; $i < $this->m_nColors; $i++) {
|
||||
$ret .=
|
||||
chr(($this->m_arColors[$i] & 0x000000FF)) . // R
|
||||
chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
|
||||
chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function colorIndex($rgb)
|
||||
{
|
||||
$rgb = intval($rgb) & 0xFFFFFF;
|
||||
$r1 = ($rgb & 0x0000FF);
|
||||
$g1 = ($rgb & 0x00FF00) >> 8;
|
||||
$b1 = ($rgb & 0xFF0000) >> 16;
|
||||
$idx = -1;
|
||||
|
||||
for ($i = 0; $i < $this->m_nColors; $i++) {
|
||||
$r2 = ($this->m_arColors[$i] & 0x000000FF);
|
||||
$g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8;
|
||||
$b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
|
||||
$d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
|
||||
|
||||
if (($idx == -1) || ($d < $dif)) {
|
||||
$idx = $i;
|
||||
$dif = $d;
|
||||
}
|
||||
}
|
||||
|
||||
return $idx;
|
||||
}
|
||||
}
|
||||
94
Mpdf/Gif/FileHeader.php
Normal file
94
Mpdf/Gif/FileHeader.php
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Gif;
|
||||
|
||||
/**
|
||||
* GIF Util - (C) 2003 Yamasoft (S/C)
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file can be freely copied, distributed, modified, updated by anyone under the only
|
||||
* condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
|
||||
*
|
||||
* @link http://www.yamasoft.com
|
||||
*/
|
||||
class FileHeader
|
||||
{
|
||||
|
||||
var $m_lpVer;
|
||||
|
||||
var $m_nWidth;
|
||||
|
||||
var $m_nHeight;
|
||||
|
||||
var $m_bGlobalClr;
|
||||
|
||||
var $m_nColorRes;
|
||||
|
||||
var $m_bSorted;
|
||||
|
||||
var $m_nTableSize;
|
||||
|
||||
var $m_nBgColor;
|
||||
|
||||
var $m_nPixelRatio;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Gif\ColorTable
|
||||
*/
|
||||
var $m_colorTable;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
unset($this->m_lpVer);
|
||||
unset($this->m_nWidth);
|
||||
unset($this->m_nHeight);
|
||||
unset($this->m_bGlobalClr);
|
||||
unset($this->m_nColorRes);
|
||||
unset($this->m_bSorted);
|
||||
unset($this->m_nTableSize);
|
||||
unset($this->m_nBgColor);
|
||||
unset($this->m_nPixelRatio);
|
||||
unset($this->m_colorTable);
|
||||
}
|
||||
|
||||
function load($lpData, &$hdrLen)
|
||||
{
|
||||
$hdrLen = 0;
|
||||
|
||||
$this->m_lpVer = substr($lpData, 0, 6);
|
||||
if (($this->m_lpVer <> "GIF87a") && ($this->m_lpVer <> "GIF89a")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->m_nWidth = $this->w2i(substr($lpData, 6, 2));
|
||||
$this->m_nHeight = $this->w2i(substr($lpData, 8, 2));
|
||||
if (!$this->m_nWidth || !$this->m_nHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$b = ord(substr($lpData, 10, 1));
|
||||
$this->m_bGlobalClr = ($b & 0x80) ? true : false;
|
||||
$this->m_nColorRes = ($b & 0x70) >> 4;
|
||||
$this->m_bSorted = ($b & 0x08) ? true : false;
|
||||
$this->m_nTableSize = 2 << ($b & 0x07);
|
||||
$this->m_nBgColor = ord(substr($lpData, 11, 1));
|
||||
$this->m_nPixelRatio = ord(substr($lpData, 12, 1));
|
||||
$hdrLen = 13;
|
||||
|
||||
if ($this->m_bGlobalClr) {
|
||||
$this->m_colorTable = new ColorTable();
|
||||
if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
|
||||
return false;
|
||||
}
|
||||
$hdrLen += 3 * $this->m_nTableSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function w2i($str)
|
||||
{
|
||||
return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
|
||||
}
|
||||
}
|
||||
70
Mpdf/Gif/Gif.php
Normal file
70
Mpdf/Gif/Gif.php
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Gif;
|
||||
|
||||
/**
|
||||
* GIF Util - (C) 2003 Yamasoft (S/C)
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file can be freely copied, distributed, modified, updated by anyone under the only
|
||||
* condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
|
||||
*
|
||||
* @link http://www.yamasoft.com
|
||||
*/
|
||||
class Gif
|
||||
{
|
||||
|
||||
var $m_gfh;
|
||||
|
||||
var $m_lpData;
|
||||
|
||||
var $m_img;
|
||||
|
||||
var $m_bLoaded;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->m_gfh = new FileHeader();
|
||||
$this->m_img = new Image();
|
||||
$this->m_lpData = '';
|
||||
$this->m_bLoaded = false;
|
||||
}
|
||||
|
||||
function ClearData()
|
||||
{
|
||||
$this->m_lpData = '';
|
||||
unset($this->m_img->m_data);
|
||||
unset($this->m_img->m_lzw->Next);
|
||||
unset($this->m_img->m_lzw->Vals);
|
||||
unset($this->m_img->m_lzw->Stack);
|
||||
unset($this->m_img->m_lzw->Buf);
|
||||
}
|
||||
|
||||
function loadFile(&$data, $iIndex)
|
||||
{
|
||||
if ($iIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
$this->m_lpData = $data;
|
||||
|
||||
// GET FILE HEADER
|
||||
$len = 0;
|
||||
if (!$this->m_gfh->load($this->m_lpData, $len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->m_lpData = substr($this->m_lpData, $len);
|
||||
|
||||
do {
|
||||
$imgLen = 0;
|
||||
if (!$this->m_img->load($this->m_lpData, $imgLen)) {
|
||||
return false;
|
||||
}
|
||||
$this->m_lpData = substr($this->m_lpData, $imgLen);
|
||||
} while ($iIndex-- > 0);
|
||||
|
||||
$this->m_bLoaded = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
187
Mpdf/Gif/Image.php
Normal file
187
Mpdf/Gif/Image.php
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Gif;
|
||||
|
||||
/**
|
||||
* GIF Util - (C) 2003 Yamasoft (S/C)
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file can be freely copied, distributed, modified, updated by anyone under the only
|
||||
* condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
|
||||
*
|
||||
* @link http://www.yamasoft.com
|
||||
*/
|
||||
class Image
|
||||
{
|
||||
|
||||
var $m_disp;
|
||||
|
||||
var $m_bUser;
|
||||
|
||||
var $m_bTrans;
|
||||
|
||||
var $m_nDelay;
|
||||
|
||||
var $m_nTrans;
|
||||
|
||||
var $m_lpComm;
|
||||
|
||||
var $m_gih;
|
||||
|
||||
var $m_data;
|
||||
|
||||
var $m_lzw;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
unset($this->m_disp);
|
||||
unset($this->m_bUser);
|
||||
unset($this->m_bTrans);
|
||||
unset($this->m_nDelay);
|
||||
unset($this->m_nTrans);
|
||||
unset($this->m_lpComm);
|
||||
unset($this->m_data);
|
||||
$this->m_gih = new ImageHeader();
|
||||
$this->m_lzw = new Lzw();
|
||||
}
|
||||
|
||||
function load($data, &$datLen)
|
||||
{
|
||||
$datLen = 0;
|
||||
|
||||
while (true) {
|
||||
$b = ord($data[0]);
|
||||
$data = substr($data, 1);
|
||||
$datLen++;
|
||||
|
||||
switch ($b) {
|
||||
case 0x21: // Extension
|
||||
$len = 0;
|
||||
if (!$this->skipExt($data, $len)) {
|
||||
return false;
|
||||
}
|
||||
$datLen += $len;
|
||||
break;
|
||||
|
||||
case 0x2C: // Image
|
||||
// LOAD HEADER & COLOR TABLE
|
||||
$len = 0;
|
||||
if (!$this->m_gih->load($data, $len)) {
|
||||
return false;
|
||||
}
|
||||
$data = substr($data, $len);
|
||||
$datLen += $len;
|
||||
|
||||
// ALLOC BUFFER
|
||||
$len = 0;
|
||||
|
||||
if (!($this->m_data = $this->m_lzw->deCompress($data, $len))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = substr($data, $len);
|
||||
$datLen += $len;
|
||||
|
||||
if ($this->m_gih->m_bInterlace) {
|
||||
$this->deInterlace();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case 0x3B: // EOF
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function skipExt(&$data, &$extLen)
|
||||
{
|
||||
$extLen = 0;
|
||||
|
||||
$b = ord($data[0]);
|
||||
$data = substr($data, 1);
|
||||
$extLen++;
|
||||
|
||||
switch ($b) {
|
||||
case 0xF9: // Graphic Control
|
||||
$b = ord($data[1]);
|
||||
$this->m_disp = ($b & 0x1C) >> 2;
|
||||
$this->m_bUser = ($b & 0x02) ? true : false;
|
||||
$this->m_bTrans = ($b & 0x01) ? true : false;
|
||||
$this->m_nDelay = $this->w2i(substr($data, 2, 2));
|
||||
$this->m_nTrans = ord($data[4]);
|
||||
break;
|
||||
|
||||
case 0xFE: // Comment
|
||||
$this->m_lpComm = substr($data, 1, ord($data[0]));
|
||||
break;
|
||||
|
||||
case 0x01: // Plain text
|
||||
break;
|
||||
|
||||
case 0xFF: // Application
|
||||
break;
|
||||
}
|
||||
|
||||
// SKIP DEFAULT AS DEFS MAY CHANGE
|
||||
$b = ord($data[0]);
|
||||
$data = substr($data, 1);
|
||||
$extLen++;
|
||||
while ($b > 0) {
|
||||
$data = substr($data, $b);
|
||||
$extLen += $b;
|
||||
$b = ord($data[0]);
|
||||
$data = substr($data, 1);
|
||||
$extLen++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function w2i($str)
|
||||
{
|
||||
return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
|
||||
}
|
||||
|
||||
function deInterlace()
|
||||
{
|
||||
$data = $this->m_data;
|
||||
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
switch ($i) {
|
||||
case 0:
|
||||
$s = 8;
|
||||
$y = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$s = 8;
|
||||
$y = 4;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$s = 4;
|
||||
$y = 2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$s = 2;
|
||||
$y = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (; $y < $this->m_gih->m_nHeight; $y += $s) {
|
||||
$lne = substr($this->m_data, 0, $this->m_gih->m_nWidth);
|
||||
$this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
|
||||
|
||||
$data = substr($data, 0, $y * $this->m_gih->m_nWidth) .
|
||||
$lne .
|
||||
substr($data, ($y + 1) * $this->m_gih->m_nWidth);
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_data = $data;
|
||||
}
|
||||
}
|
||||
87
Mpdf/Gif/ImageHeader.php
Normal file
87
Mpdf/Gif/ImageHeader.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Gif;
|
||||
|
||||
/**
|
||||
* GIF Util - (C) 2003 Yamasoft (S/C)
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file can be freely copied, distributed, modified, updated by anyone under the only
|
||||
* condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
|
||||
*
|
||||
* @link http://www.yamasoft.com
|
||||
*/
|
||||
class ImageHeader
|
||||
{
|
||||
|
||||
var $m_nLeft;
|
||||
|
||||
var $m_nTop;
|
||||
|
||||
var $m_nWidth;
|
||||
|
||||
var $m_nHeight;
|
||||
|
||||
var $m_bLocalClr;
|
||||
|
||||
var $m_bInterlace;
|
||||
|
||||
var $m_bSorted;
|
||||
|
||||
var $m_nTableSize;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Gif\ColorTable
|
||||
*/
|
||||
var $m_colorTable;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
unset($this->m_nLeft);
|
||||
unset($this->m_nTop);
|
||||
unset($this->m_nWidth);
|
||||
unset($this->m_nHeight);
|
||||
unset($this->m_bLocalClr);
|
||||
unset($this->m_bInterlace);
|
||||
unset($this->m_bSorted);
|
||||
unset($this->m_nTableSize);
|
||||
unset($this->m_colorTable);
|
||||
}
|
||||
|
||||
function load($lpData, &$hdrLen)
|
||||
{
|
||||
$hdrLen = 0;
|
||||
|
||||
$this->m_nLeft = $this->w2i(substr($lpData, 0, 2));
|
||||
$this->m_nTop = $this->w2i(substr($lpData, 2, 2));
|
||||
$this->m_nWidth = $this->w2i(substr($lpData, 4, 2));
|
||||
$this->m_nHeight = $this->w2i(substr($lpData, 6, 2));
|
||||
|
||||
if (!$this->m_nWidth || !$this->m_nHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$b = ord($lpData[8]);
|
||||
$this->m_bLocalClr = ($b & 0x80) ? true : false;
|
||||
$this->m_bInterlace = ($b & 0x40) ? true : false;
|
||||
$this->m_bSorted = ($b & 0x20) ? true : false;
|
||||
$this->m_nTableSize = 2 << ($b & 0x07);
|
||||
$hdrLen = 9;
|
||||
|
||||
if ($this->m_bLocalClr) {
|
||||
$this->m_colorTable = new ColorTable();
|
||||
if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) {
|
||||
return false;
|
||||
}
|
||||
$hdrLen += 3 * $this->m_nTableSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function w2i($str)
|
||||
{
|
||||
return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8);
|
||||
}
|
||||
}
|
||||
236
Mpdf/Gif/Lzw.php
Normal file
236
Mpdf/Gif/Lzw.php
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Gif;
|
||||
|
||||
/**
|
||||
* GIF Util - (C) 2003 Yamasoft (S/C)
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This file can be freely copied, distributed, modified, updated by anyone under the only
|
||||
* condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
|
||||
*
|
||||
* @link http://www.yamasoft.com
|
||||
*/
|
||||
class Lzw
|
||||
{
|
||||
|
||||
var $MAX_LZW_BITS;
|
||||
|
||||
var $Fresh;
|
||||
var $CodeSize;
|
||||
var $SetCodeSize;
|
||||
var $MaxCode;
|
||||
var $MaxCodeSize;
|
||||
var $FirstCode;
|
||||
var $OldCode;
|
||||
|
||||
var $ClearCode;
|
||||
var $EndCode;
|
||||
var $Next;
|
||||
var $Vals;
|
||||
var $Stack;
|
||||
var $sp;
|
||||
var $Buf;
|
||||
var $CurBit;
|
||||
var $LastBit;
|
||||
var $Done;
|
||||
var $LastByte;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->MAX_LZW_BITS = 12;
|
||||
|
||||
unset($this->Next);
|
||||
unset($this->Vals);
|
||||
unset($this->Stack);
|
||||
unset($this->Buf);
|
||||
|
||||
$this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1);
|
||||
$this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1);
|
||||
$this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
|
||||
$this->Buf = range(0, 279);
|
||||
}
|
||||
|
||||
function deCompress($data, &$datLen)
|
||||
{
|
||||
$stLen = strlen($data);
|
||||
$datLen = 0;
|
||||
$ret = "";
|
||||
$dp = 0; // data pointer
|
||||
// INITIALIZATION
|
||||
$this->LZWCommandInit($data, $dp);
|
||||
|
||||
while (($iIndex = $this->LZWCommand($data, $dp)) >= 0) {
|
||||
$ret .= chr($iIndex);
|
||||
}
|
||||
|
||||
$datLen = $dp;
|
||||
|
||||
if ($iIndex != -2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function LZWCommandInit(&$data, &$dp)
|
||||
{
|
||||
$this->SetCodeSize = ord($data[0]);
|
||||
$dp += 1;
|
||||
|
||||
$this->CodeSize = $this->SetCodeSize + 1;
|
||||
$this->ClearCode = 1 << $this->SetCodeSize;
|
||||
$this->EndCode = $this->ClearCode + 1;
|
||||
$this->MaxCode = $this->ClearCode + 2;
|
||||
$this->MaxCodeSize = $this->ClearCode << 1;
|
||||
|
||||
$this->GetCodeInit($data, $dp);
|
||||
|
||||
$this->Fresh = 1;
|
||||
for ($i = 0; $i < $this->ClearCode; $i++) {
|
||||
$this->Next[$i] = 0;
|
||||
$this->Vals[$i] = $i;
|
||||
}
|
||||
|
||||
for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
|
||||
$this->Next[$i] = 0;
|
||||
$this->Vals[$i] = 0;
|
||||
}
|
||||
|
||||
$this->sp = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
function LZWCommand(&$data, &$dp)
|
||||
{
|
||||
if ($this->Fresh) {
|
||||
$this->Fresh = 0;
|
||||
do {
|
||||
$this->FirstCode = $this->GetCode($data, $dp);
|
||||
$this->OldCode = $this->FirstCode;
|
||||
} while ($this->FirstCode == $this->ClearCode);
|
||||
|
||||
return $this->FirstCode;
|
||||
}
|
||||
|
||||
if ($this->sp > 0) {
|
||||
$this->sp--;
|
||||
return $this->Stack[$this->sp];
|
||||
}
|
||||
|
||||
while (($Code = $this->GetCode($data, $dp)) >= 0) {
|
||||
if ($Code == $this->ClearCode) {
|
||||
for ($i = 0; $i < $this->ClearCode; $i++) {
|
||||
$this->Next[$i] = 0;
|
||||
$this->Vals[$i] = $i;
|
||||
}
|
||||
|
||||
for (; $i < (1 << $this->MAX_LZW_BITS); $i++) {
|
||||
$this->Next[$i] = 0;
|
||||
$this->Vals[$i] = 0;
|
||||
}
|
||||
|
||||
$this->CodeSize = $this->SetCodeSize + 1;
|
||||
$this->MaxCodeSize = $this->ClearCode << 1;
|
||||
$this->MaxCode = $this->ClearCode + 2;
|
||||
$this->sp = 0;
|
||||
$this->FirstCode = $this->GetCode($data, $dp);
|
||||
$this->OldCode = $this->FirstCode;
|
||||
|
||||
return $this->FirstCode;
|
||||
}
|
||||
|
||||
if ($Code == $this->EndCode) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
$InCode = $Code;
|
||||
if ($Code >= $this->MaxCode) {
|
||||
$this->Stack[$this->sp++] = $this->FirstCode;
|
||||
$Code = $this->OldCode;
|
||||
}
|
||||
|
||||
while ($Code >= $this->ClearCode) {
|
||||
$this->Stack[$this->sp++] = $this->Vals[$Code];
|
||||
|
||||
if ($Code == $this->Next[$Code]) { // Circular table entry, big GIF Error!
|
||||
return -1;
|
||||
}
|
||||
|
||||
$Code = $this->Next[$Code];
|
||||
}
|
||||
|
||||
$this->FirstCode = $this->Vals[$Code];
|
||||
$this->Stack[$this->sp++] = $this->FirstCode;
|
||||
|
||||
if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) {
|
||||
$this->Next[$Code] = $this->OldCode;
|
||||
$this->Vals[$Code] = $this->FirstCode;
|
||||
$this->MaxCode++;
|
||||
|
||||
if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) {
|
||||
$this->MaxCodeSize *= 2;
|
||||
$this->CodeSize++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->OldCode = $InCode;
|
||||
if ($this->sp > 0) {
|
||||
$this->sp--;
|
||||
return $this->Stack[$this->sp];
|
||||
}
|
||||
}
|
||||
|
||||
return $Code;
|
||||
}
|
||||
|
||||
function GetCodeInit(&$data, &$dp)
|
||||
{
|
||||
$this->CurBit = 0;
|
||||
$this->LastBit = 0;
|
||||
$this->Done = 0;
|
||||
$this->LastByte = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
function GetCode(&$data, &$dp)
|
||||
{
|
||||
if (($this->CurBit + $this->CodeSize) >= $this->LastBit) {
|
||||
if ($this->Done) {
|
||||
if ($this->CurBit >= $this->LastBit) {
|
||||
// Ran off the end of my bits
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
$this->Buf[0] = $this->Buf[$this->LastByte - 2];
|
||||
$this->Buf[1] = $this->Buf[$this->LastByte - 1];
|
||||
|
||||
$Count = ord($data[$dp]);
|
||||
$dp += 1;
|
||||
|
||||
if ($Count) {
|
||||
for ($i = 0; $i < $Count; $i++) {
|
||||
$this->Buf[2 + $i] = ord($data[$dp + $i]);
|
||||
}
|
||||
$dp += $Count;
|
||||
} else {
|
||||
$this->Done = 1;
|
||||
}
|
||||
|
||||
$this->LastByte = 2 + $Count;
|
||||
$this->CurBit = ($this->CurBit - $this->LastBit) + 16;
|
||||
$this->LastBit = (2 + $Count) << 3;
|
||||
}
|
||||
|
||||
$iRet = 0;
|
||||
for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) {
|
||||
$iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j;
|
||||
}
|
||||
|
||||
$this->CurBit += $this->CodeSize;
|
||||
return $iRet;
|
||||
}
|
||||
}
|
||||
975
Mpdf/Gradient.php
Normal file
975
Mpdf/Gradient.php
Normal file
|
|
@ -0,0 +1,975 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
use Mpdf\Color\ColorConverter;
|
||||
use Mpdf\Writer\BaseWriter;
|
||||
|
||||
class Gradient
|
||||
{
|
||||
|
||||
const TYPE_LINEAR = 2;
|
||||
const TYPE_RADIAL = 3;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\SizeConverter
|
||||
*/
|
||||
private $sizeConverter;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Color\ColorConverter
|
||||
*/
|
||||
private $colorConverter;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Writer\BaseWriter
|
||||
*/
|
||||
private $writer;
|
||||
|
||||
public function __construct(Mpdf $mpdf, SizeConverter $sizeConverter, ColorConverter $colorConverter, BaseWriter $writer)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->sizeConverter = $sizeConverter;
|
||||
$this->colorConverter = $colorConverter;
|
||||
$this->writer = $writer;
|
||||
}
|
||||
|
||||
// mPDF 5.3.A1
|
||||
public function CoonsPatchMesh($x, $y, $w, $h, $patch_array = [], $x_min = 0, $x_max = 1, $y_min = 0, $y_max = 1, $colspace = 'RGB', $return = false)
|
||||
{
|
||||
$s = ' q ';
|
||||
$s.=sprintf(' %.3F %.3F %.3F %.3F re W n ', $x * Mpdf::SCALE, ($this->mpdf->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$h * Mpdf::SCALE);
|
||||
$s.=sprintf(' %.3F 0 0 %.3F %.3F %.3F cm ', $w * Mpdf::SCALE, $h * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->mpdf->h - ($y + $h)) * Mpdf::SCALE);
|
||||
$n = count($this->mpdf->gradients) + 1;
|
||||
$this->mpdf->gradients[$n]['type'] = 6; //coons patch mesh
|
||||
$this->mpdf->gradients[$n]['colorspace'] = $colspace; //coons patch mesh
|
||||
$bpcd = 65535; //16 BitsPerCoordinate
|
||||
$trans = false;
|
||||
$this->mpdf->gradients[$n]['stream'] = '';
|
||||
for ($i = 0; $i < count($patch_array); $i++) {
|
||||
$this->mpdf->gradients[$n]['stream'].=chr($patch_array[$i]['f']); //start with the edge flag as 8 bit
|
||||
for ($j = 0; $j < count($patch_array[$i]['points']); $j++) {
|
||||
//each point as 16 bit
|
||||
if (($j % 2) == 1) { // Y coordinate (adjusted as input is From top left)
|
||||
$patch_array[$i]['points'][$j] = (($patch_array[$i]['points'][$j] - $y_min) / ($y_max - $y_min)) * $bpcd;
|
||||
$patch_array[$i]['points'][$j] = $bpcd - $patch_array[$i]['points'][$j];
|
||||
} else {
|
||||
$patch_array[$i]['points'][$j] = (($patch_array[$i]['points'][$j] - $x_min) / ($x_max - $x_min)) * $bpcd;
|
||||
}
|
||||
if ($patch_array[$i]['points'][$j] < 0) {
|
||||
$patch_array[$i]['points'][$j] = 0;
|
||||
}
|
||||
if ($patch_array[$i]['points'][$j] > $bpcd) {
|
||||
$patch_array[$i]['points'][$j] = $bpcd;
|
||||
}
|
||||
$this->mpdf->gradients[$n]['stream'].=chr(floor($patch_array[$i]['points'][$j] / 256));
|
||||
$this->mpdf->gradients[$n]['stream'].=chr(floor($patch_array[$i]['points'][$j] % 256));
|
||||
}
|
||||
for ($j = 0; $j < count($patch_array[$i]['colors']); $j++) {
|
||||
//each color component as 8 bit
|
||||
if ($colspace === 'RGB') {
|
||||
$this->mpdf->gradients[$n]['stream'].= $patch_array[$i]['colors'][$j][1];
|
||||
$this->mpdf->gradients[$n]['stream'].= $patch_array[$i]['colors'][$j][2];
|
||||
$this->mpdf->gradients[$n]['stream'].= $patch_array[$i]['colors'][$j][3];
|
||||
if (isset($patch_array[$i]['colors'][$j][4]) && ord($patch_array[$i]['colors'][$j][4]) < 100) {
|
||||
$trans = true;
|
||||
}
|
||||
} elseif ($colspace === 'CMYK') {
|
||||
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][1]) * 2.55);
|
||||
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][2]) * 2.55);
|
||||
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][3]) * 2.55);
|
||||
$this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][4]) * 2.55);
|
||||
if (isset($patch_array[$i]['colors'][$j][5]) && ord($patch_array[$i]['colors'][$j][5]) < 100) {
|
||||
$trans = true;
|
||||
}
|
||||
} elseif ($colspace === 'Gray') {
|
||||
$this->mpdf->gradients[$n]['stream'].= $patch_array[$i]['colors'][$j][1];
|
||||
if ($patch_array[$i]['colors'][$j][2] == 1) {
|
||||
$trans = true;
|
||||
} // transparency converted from rgba or cmyka()
|
||||
}
|
||||
}
|
||||
}
|
||||
// TRANSPARENCY
|
||||
if ($trans) {
|
||||
$this->mpdf->gradients[$n]['stream_trans'] = '';
|
||||
for ($i = 0; $i < count($patch_array); $i++) {
|
||||
$this->mpdf->gradients[$n]['stream_trans'].=chr($patch_array[$i]['f']);
|
||||
for ($j = 0; $j < count($patch_array[$i]['points']); $j++) {
|
||||
//each point as 16 bit
|
||||
$this->mpdf->gradients[$n]['stream_trans'].=chr(floor($patch_array[$i]['points'][$j] / 256));
|
||||
$this->mpdf->gradients[$n]['stream_trans'].=chr(floor($patch_array[$i]['points'][$j] % 256));
|
||||
}
|
||||
for ($j = 0; $j < count($patch_array[$i]['colors']); $j++) {
|
||||
//each color component as 8 bit // OPACITY
|
||||
if ($colspace === 'RGB') {
|
||||
$this->mpdf->gradients[$n]['stream_trans'].=chr((int) (ord($patch_array[$i]['colors'][$j][4]) * 2.55));
|
||||
} elseif ($colspace === 'CMYK') {
|
||||
$this->mpdf->gradients[$n]['stream_trans'].=chr((int) (ord($patch_array[$i]['colors'][$j][5]) * 2.55));
|
||||
} elseif ($colspace === 'Gray') {
|
||||
$this->mpdf->gradients[$n]['stream_trans'].=chr((int) (ord($patch_array[$i]['colors'][$j][3]) * 2.55));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->mpdf->gradients[$n]['trans'] = true;
|
||||
$s .= ' /TGS' . $n . ' gs ';
|
||||
}
|
||||
//paint the gradient
|
||||
$s .= '/Sh' . $n . ' sh' . "\n";
|
||||
//restore previous Graphic State
|
||||
$s .= 'Q' . "\n";
|
||||
if ($return) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
$this->writer->write($s);
|
||||
}
|
||||
|
||||
// type = linear:2; radial: 3;
|
||||
// Linear: $coords - array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg).
|
||||
// The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
|
||||
// Radial: $coords - array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1,
|
||||
// (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg).
|
||||
// (fx, fy) should be inside the circle, otherwise some areas will not be defined
|
||||
// $col = array(R,G,B/255); or array(G/255); or array(C,M,Y,K/100)
|
||||
// $stops = array('col'=>$col [, 'opacity'=>0-1] [, 'offset'=>0-1])
|
||||
public function Gradient($x, $y, $w, $h, $type, $stops = [], $colorspace = 'RGB', $coords = '', $extend = '', $return = false, $is_mask = false)
|
||||
{
|
||||
if (stripos($type, 'L') === 0) {
|
||||
$type = self::TYPE_LINEAR;
|
||||
} elseif (stripos($type, 'R') === 0) {
|
||||
$type = self::TYPE_RADIAL;
|
||||
}
|
||||
|
||||
if ($colorspace !== 'CMYK' && $colorspace !== 'Gray') {
|
||||
$colorspace = 'RGB';
|
||||
}
|
||||
$bboxw = $w;
|
||||
$bboxh = $h;
|
||||
$usex = $x;
|
||||
$usey = $y;
|
||||
$usew = $bboxw;
|
||||
$useh = $bboxh;
|
||||
|
||||
if ($type < 1) {
|
||||
$type = self::TYPE_LINEAR;
|
||||
}
|
||||
if ($coords[0] !== false && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $coords[0], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$coords[0] = $tmp / $w;
|
||||
}
|
||||
}
|
||||
if ($coords[1] !== false && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $coords[1], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$coords[1] = 1 - ($tmp / $h);
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == self::TYPE_LINEAR) {
|
||||
$angle = (isset($coords[4]) ? $coords[4] : false);
|
||||
$repeat = (isset($coords[5]) ? $coords[5] : false);
|
||||
// ALL POINTS SET (default for custom mPDF linear gradient) - no -moz
|
||||
if ($coords[0] !== false && $coords[1] !== false && $coords[2] !== false && $coords[3] !== false) {
|
||||
// do nothing - coords used as they are
|
||||
} elseif ($angle !== false && $coords[0] !== false && $coords[1] !== false && $coords[2] === false && $coords[3] === false) {
|
||||
// If both a <point> and <angle> are defined, the gradient axis starts from the point and runs along the angle. The end point is
|
||||
// defined as before - in this case start points may not be in corners, and axis may not correctly fall in the right quadrant.
|
||||
// NO end points (Angle defined & Start points)
|
||||
if ($angle == 0 || $angle == 360) {
|
||||
$coords[3] = $coords[1];
|
||||
if ($coords[0] == 1) {
|
||||
$coords[2] = 2;
|
||||
} else {
|
||||
$coords[2] = 1;
|
||||
}
|
||||
} elseif ($angle == 90) {
|
||||
$coords[2] = $coords[0];
|
||||
$coords[3] = 1;
|
||||
if ($coords[1] == 1) {
|
||||
$coords[3] = 2;
|
||||
} else {
|
||||
$coords[3] = 1;
|
||||
}
|
||||
} elseif ($angle == 180) {
|
||||
if ($coords[4] == 0) {
|
||||
$coords[2] = -1;
|
||||
} else {
|
||||
$coords[2] = 0;
|
||||
}
|
||||
$coords[3] = $coords[1];
|
||||
} elseif ($angle == 270) {
|
||||
$coords[2] = $coords[0];
|
||||
if ($coords[1] == 0) {
|
||||
$coords[3] = -1;
|
||||
} else {
|
||||
$coords[3] = 0;
|
||||
}
|
||||
} else {
|
||||
$endx = 1;
|
||||
$endy = 1;
|
||||
if ($angle <= 90) {
|
||||
if ($angle <= 45) {
|
||||
$endy = tan(deg2rad($angle));
|
||||
} else {
|
||||
$endx = tan(deg2rad(90 - $angle));
|
||||
}
|
||||
$b = atan2($endy * $bboxh, $endx * $bboxw);
|
||||
$ny = 1 - $coords[1] - (tan($b) * (1 - $coords[0]));
|
||||
$tx = sin($b) * cos($b) * $ny;
|
||||
$ty = cos($b) * cos($b) * $ny;
|
||||
$coords[2] = 1 + $tx;
|
||||
$coords[3] = 1 - $ty;
|
||||
} elseif ($angle <= 180) {
|
||||
if ($angle <= 135) {
|
||||
$endx = tan(deg2rad($angle - 90));
|
||||
} else {
|
||||
$endy = tan(deg2rad(180 - $angle));
|
||||
}
|
||||
$b = atan2($endy * $bboxh, $endx * $bboxw);
|
||||
$ny = 1 - $coords[1] - (tan($b) * $coords[0]);
|
||||
$tx = sin($b) * cos($b) * $ny;
|
||||
$ty = cos($b) * cos($b) * $ny;
|
||||
$coords[2] = -$tx;
|
||||
$coords[3] = 1 - $ty;
|
||||
} elseif ($angle <= 270) {
|
||||
if ($angle <= 225) {
|
||||
$endy = tan(deg2rad($angle - 180));
|
||||
} else {
|
||||
$endx = tan(deg2rad(270 - $angle));
|
||||
}
|
||||
$b = atan2($endy * $bboxh, $endx * $bboxw);
|
||||
$ny = $coords[1] - (tan($b) * $coords[0]);
|
||||
$tx = sin($b) * cos($b) * $ny;
|
||||
$ty = cos($b) * cos($b) * $ny;
|
||||
$coords[2] = -$tx;
|
||||
$coords[3] = $ty;
|
||||
} else {
|
||||
if ($angle <= 315) {
|
||||
$endx = tan(deg2rad($angle - 270));
|
||||
} else {
|
||||
$endy = tan(deg2rad(360 - $angle));
|
||||
}
|
||||
$b = atan2($endy * $bboxh, $endx * $bboxw);
|
||||
$ny = $coords[1] - (tan($b) * (1 - $coords[0]));
|
||||
$tx = sin($b) * cos($b) * $ny;
|
||||
$ty = cos($b) * cos($b) * $ny;
|
||||
$coords[2] = 1 + $tx;
|
||||
$coords[3] = $ty;
|
||||
}
|
||||
}
|
||||
} elseif ($angle !== false && $coords[0] === false && $coords[1] === false) {
|
||||
// -moz If the first parameter is only an <angle>, the gradient axis starts from the box's corner that would ensure the
|
||||
// axis goes through the box. The axis runs along the specified angle. The end point of the axis is defined such that the
|
||||
// farthest corner of the box from the starting point is perpendicular to the gradient axis at that point.
|
||||
// NO end points or Start points (Angle defined)
|
||||
if ($angle == 0 || $angle == 360) {
|
||||
$coords[0] = 0;
|
||||
$coords[1] = 0;
|
||||
$coords[2] = 1;
|
||||
$coords[3] = 0;
|
||||
} elseif ($angle == 90) {
|
||||
$coords[0] = 0;
|
||||
$coords[1] = 0;
|
||||
$coords[2] = 0;
|
||||
$coords[3] = 1;
|
||||
} elseif ($angle == 180) {
|
||||
$coords[0] = 1;
|
||||
$coords[1] = 0;
|
||||
$coords[2] = 0;
|
||||
$coords[3] = 0;
|
||||
} elseif ($angle == 270) {
|
||||
$coords[0] = 0;
|
||||
$coords[1] = 1;
|
||||
$coords[2] = 0;
|
||||
$coords[3] = 0;
|
||||
} else {
|
||||
if ($angle <= 90) {
|
||||
$coords[0] = 0;
|
||||
$coords[1] = 0;
|
||||
if ($angle <= 45) {
|
||||
$endx = 1;
|
||||
$endy = tan(deg2rad($angle));
|
||||
} else {
|
||||
$endx = tan(deg2rad(90 - $angle));
|
||||
$endy = 1;
|
||||
}
|
||||
} elseif ($angle <= 180) {
|
||||
$coords[0] = 1;
|
||||
$coords[1] = 0;
|
||||
if ($angle <= 135) {
|
||||
$endx = tan(deg2rad($angle - 90));
|
||||
$endy = 1;
|
||||
} else {
|
||||
$endx = 1;
|
||||
$endy = tan(deg2rad(180 - $angle));
|
||||
}
|
||||
} elseif ($angle <= 270) {
|
||||
$coords[0] = 1;
|
||||
$coords[1] = 1;
|
||||
if ($angle <= 225) {
|
||||
$endx = 1;
|
||||
$endy = tan(deg2rad($angle - 180));
|
||||
} else {
|
||||
$endx = tan(deg2rad(270 - $angle));
|
||||
$endy = 1;
|
||||
}
|
||||
} else {
|
||||
$coords[0] = 0;
|
||||
$coords[1] = 1;
|
||||
if ($angle <= 315) {
|
||||
$endx = tan(deg2rad($angle - 270));
|
||||
$endy = 1;
|
||||
} else {
|
||||
$endx = 1;
|
||||
$endy = tan(deg2rad(360 - $angle));
|
||||
}
|
||||
}
|
||||
$b = atan2($endy * $bboxh, $endx * $bboxw);
|
||||
$h2 = $bboxh - ($bboxh * tan($b));
|
||||
$px = $bboxh + ($h2 * sin($b) * cos($b));
|
||||
$py = ($bboxh * tan($b)) + ($h2 * sin($b) * sin($b));
|
||||
$x1 = $px / $bboxh;
|
||||
$y1 = $py / $bboxh;
|
||||
if ($angle <= 90) {
|
||||
$coords[2] = $x1;
|
||||
$coords[3] = $y1;
|
||||
} elseif ($angle <= 180) {
|
||||
$coords[2] = 1 - $x1;
|
||||
$coords[3] = $y1;
|
||||
} elseif ($angle <= 270) {
|
||||
$coords[2] = 1 - $x1;
|
||||
$coords[3] = 1 - $y1;
|
||||
} else {
|
||||
$coords[2] = $x1;
|
||||
$coords[3] = 1 - $y1;
|
||||
}
|
||||
}
|
||||
} elseif ((!isset($angle) || $angle === false) && $coords[0] !== false && $coords[1] !== false) {
|
||||
// -moz If the first parameter to the gradient function is only a <point>, the gradient axis starts from the specified point,
|
||||
// and ends at the point you would get if you rotated the starting point by 180 degrees about the center of the box that the
|
||||
// gradient is to be applied to.
|
||||
// NO angle and NO end points (Start points defined)
|
||||
$coords[2] = 1 - $coords[0];
|
||||
$coords[3] = 1 - $coords[1];
|
||||
$angle = rad2deg(atan2($coords[3] - $coords[1], $coords[2] - $coords[0]));
|
||||
if ($angle < 0) {
|
||||
$angle += 360;
|
||||
} elseif ($angle > 360) {
|
||||
$angle -= 360;
|
||||
}
|
||||
if ($angle != 0 && $angle != 360 && $angle != 90 && $angle != 180 && $angle != 270) {
|
||||
if ($w >= $h) {
|
||||
$coords[1] *= $h / $w;
|
||||
$coords[3] *= $h / $w;
|
||||
$usew = $useh = $bboxw;
|
||||
$usey -= ($w - $h);
|
||||
} else {
|
||||
$coords[0] *= $w / $h;
|
||||
$coords[2] *= $w / $h;
|
||||
$usew = $useh = $bboxh;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// default values T2B
|
||||
// -moz If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient
|
||||
// axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box.
|
||||
// All values are set in parseMozGradient - so won't appear here
|
||||
$coords = [0, 0, 1, 0]; // default for original linear gradient (L2R)
|
||||
}
|
||||
} elseif ($type == self::TYPE_RADIAL) {
|
||||
$radius = (isset($coords[4]) ? $coords[4] : false);
|
||||
$shape = (isset($coords[6]) ? $coords[6] : false);
|
||||
$size = (isset($coords[7]) ? $coords[7] : false);
|
||||
$repeat = (isset($coords[8]) ? $coords[8] : false);
|
||||
// ALL POINTS AND RADIUS SET (default for custom mPDF radial gradient) - no -moz
|
||||
if ($coords[0] !== false && $coords[1] !== false && $coords[2] !== false && $coords[3] !== false && $coords[4] !== false) {
|
||||
// If a <point> is defined
|
||||
// do nothing - coords used as they are
|
||||
} elseif ($shape !== false && $size !== false) {
|
||||
if ($coords[2] == false) {
|
||||
$coords[2] = $coords[0];
|
||||
}
|
||||
if ($coords[3] == false) {
|
||||
$coords[3] = $coords[1];
|
||||
}
|
||||
// ELLIPSE
|
||||
if ($shape === 'ellipse') {
|
||||
$corner1 = sqrt(($coords[0] ** 2) + ($coords[1] ** 2));
|
||||
$corner2 = sqrt(($coords[0] ** 2) + ((1 - $coords[1]) ** 2));
|
||||
$corner3 = sqrt(((1 - $coords[0]) ** 2) + ($coords[1] ** 2));
|
||||
$corner4 = sqrt(((1 - $coords[0]) ** 2) + ((1 - $coords[1]) ** 2));
|
||||
if ($size === 'closest-side') {
|
||||
$radius = min($coords[0], $coords[1], 1 - $coords[0], 1 - $coords[1]);
|
||||
} elseif ($size === 'closest-corner') {
|
||||
$radius = min($corner1, $corner2, $corner3, $corner4);
|
||||
} elseif ($size === 'farthest-side') {
|
||||
$radius = max($coords[0], $coords[1], 1 - $coords[0], 1 - $coords[1]);
|
||||
} else {
|
||||
$radius = max($corner1, $corner2, $corner3, $corner4);
|
||||
} // farthest corner (default)
|
||||
} elseif ($shape === 'circle') {
|
||||
if ($w >= $h) {
|
||||
$coords[1] = $coords[3] = ($coords[1] * $h / $w);
|
||||
$corner1 = sqrt(($coords[0] ** 2) + ($coords[1] ** 2));
|
||||
$corner2 = sqrt(($coords[0] ** 2) + ((($h / $w) - $coords[1]) ** 2));
|
||||
$corner3 = sqrt(((1 - $coords[0]) ** 2) + ($coords[1] ** 2));
|
||||
$corner4 = sqrt(((1 - $coords[0]) ** 2) + ((($h / $w) - $coords[1]) ** 2));
|
||||
if ($size === 'closest-side') {
|
||||
$radius = min($coords[0], $coords[1], 1 - $coords[0], ($h / $w) - $coords[1]);
|
||||
} elseif ($size === 'closest-corner') {
|
||||
$radius = min($corner1, $corner2, $corner3, $corner4);
|
||||
} elseif ($size === 'farthest-side') {
|
||||
$radius = max($coords[0], $coords[1], 1 - $coords[0], ($h / $w) - $coords[1]);
|
||||
} elseif ($size === 'farthest-corner') {
|
||||
$radius = max($corner1, $corner2, $corner3, $corner4);
|
||||
} // farthest corner (default)
|
||||
$usew = $useh = $bboxw;
|
||||
$usey -= ($w - $h);
|
||||
} else {
|
||||
$coords[0] = $coords[2] = ($coords[0] * $w / $h);
|
||||
$corner1 = sqrt(($coords[0] ** 2) + ($coords[1] ** 2));
|
||||
$corner2 = sqrt(($coords[0] ** 2) + ((1 - $coords[1]) ** 2));
|
||||
$corner3 = sqrt(((($w / $h) - $coords[0]) ** 2) + ($coords[1] ** 2));
|
||||
$corner4 = sqrt(((($w / $h) - $coords[0]) ** 2) + ((1 - $coords[1]) ** 2));
|
||||
if ($size === 'closest-side') {
|
||||
$radius = min($coords[0], $coords[1], ($w / $h) - $coords[0], 1 - $coords[1]);
|
||||
} elseif ($size === 'closest-corner') {
|
||||
$radius = min($corner1, $corner2, $corner3, $corner4);
|
||||
} elseif ($size === 'farthest-side') {
|
||||
$radius = max($coords[0], $coords[1], ($w / $h) - $coords[0], 1 - $coords[1]);
|
||||
} elseif ($size === 'farthest-corner') {
|
||||
$radius = max($corner1, $corner2, $corner3, $corner4);
|
||||
} // farthest corner (default)
|
||||
$usew = $useh = $bboxh;
|
||||
}
|
||||
}
|
||||
if ($radius == 0) {
|
||||
$radius = 0.001;
|
||||
} // to prevent error
|
||||
$coords[4] = $radius;
|
||||
} else {
|
||||
// -moz If entire function consists of only <stop> values
|
||||
// All values are set in parseMozGradient - so won't appear here
|
||||
$coords = [0.5, 0.5, 0.5, 0.5]; // default for radial gradient (centred)
|
||||
}
|
||||
}
|
||||
$s = ' q';
|
||||
$s .= sprintf(' %.3F %.3F %.3F %.3F re W n', $x * Mpdf::SCALE, ($this->mpdf->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$h * Mpdf::SCALE) . "\n";
|
||||
$s .= sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $usew * Mpdf::SCALE, $useh * Mpdf::SCALE, $usex * Mpdf::SCALE, ($this->mpdf->h - ($usey + $useh)) * Mpdf::SCALE) . "\n";
|
||||
|
||||
$n = count($this->mpdf->gradients) + 1;
|
||||
$this->mpdf->gradients[$n]['type'] = $type;
|
||||
$this->mpdf->gradients[$n]['colorspace'] = $colorspace;
|
||||
$trans = false;
|
||||
$this->mpdf->gradients[$n]['is_mask'] = $is_mask;
|
||||
if ($is_mask) {
|
||||
$trans = true;
|
||||
}
|
||||
if (count($stops) == 1) {
|
||||
$stops[1] = $stops[0];
|
||||
}
|
||||
if (!isset($stops[0]['offset'])) {
|
||||
$stops[0]['offset'] = 0;
|
||||
}
|
||||
if (!isset($stops[count($stops) - 1]['offset'])) {
|
||||
$stops[count($stops) - 1]['offset'] = 1;
|
||||
}
|
||||
|
||||
// Fix stop-offsets set as absolute lengths
|
||||
if ($type == self::TYPE_LINEAR) {
|
||||
$axisx = ($coords[2] - $coords[0]) * $usew;
|
||||
$axisy = ($coords[3] - $coords[1]) * $useh;
|
||||
$axis_length = sqrt(($axisx ** 2) + ($axisy ** 2));
|
||||
} else {
|
||||
$axis_length = $coords[4] * $usew;
|
||||
} // Absolute lengths are meaningless for an ellipse - Firefox uses Width as reference
|
||||
|
||||
for ($i = 0; $i < count($stops); $i++) {
|
||||
if (isset($stops[$i]['offset']) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $stops[$i]['offset'], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
$stops[$i]['offset'] = $tmp / $axis_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($stops[0]['offset']) && $stops[0]['offset'] > 0) {
|
||||
$firststop = $stops[0];
|
||||
$firststop['offset'] = 0;
|
||||
array_unshift($stops, $firststop);
|
||||
}
|
||||
if (!$repeat && isset($stops[count($stops) - 1]['offset']) && $stops[count($stops) - 1]['offset'] < 1) {
|
||||
$endstop = $stops[count($stops) - 1];
|
||||
$endstop['offset'] = 1;
|
||||
$stops[] = $endstop;
|
||||
}
|
||||
if ($stops[0]['offset'] > $stops[count($stops) - 1]['offset']) {
|
||||
$stops[0]['offset'] = 0;
|
||||
$stops[count($stops) - 1]['offset'] = 1;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($stops); $i++) {
|
||||
// mPDF 5.3.74
|
||||
if ($colorspace === 'CMYK') {
|
||||
$this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F %.3F %.3F %.3F', ord($stops[$i]['col'][1]) / 100, ord($stops[$i]['col'][2]) / 100, ord($stops[$i]['col'][3]) / 100, ord($stops[$i]['col'][4]) / 100);
|
||||
} elseif ($colorspace === 'Gray') {
|
||||
$this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F', ord($stops[$i]['col'][1]) / 255);
|
||||
} else {
|
||||
$this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F %.3F %.3F', ord($stops[$i]['col'][1]) / 255, ord($stops[$i]['col'][2]) / 255, ord($stops[$i]['col'][3]) / 255);
|
||||
}
|
||||
if (!isset($stops[$i]['opacity'])) {
|
||||
$stops[$i]['opacity'] = 1;
|
||||
} elseif ($stops[$i]['opacity'] > 1 || $stops[$i]['opacity'] < 0) {
|
||||
$stops[$i]['opacity'] = 1;
|
||||
} elseif ($stops[$i]['opacity'] < 1) {
|
||||
$trans = true;
|
||||
}
|
||||
$this->mpdf->gradients[$n]['stops'][$i]['opacity'] = $stops[$i]['opacity'];
|
||||
// OFFSET
|
||||
if ($i > 0 && $i < (count($stops) - 1)) {
|
||||
if (!isset($stops[$i]['offset']) || (isset($stops[$i + 1]['offset']) && $stops[$i]['offset'] > $stops[$i + 1]['offset']) || $stops[$i]['offset'] < $stops[$i - 1]['offset']) {
|
||||
if (isset($stops[$i - 1]['offset']) && isset($stops[$i + 1]['offset'])) {
|
||||
$stops[$i]['offset'] = ($stops[$i - 1]['offset'] + $stops[$i + 1]['offset']) / 2;
|
||||
} else {
|
||||
for ($j = ($i + 1); $j < count($stops); $j++) {
|
||||
if (isset($stops[$j]['offset'])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$int = ($stops[$j]['offset'] - $stops[$i - 1]['offset']) / ($j - $i + 1);
|
||||
for ($f = 0; $f < ($j - $i - 1); $f++) {
|
||||
$stops[$i + $f]['offset'] = $stops[$i + $f - 1]['offset'] + $int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->mpdf->gradients[$n]['stops'][$i]['offset'] = $stops[$i]['offset'];
|
||||
}
|
||||
|
||||
if ($repeat) {
|
||||
$ns = count($this->mpdf->gradients[$n]['stops']);
|
||||
$offs = [];
|
||||
for ($i = 0; $i < $ns; $i++) {
|
||||
$offs[$i] = $this->mpdf->gradients[$n]['stops'][$i]['offset'];
|
||||
}
|
||||
$gp = 0;
|
||||
$inside = true;
|
||||
while ($inside) {
|
||||
$gp++;
|
||||
for ($i = 0; $i < $ns; $i++) {
|
||||
$this->mpdf->gradients[$n]['stops'][($ns * $gp) + $i] = $this->mpdf->gradients[$n]['stops'][($ns * ($gp - 1)) + $i];
|
||||
$tmp = $this->mpdf->gradients[$n]['stops'][($ns * ($gp - 1)) + ($ns - 1)]['offset'] + $offs[$i];
|
||||
if ($tmp < 1) {
|
||||
$this->mpdf->gradients[$n]['stops'][($ns * $gp) + $i]['offset'] = $tmp;
|
||||
} else {
|
||||
$this->mpdf->gradients[$n]['stops'][($ns * $gp) + $i]['offset'] = 1;
|
||||
$inside = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($trans) {
|
||||
$this->mpdf->gradients[$n]['trans'] = true;
|
||||
$s .= ' /TGS' . $n . ' gs ';
|
||||
}
|
||||
if (!is_array($extend) || count($extend) < 1) {
|
||||
$extend = ['true', 'true']; // These are supposed to be quoted - appear in PDF file as text
|
||||
}
|
||||
$this->mpdf->gradients[$n]['coords'] = $coords;
|
||||
$this->mpdf->gradients[$n]['extend'] = $extend;
|
||||
//paint the gradient
|
||||
$s .= '/Sh' . $n . ' sh ' . "\n";
|
||||
//restore previous Graphic State
|
||||
$s .= ' Q ' . "\n";
|
||||
if ($return) {
|
||||
return $s;
|
||||
}
|
||||
|
||||
$this->writer->write($s);
|
||||
}
|
||||
|
||||
private function parseMozLinearGradient($m, $repeat)
|
||||
{
|
||||
$g = [];
|
||||
$g['type'] = self::TYPE_LINEAR;
|
||||
$g['colorspace'] = 'RGB';
|
||||
$g['extend'] = ['true', 'true'];
|
||||
$v = trim($m[1]);
|
||||
// Change commas inside e.g. rgb(x,x,x)
|
||||
while (preg_match('/(\([^\)]*?),/', $v)) {
|
||||
$v = preg_replace('/(\([^\)]*?),/', '\\1@', $v);
|
||||
}
|
||||
// Remove spaces inside e.g. rgb(x, x, x)
|
||||
while (preg_match('/(\([^\)]*?)[ ]/', $v)) {
|
||||
$v = preg_replace('/(\([^\)]*?)[ ]/', '\\1', $v);
|
||||
}
|
||||
$bgr = preg_split('/\s*,\s*/', $v);
|
||||
for ($i = 0; $i < count($bgr); $i++) {
|
||||
$bgr[$i] = preg_replace('/@/', ',', $bgr[$i]);
|
||||
}
|
||||
// Is first part $bgr[0] a valid point/angle?
|
||||
$first = preg_split('/\s+/', trim($bgr[0]));
|
||||
if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) {
|
||||
$startStops = 1;
|
||||
} elseif (trim($first[count($first) - 1]) === '0') {
|
||||
$startStops = 1;
|
||||
} else {
|
||||
$check = $this->colorConverter->convert($first[0], $this->mpdf->PDFAXwarnings);
|
||||
$startStops = 1;
|
||||
if ($check) {
|
||||
$startStops = 0;
|
||||
}
|
||||
}
|
||||
// first part a valid point/angle?
|
||||
if ($startStops === 1) { // default values
|
||||
// [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,]
|
||||
if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $bgr[0], $m)) {
|
||||
$angle = $m[1] + 0;
|
||||
if (strtolower($m[2]) === 'grad') {
|
||||
$angle *= (360 / 400);
|
||||
} elseif (strtolower($m[2]) === 'rad') {
|
||||
$angle = rad2deg($angle);
|
||||
}
|
||||
while ($angle < 0) {
|
||||
$angle += 360;
|
||||
}
|
||||
$angle %= 360;
|
||||
} elseif (trim($first[count($first) - 1]) === '0') {
|
||||
$angle = 0;
|
||||
}
|
||||
if (stripos($bgr[0], 'left') !== false) {
|
||||
$startx = 0;
|
||||
} elseif (stripos($bgr[0], 'right') !== false) {
|
||||
$startx = 1;
|
||||
}
|
||||
if (stripos($bgr[0], 'top') !== false) {
|
||||
$starty = 1;
|
||||
} elseif (stripos($bgr[0], 'bottom') !== false) {
|
||||
$starty = 0;
|
||||
}
|
||||
// Check for %? ?% or %%
|
||||
if (preg_match('/(\d+)[%]/i', $first[0], $m)) {
|
||||
$startx = $m[1] / 100;
|
||||
} elseif (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$startx = $m[1];
|
||||
}
|
||||
}
|
||||
if (isset($first[1]) && preg_match('/(\d+)[%]/i', $first[1], $m)) {
|
||||
$starty = 1 - ($m[1] / 100);
|
||||
} elseif (!isset($starty) && isset($first[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$starty = $m[1];
|
||||
}
|
||||
}
|
||||
if (isset($startx) && !isset($starty)) {
|
||||
$starty = 0.5;
|
||||
}
|
||||
if (!isset($startx) && isset($starty)) {
|
||||
$startx = 0.5;
|
||||
}
|
||||
} else {
|
||||
// If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values,
|
||||
// the gradient axis starts from the top of the box and runs vertically downwards, ending at the bottom of
|
||||
// the box.
|
||||
$starty = 1;
|
||||
$startx = 0.5;
|
||||
$endy = 0;
|
||||
$endx = 0.5;
|
||||
}
|
||||
if (!isset($startx)) {
|
||||
$startx = false;
|
||||
}
|
||||
if (!isset($starty)) {
|
||||
$starty = false;
|
||||
}
|
||||
if (!isset($endx)) {
|
||||
$endx = false;
|
||||
}
|
||||
if (!isset($endy)) {
|
||||
$endy = false;
|
||||
}
|
||||
if (!isset($angle)) {
|
||||
$angle = false;
|
||||
}
|
||||
$g['coords'] = [$startx, $starty, $endx, $endy, $angle, $repeat];
|
||||
$g['stops'] = [];
|
||||
for ($i = $startStops; $i < count($bgr); $i++) {
|
||||
// parse stops
|
||||
$el = preg_split('/\s+/', trim($bgr[$i]));
|
||||
// mPDF 5.3.74
|
||||
$col = $this->colorConverter->convert($el[0], $this->mpdf->PDFAXwarnings);
|
||||
if (!$col) {
|
||||
$col = $this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings);
|
||||
}
|
||||
if ($col[0] == 1) {
|
||||
$g['colorspace'] = 'Gray';
|
||||
} elseif ($col[0] == 4 || $col[0] == 6) {
|
||||
$g['colorspace'] = 'CMYK';
|
||||
}
|
||||
|
||||
$g['stops'][] = $this->getStop($col, $el, true);
|
||||
}
|
||||
return $g;
|
||||
}
|
||||
|
||||
private function parseMozRadialGradient($m, $repeat)
|
||||
{
|
||||
$g = [];
|
||||
$g['type'] = self::TYPE_RADIAL;
|
||||
$g['colorspace'] = 'RGB';
|
||||
$g['extend'] = ['true', 'true'];
|
||||
$v = trim($m[1]);
|
||||
// Change commas inside e.g. rgb(x,x,x)
|
||||
while (preg_match('/(\([^\)]*?),/', $v)) {
|
||||
$v = preg_replace('/(\([^\)]*?),/', '\\1@', $v);
|
||||
}
|
||||
// Remove spaces inside e.g. rgb(x, x, x)
|
||||
while (preg_match('/(\([^\)]*?)[ ]/', $v)) {
|
||||
$v = preg_replace('/(\([^\)]*?)[ ]/', '\\1', $v);
|
||||
}
|
||||
$bgr = preg_split('/\s*,\s*/', $v);
|
||||
for ($i = 0; $i < count($bgr); $i++) {
|
||||
$bgr[$i] = preg_replace('/@/', ',', $bgr[$i]);
|
||||
}
|
||||
|
||||
// Is first part $bgr[0] a valid point/angle?
|
||||
$startStops = 0;
|
||||
$pos_angle = false;
|
||||
$shape_size = false;
|
||||
$first = preg_split('/\s+/', trim($bgr[0]));
|
||||
$checkCol = $this->colorConverter->convert($first[0], $this->mpdf->PDFAXwarnings);
|
||||
if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) {
|
||||
$startStops = 1;
|
||||
$pos_angle = $bgr[0];
|
||||
} elseif (trim($first[count($first) - 1]) === '0') {
|
||||
$startStops = 1;
|
||||
$pos_angle = $bgr[0];
|
||||
} elseif (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[0])) {
|
||||
$startStops = 1;
|
||||
$shape_size = $bgr[0];
|
||||
} elseif (!$checkCol) {
|
||||
$startStops = 1;
|
||||
$pos_angle = $bgr[0];
|
||||
}
|
||||
if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[1])) {
|
||||
$startStops = 2;
|
||||
$shape_size = $bgr[1];
|
||||
}
|
||||
|
||||
// If valid point/angle?
|
||||
if ($pos_angle) { // default values
|
||||
// [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,]
|
||||
if (stripos($pos_angle, 'left') !== false) {
|
||||
$startx = 0;
|
||||
} elseif (stripos($pos_angle, 'right') !== false) {
|
||||
$startx = 1;
|
||||
}
|
||||
if (stripos($pos_angle, 'top') !== false) {
|
||||
$starty = 1;
|
||||
} elseif (stripos($pos_angle, 'bottom') !== false) {
|
||||
$starty = 0;
|
||||
}
|
||||
// Check for %? ?% or %%
|
||||
if (preg_match('/(\d+)[%]/i', $first[0], $m)) {
|
||||
$startx = $m[1] / 100;
|
||||
} elseif (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$startx = $m[1];
|
||||
}
|
||||
}
|
||||
if (isset($first[1]) && preg_match('/(\d+)[%]/i', $first[1], $m)) {
|
||||
$starty = 1 - ($m[1] / 100);
|
||||
} elseif (!isset($starty) && isset($first[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$starty = $m[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($starty)) {
|
||||
$starty = 0.5;
|
||||
}
|
||||
if (!isset($startx)) {
|
||||
$startx = 0.5;
|
||||
}
|
||||
} else {
|
||||
// If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values,
|
||||
// the gradient axis starts from the top of the box and runs vertically downwards, ending at the bottom of
|
||||
// the box. default values Center
|
||||
$starty = 0.5;
|
||||
$startx = 0.5;
|
||||
$endy = 0.5;
|
||||
$endx = 0.5;
|
||||
}
|
||||
|
||||
// If valid shape/size?
|
||||
$shape = 'ellipse'; // default
|
||||
$size = 'farthest-corner'; // default
|
||||
if ($shape_size) { // default values
|
||||
if (preg_match('/(circle|ellipse)/i', $shape_size, $m)) {
|
||||
$shape = $m[1];
|
||||
}
|
||||
if (preg_match('/(closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $shape_size, $m)) {
|
||||
$size = $m[1];
|
||||
if ($size === 'contain') {
|
||||
$size = 'closest-side';
|
||||
} elseif ($size === 'cover') {
|
||||
$size = 'farthest-corner';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($startx)) {
|
||||
$startx = false;
|
||||
}
|
||||
if (!isset($starty)) {
|
||||
$starty = false;
|
||||
}
|
||||
if (!isset($endx)) {
|
||||
$endx = false;
|
||||
}
|
||||
if (!isset($endy)) {
|
||||
$endy = false;
|
||||
}
|
||||
$radius = false;
|
||||
$angle = 0;
|
||||
$g['coords'] = [$startx, $starty, $endx, $endy, $radius, $angle, $shape, $size, $repeat];
|
||||
|
||||
$g['stops'] = [];
|
||||
for ($i = $startStops; $i < count($bgr); $i++) {
|
||||
// parse stops
|
||||
$el = preg_split('/\s+/', trim($bgr[$i]));
|
||||
// mPDF 5.3.74
|
||||
$col = $this->colorConverter->convert($el[0], $this->mpdf->PDFAXwarnings);
|
||||
if (!$col) {
|
||||
$col = $this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings);
|
||||
}
|
||||
if ($col[0] == 1) {
|
||||
$g['colorspace'] = 'Gray';
|
||||
} elseif ($col[0] == 4 || $col[0] == 6) {
|
||||
$g['colorspace'] = 'CMYK';
|
||||
}
|
||||
$g['stops'][] = $this->getStop($col, $el);
|
||||
}
|
||||
return $g;
|
||||
}
|
||||
|
||||
private function getStop($col, $el, $convertOffset = false)
|
||||
{
|
||||
$stop = [
|
||||
'col' => $col,
|
||||
];
|
||||
|
||||
if ($col[0] == 5) {
|
||||
// transparency from rgba()
|
||||
$stop['opacity'] = ord($col[4]) / 100;
|
||||
} elseif ($col[0] == 6) {
|
||||
// transparency from cmyka()
|
||||
$stop['opacity'] = ord($col[5]) / 100;
|
||||
} elseif ($col[0] == 1 && $col[2] == 1) {
|
||||
// transparency converted from rgba or cmyka()
|
||||
$stop['opacity'] = ord($col[3]) / 100;
|
||||
}
|
||||
|
||||
if (isset($el[1])) {
|
||||
if (preg_match('/(\d+)[%]/', $el[1], $m)) {
|
||||
$stop['offset'] = $m[1] / 100;
|
||||
if ($stop['offset'] > 1) {
|
||||
unset($stop['offset']);
|
||||
}
|
||||
} elseif (preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) {
|
||||
if ($convertOffset) {
|
||||
$tmp = $this->sizeConverter->convert($m[1], $this->mpdf->w, $this->mpdf->FontSize, false);
|
||||
if ($tmp) {
|
||||
$stop['offset'] = $m[1];
|
||||
}
|
||||
} else {
|
||||
$stop['offset'] = $el[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $stop;
|
||||
}
|
||||
|
||||
public function parseMozGradient($bg)
|
||||
{
|
||||
// background[-image]: -moz-linear-gradient(left, #c7Fdde 20%, #FF0000 );
|
||||
// background[-image]: linear-gradient(left, #c7Fdde 20%, #FF0000 ); // CSS3
|
||||
$repeat = strpos($bg, 'repeating-') !== false;
|
||||
|
||||
if (preg_match('/linear-gradient\((.*)\)/', $bg, $m)) {
|
||||
$g = $this->parseMozLinearGradient($m, $repeat);
|
||||
if (count($g['stops'])) {
|
||||
return $g;
|
||||
}
|
||||
} elseif (preg_match('/radial-gradient\((.*)\)/', $bg, $m)) {
|
||||
$g = $this->parseMozRadialGradient($m, $repeat);
|
||||
if (count($g['stops'])) {
|
||||
return $g;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function parseBackgroundGradient($bg)
|
||||
{
|
||||
// background-gradient: linear #00FFFF #FFFF00 0 0.5 1 0.5; or
|
||||
// background-gradient: radial #00FFFF #FFFF00 0.5 0.5 1 1 1.2;
|
||||
|
||||
$v = trim($bg);
|
||||
$bgr = preg_split('/\s+/', $v);
|
||||
$count_bgr = count($bgr);
|
||||
$g = [];
|
||||
if ($count_bgr > 6) {
|
||||
if (stripos($bgr[0], 'L') === 0 && $count_bgr === 7) { // linear
|
||||
$g['type'] = self::TYPE_LINEAR;
|
||||
//$coords = array(0,0,1,1 ); // 0 0 1 0 or 0 1 1 1 is L 2 R; 1,1,0,1 is R2L; 1,1,1,0 is T2B; 1,0,1,1 is B2T
|
||||
// Linear: $coords - array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg).
|
||||
// The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
|
||||
$g['coords'] = [$bgr[3], $bgr[4], $bgr[5], $bgr[6]];
|
||||
} elseif ($count_bgr === 8) { // radial
|
||||
$g['type'] = self::TYPE_RADIAL;
|
||||
// Radial: $coords - array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1,
|
||||
// (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg).
|
||||
// (fx, fy) should be inside the circle, otherwise some areas will not be defined
|
||||
$g['coords'] = [$bgr[3], $bgr[4], $bgr[5], $bgr[6], $bgr[7]];
|
||||
}
|
||||
$g['colorspace'] = 'RGB';
|
||||
// mPDF 5.3.74
|
||||
$cor = $this->colorConverter->convert($bgr[1], $this->mpdf->PDFAXwarnings);
|
||||
if ($cor[0] == 1) {
|
||||
$g['colorspace'] = 'Gray';
|
||||
} elseif ($cor[0] == 4 || $cor[0] == 6) {
|
||||
$g['colorspace'] = 'CMYK';
|
||||
}
|
||||
if ($cor) {
|
||||
$g['col'] = $cor;
|
||||
} else {
|
||||
$g['col'] = $this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings);
|
||||
}
|
||||
$cor = $this->colorConverter->convert($bgr[2], $this->mpdf->PDFAXwarnings);
|
||||
if ($cor) {
|
||||
$g['col2'] = $cor;
|
||||
} else {
|
||||
$g['col2'] = $this->colorConverter->convert(255, $this->mpdf->PDFAXwarnings);
|
||||
}
|
||||
$g['extend'] = ['true', 'true'];
|
||||
$g['stops'] = [['col' => $g['col'], 'opacity' => 1, 'offset' => 0], ['col' => $g['col2'], 'opacity' => 1, 'offset' => 1]];
|
||||
return $g;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
46
Mpdf/HTMLParserMode.php
Normal file
46
Mpdf/HTMLParserMode.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class HTMLParserMode
|
||||
{
|
||||
/**
|
||||
* Parses a whole $html document
|
||||
*/
|
||||
const DEFAULT_MODE = 0;
|
||||
|
||||
/**
|
||||
* Parses the $html as styles and stylesheets only
|
||||
*/
|
||||
const HEADER_CSS = 1;
|
||||
|
||||
/**
|
||||
* Parses the $html as output elements only
|
||||
*/
|
||||
const HTML_BODY = 2;
|
||||
|
||||
/**
|
||||
* (For internal use only - parses the $html code without writing to document)
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const HTML_PARSE_NO_WRITE = 3;
|
||||
|
||||
/**
|
||||
* (For internal use only - writes the $html code to a buffer)
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
const HTML_HEADER_BUFFER = 4;
|
||||
|
||||
public static function getAllModes()
|
||||
{
|
||||
return [
|
||||
self::DEFAULT_MODE,
|
||||
self::HEADER_CSS,
|
||||
self::HTML_BODY,
|
||||
self::HTML_PARSE_NO_WRITE,
|
||||
self::HTML_HEADER_BUFFER,
|
||||
];
|
||||
}
|
||||
}
|
||||
207
Mpdf/Hyphenator.php
Normal file
207
Mpdf/Hyphenator.php
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class Hyphenator
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
private $patterns;
|
||||
|
||||
private $dictionary;
|
||||
|
||||
private $words;
|
||||
|
||||
private $loadedPatterns;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $dictionaryLoaded;
|
||||
|
||||
public function __construct(Mpdf $mpdf)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
|
||||
$this->dictionaryLoaded = false;
|
||||
|
||||
$this->patterns = [];
|
||||
$this->dictionary = [];
|
||||
$this->words = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $word
|
||||
* @param int $currptr
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function hyphenateWord($word, $currptr)
|
||||
{
|
||||
// Do everything inside this function in utf-8
|
||||
// Don't hyphenate web addresses
|
||||
if (preg_match('/^(http:|www\.)/', $word)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$ptr = -1;
|
||||
|
||||
if (!$this->dictionaryLoaded) {
|
||||
$this->loadDictionary();
|
||||
}
|
||||
|
||||
if (!in_array($this->mpdf->SHYlang, $this->mpdf->SHYlanguages)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If no pattern loaded or not the best one
|
||||
if (!$this->patternsLoaded()) {
|
||||
$this->loadPatterns();
|
||||
}
|
||||
|
||||
if ($this->mpdf->usingCoreFont) {
|
||||
$word = mb_convert_encoding($word, 'UTF-8', $this->mpdf->mb_enc);
|
||||
}
|
||||
|
||||
$prepre = '';
|
||||
$postpost = '';
|
||||
$startpunctuation = "\xc2\xab\xc2\xbf\xe2\x80\x98\xe2\x80\x9b\xe2\x80\x9c\xe2\x80\x9f";
|
||||
$endpunctuation = "\xe2\x80\x9e\xe2\x80\x9d\xe2\x80\x9a\xe2\x80\x99\xc2\xbb";
|
||||
|
||||
if (preg_match('/^(["\'' . $startpunctuation . '])+(.{' . $this->mpdf->SHYcharmin . ',})$/u', $word, $m)) {
|
||||
$prepre = $m[1];
|
||||
$word = $m[2];
|
||||
}
|
||||
|
||||
if (preg_match('/^(.{' . $this->mpdf->SHYcharmin . ',})([\'\.,;:!?"' . $endpunctuation . ']+)$/u', $word, $m)) {
|
||||
$word = $m[1];
|
||||
$postpost = $m[2];
|
||||
}
|
||||
|
||||
if (mb_strlen($word, 'UTF-8') < $this->mpdf->SHYcharmin) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$success = false;
|
||||
$preprelen = mb_strlen($prepre);
|
||||
|
||||
if (isset($this->words[mb_strtolower($word)])) {
|
||||
foreach ($this->words[mb_strtolower($word)] as $i) {
|
||||
if (($i + $preprelen) >= $currptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
$ptr = $i + $preprelen;
|
||||
$success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
$text_word = '_' . $word . '_';
|
||||
$word_length = mb_strlen($text_word, 'UTF-8');
|
||||
$text_word = mb_strtolower($text_word, 'UTF-8');
|
||||
$hyphenated_word = [];
|
||||
|
||||
$numbers = [
|
||||
'0' => true,
|
||||
'1' => true,
|
||||
'2' => true,
|
||||
'3' => true,
|
||||
'4' => true,
|
||||
'5' => true,
|
||||
'6' => true,
|
||||
'7' => true,
|
||||
'8' => true,
|
||||
'9' => true
|
||||
];
|
||||
|
||||
for ($position = 0; $position <= ($word_length - $this->mpdf->SHYcharmin); $position++) {
|
||||
$maxwins = min($word_length - $position, $this->mpdf->SHYcharmax);
|
||||
for ($win = $this->mpdf->SHYcharmin; $win <= $maxwins; $win++) {
|
||||
if (isset($this->patterns[mb_substr($text_word, $position, $win, 'UTF-8')])) {
|
||||
$pattern = $this->patterns[mb_substr($text_word, $position, $win, 'UTF-8')];
|
||||
$digits = 1;
|
||||
$pattern_length = mb_strlen($pattern, 'UTF-8');
|
||||
|
||||
for ($i = 0; $i < $pattern_length; $i++) {
|
||||
$char = $pattern[$i];
|
||||
if (isset($numbers[$char])) {
|
||||
$zero = $i === 0 ? $position - 1 : $position + $i - $digits;
|
||||
if (!isset($hyphenated_word[$zero]) || $hyphenated_word[$zero] !== $char) {
|
||||
$hyphenated_word[$zero] = $char;
|
||||
}
|
||||
$digits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = $this->mpdf->SHYleftmin; $i <= (mb_strlen($word, 'UTF-8') - $this->mpdf->SHYrightmin); $i++) {
|
||||
if (isset($hyphenated_word[$i]) && $hyphenated_word[$i] % 2 !== 0) {
|
||||
if (($i + $preprelen) > $currptr) {
|
||||
break;
|
||||
}
|
||||
$ptr = $i + $preprelen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ptr;
|
||||
}
|
||||
|
||||
private function patternsLoaded()
|
||||
{
|
||||
return !(count($this->patterns) < 1 || ($this->loadedPatterns && $this->loadedPatterns !== $this->mpdf->SHYlang));
|
||||
}
|
||||
|
||||
private function loadPatterns()
|
||||
{
|
||||
$patterns = require __DIR__ . '//data/patterns/' . $this->mpdf->SHYlang . '.php';
|
||||
$patterns = explode(' ', $patterns);
|
||||
|
||||
$new_patterns = [];
|
||||
$patternCount = count($patterns);
|
||||
for ($i = 0; $i < $patternCount; $i++) {
|
||||
$value = $patterns[$i];
|
||||
$new_patterns[preg_replace('/[0-9]/', '', $value)] = $value;
|
||||
}
|
||||
|
||||
$this->patterns = $new_patterns;
|
||||
$this->loadedPatterns = $this->mpdf->SHYlang;
|
||||
}
|
||||
|
||||
private function loadDictionary()
|
||||
{
|
||||
if (file_exists($this->mpdf->hyphenationDictionaryFile)) {
|
||||
$this->dictionary = file($this->mpdf->hyphenationDictionaryFile, FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($this->dictionary as $entry) {
|
||||
$entry = trim($entry);
|
||||
$poss = [];
|
||||
$offset = 0;
|
||||
$p = true;
|
||||
$wl = mb_strlen($entry, 'UTF-8');
|
||||
while ($offset < $wl) {
|
||||
$p = mb_strpos($entry, '/', $offset, 'UTF-8');
|
||||
if ($p !== false) {
|
||||
$poss[] = $p - count($poss);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
$offset = $p + 1;
|
||||
}
|
||||
if (count($poss)) {
|
||||
$this->words[str_replace('/', '', mb_strtolower($entry))] = $poss;
|
||||
}
|
||||
}
|
||||
} elseif ($this->mpdf->debug) {
|
||||
throw new \Mpdf\MpdfException(sprintf('Unable to open hyphenation dictionary "%s"', $this->mpdf->hyphenationDictionaryFile));
|
||||
}
|
||||
|
||||
$this->dictionaryLoaded = true;
|
||||
}
|
||||
}
|
||||
297
Mpdf/Image/Bmp.php
Normal file
297
Mpdf/Image/Bmp.php
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Image;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class Bmp
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
public function __construct(Mpdf $mpdf)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
}
|
||||
|
||||
public function _getBMPimage($data, $file)
|
||||
{
|
||||
// Adapted from script by Valentin Schmidt
|
||||
// http://staff.dasdeck.de/valentin/fpdf/fpdf_bmp/
|
||||
$bfOffBits = $this->_fourbytes2int_le(substr($data, 10, 4));
|
||||
$width = $this->_fourbytes2int_le(substr($data, 18, 4));
|
||||
$height = $this->_fourbytes2int_le(substr($data, 22, 4));
|
||||
$flip = ($height < 0);
|
||||
if ($flip) {
|
||||
$height = -$height;
|
||||
}
|
||||
$biBitCount = $this->_twobytes2int_le(substr($data, 28, 2));
|
||||
$biCompression = $this->_fourbytes2int_le(substr($data, 30, 4));
|
||||
$info = ['w' => $width, 'h' => $height];
|
||||
if ($biBitCount < 16) {
|
||||
$info['cs'] = 'Indexed';
|
||||
$info['bpc'] = $biBitCount;
|
||||
$palStr = substr($data, 54, $bfOffBits - 54);
|
||||
$pal = '';
|
||||
$cnt = strlen($palStr) / 4;
|
||||
for ($i = 0; $i < $cnt; $i++) {
|
||||
$n = 4 * $i;
|
||||
$pal .= $palStr[$n + 2] . $palStr[$n + 1] . $palStr[$n];
|
||||
}
|
||||
$info['pal'] = $pal;
|
||||
} else {
|
||||
$info['cs'] = 'DeviceRGB';
|
||||
$info['bpc'] = 8;
|
||||
}
|
||||
|
||||
if ($this->mpdf->restrictColorSpace == 1 || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace == 3) {
|
||||
if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
|
||||
$this->mpdf->PDFAXwarnings[] = "Image cannot be converted to suitable colour space for PDFA or PDFX file - $file - (Image replaced by 'no-image'.)";
|
||||
}
|
||||
return ['error' => "BMP Image cannot be converted to suitable colour space - $file - (Image replaced by 'no-image'.)"];
|
||||
}
|
||||
|
||||
$biXPelsPerMeter = $this->_fourbytes2int_le(substr($data, 38, 4)); // horizontal pixels per meter, usually set to zero
|
||||
//$biYPelsPerMeter=$this->_fourbytes2int_le(substr($data,42,4)); // vertical pixels per meter, usually set to zero
|
||||
$biXPelsPerMeter = round($biXPelsPerMeter / 1000 * 25.4);
|
||||
//$biYPelsPerMeter=round($biYPelsPerMeter/1000 *25.4);
|
||||
$info['set-dpi'] = $biXPelsPerMeter;
|
||||
|
||||
switch ($biCompression) {
|
||||
case 0:
|
||||
$str = substr($data, $bfOffBits);
|
||||
break;
|
||||
case 1: # BI_RLE8
|
||||
$str = $this->rle8_decode(substr($data, $bfOffBits), $width);
|
||||
break;
|
||||
case 2: # BI_RLE4
|
||||
$str = $this->rle4_decode(substr($data, $bfOffBits), $width);
|
||||
break;
|
||||
}
|
||||
$bmpdata = '';
|
||||
$padCnt = (4 - ceil($width / (8 / $biBitCount)) % 4) % 4;
|
||||
switch ($biBitCount) {
|
||||
case 1:
|
||||
case 4:
|
||||
case 8:
|
||||
$w = floor($width / (8 / $biBitCount)) + ($width % (8 / $biBitCount) ? 1 : 0);
|
||||
$w_row = $w + $padCnt;
|
||||
if ($flip) {
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
$y0 = $y * $w_row;
|
||||
for ($x = 0; $x < $w; $x++) {
|
||||
$bmpdata .= $str[$y0 + $x];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ($y = $height - 1; $y >= 0; $y--) {
|
||||
$y0 = $y * $w_row;
|
||||
for ($x = 0; $x < $w; $x++) {
|
||||
$bmpdata .= $str[$y0 + $x];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
$w_row = $width * 2 + $padCnt;
|
||||
if ($flip) {
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
$y0 = $y * $w_row;
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
$n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
|
||||
$b = ($n & 31) << 3;
|
||||
$g = ($n & 992) >> 2;
|
||||
$r = ($n & 31744) >> 7;
|
||||
$bmpdata .= chr($r) . chr($g) . chr($b);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ($y = $height - 1; $y >= 0; $y--) {
|
||||
$y0 = $y * $w_row;
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
$n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
|
||||
$b = ($n & 31) << 3;
|
||||
$g = ($n & 992) >> 2;
|
||||
$r = ($n & 31744) >> 7;
|
||||
$bmpdata .= chr($r) . chr($g) . chr($b);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 24:
|
||||
case 32:
|
||||
$byteCnt = $biBitCount / 8;
|
||||
$w_row = $width * $byteCnt + $padCnt;
|
||||
|
||||
if ($flip) {
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
$y0 = $y * $w_row;
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
$i = $y0 + $x * $byteCnt; # + 1
|
||||
$bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ($y = $height - 1; $y >= 0; $y--) {
|
||||
$y0 = $y * $w_row;
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
$i = $y0 + $x * $byteCnt; # + 1
|
||||
$bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return ['error' => 'Error parsing BMP image - Unsupported image biBitCount'];
|
||||
}
|
||||
if ($this->mpdf->compress) {
|
||||
$bmpdata = gzcompress($bmpdata);
|
||||
$info['f'] = 'FlateDecode';
|
||||
}
|
||||
$info['data'] = $bmpdata;
|
||||
$info['type'] = 'bmp';
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 4-byte integer from string
|
||||
*
|
||||
* @param $s
|
||||
* @return int
|
||||
*/
|
||||
private function _fourbytes2int_le($s)
|
||||
{
|
||||
return (ord($s[3]) << 24) + (ord($s[2]) << 16) + (ord($s[1]) << 8) + ord($s[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 2-byte integer from string
|
||||
*
|
||||
* @param $s
|
||||
* @return int
|
||||
*/
|
||||
private function _twobytes2int_le($s)
|
||||
{
|
||||
return (ord(substr($s, 1, 1)) << 8) + ord(substr($s, 0, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoder for RLE8 compression in windows bitmaps
|
||||
*
|
||||
* @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
* @param $str
|
||||
* @param $width
|
||||
* @return string
|
||||
*/
|
||||
private function rle8_decode($str, $width)
|
||||
{
|
||||
$lineWidth = $width + (3 - ($width - 1) % 4);
|
||||
$out = '';
|
||||
$cnt = strlen($str);
|
||||
for ($i = 0; $i < $cnt; $i++) {
|
||||
$o = ord($str[$i]);
|
||||
if ($o === 0) { # ESCAPE
|
||||
$i++;
|
||||
switch (ord($str[$i])) {
|
||||
case 0: # NEW LINE
|
||||
$padCnt = $lineWidth - strlen($out) % $lineWidth;
|
||||
if ($padCnt < $lineWidth) {
|
||||
$out .= str_repeat(chr(0), $padCnt);# pad line
|
||||
}
|
||||
break;
|
||||
case 1: # END OF FILE
|
||||
$padCnt = $lineWidth - strlen($out) % $lineWidth;
|
||||
if ($padCnt < $lineWidth) {
|
||||
$out .= str_repeat(chr(0), $padCnt);# pad line
|
||||
}
|
||||
break 2;
|
||||
case 2: # DELTA
|
||||
$i += 2;
|
||||
break;
|
||||
default: # ABSOLUTE MODE
|
||||
$num = ord($str[$i]);
|
||||
for ($j = 0; $j < $num; $j++) {
|
||||
$out .= $str[++$i];
|
||||
}
|
||||
if ($num % 2) {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$out .= str_repeat($str[++$i], $o);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoder for RLE4 compression in windows bitmaps
|
||||
*
|
||||
* @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
* @param $str
|
||||
* @param $width
|
||||
* @return string
|
||||
*/
|
||||
private function rle4_decode($str, $width)
|
||||
{
|
||||
$w = floor($width / 2) + ($width % 2);
|
||||
$lineWidth = $w + (3 - ( ($width - 1) / 2) % 4);
|
||||
$pixels = [];
|
||||
$cnt = strlen($str);
|
||||
for ($i = 0; $i < $cnt; $i++) {
|
||||
$o = ord($str[$i]);
|
||||
if ($o === 0) { # ESCAPE
|
||||
$i++;
|
||||
switch (ord($str[$i])) {
|
||||
case 0: # NEW LINE
|
||||
while (count($pixels) % $lineWidth !== 0) {
|
||||
$pixels[] = 0;
|
||||
}
|
||||
break;
|
||||
case 1: # END OF FILE
|
||||
while (count($pixels) % $lineWidth !== 0) {
|
||||
$pixels[] = 0;
|
||||
}
|
||||
break 2;
|
||||
case 2: # DELTA
|
||||
$i += 2;
|
||||
break;
|
||||
default: # ABSOLUTE MODE
|
||||
$num = ord($str[$i]);
|
||||
for ($j = 0; $j < $num; $j++) {
|
||||
if ($j % 2 === 0) {
|
||||
$c = ord($str[++$i]);
|
||||
$pixels[] = ($c & 240) >> 4;
|
||||
} else {
|
||||
$pixels[] = $c & 15; //FIXME: undefined var
|
||||
}
|
||||
}
|
||||
if ($num % 2) {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$c = ord($str[++$i]);
|
||||
for ($j = 0; $j < $o; $j++) {
|
||||
$pixels[] = ($j % 2 === 0 ? ($c & 240) >> 4 : $c & 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$out = '';
|
||||
if (count($pixels) % 2) {
|
||||
$pixels[] = 0;
|
||||
}
|
||||
$cnt = count($pixels) / 2;
|
||||
for ($i = 0; $i < $cnt; $i++) {
|
||||
$out .= chr(16 * $pixels[2 * $i] + $pixels[2 * $i + 1]);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
1435
Mpdf/Image/ImageProcessor.php
Normal file
1435
Mpdf/Image/ImageProcessor.php
Normal file
File diff suppressed because it is too large
Load Diff
42
Mpdf/Image/ImageTypeGuesser.php
Normal file
42
Mpdf/Image/ImageTypeGuesser.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Image;
|
||||
|
||||
class ImageTypeGuesser
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function guess($data)
|
||||
{
|
||||
if (in_array(substr($data, 6, 4), ['JFIF', 'Exif'], true) || strpos($data, chr(255) . chr(216)) === 0) { // 0xFF 0xD8 // mpDF 5.7.2
|
||||
return 'jpeg';
|
||||
}
|
||||
|
||||
if (in_array(substr($data, 0, 6), ['GIF87a', 'GIF89a'], true)) {
|
||||
return 'gif';
|
||||
}
|
||||
|
||||
if (strpos($data, chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) === 0) {
|
||||
return 'png';
|
||||
}
|
||||
|
||||
if (strpos($data, chr(215) . chr(205) . chr(198) . chr(154)) === 0) {
|
||||
return 'wmf';
|
||||
}
|
||||
|
||||
if (preg_match('/<svg.*<\/svg>/is', $data)) {
|
||||
return 'svg';
|
||||
}
|
||||
|
||||
if (strpos($data, 'BM') === 0) {
|
||||
return 'bmp';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
4020
Mpdf/Image/Svg.php
Normal file
4020
Mpdf/Image/Svg.php
Normal file
File diff suppressed because it is too large
Load Diff
290
Mpdf/Image/Wmf.php
Normal file
290
Mpdf/Image/Wmf.php
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Image;
|
||||
|
||||
use Mpdf\Color\ColorConverter;
|
||||
use Mpdf\Mpdf;
|
||||
|
||||
class Wmf
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Color\ColorConverter
|
||||
*/
|
||||
private $colorConverter;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $gdiObjectArray;
|
||||
|
||||
public function __construct(Mpdf $mpdf, ColorConverter $colorConverter)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->colorConverter = $colorConverter;
|
||||
}
|
||||
|
||||
function _getWMFimage($data)
|
||||
{
|
||||
$k = Mpdf::SCALE;
|
||||
|
||||
$this->gdiObjectArray = [];
|
||||
$a = unpack('stest', "\1\0");
|
||||
if ($a['test'] != 1) {
|
||||
return [0, 'Error parsing WMF image - Big-endian architecture not supported'];
|
||||
}
|
||||
// check for Aldus placeable metafile header
|
||||
$key = unpack('Lmagic', substr($data, 0, 4));
|
||||
$p = 18; // WMF header
|
||||
if ($key['magic'] == (int) 0x9AC6CDD7) {
|
||||
$p +=22;
|
||||
} // Aldus header
|
||||
// define some state variables
|
||||
$wo = null; // window origin
|
||||
$we = null; // window extent
|
||||
$polyFillMode = 0;
|
||||
$nullPen = false;
|
||||
$nullBrush = false;
|
||||
$endRecord = false;
|
||||
$wmfdata = '';
|
||||
while ($p < strlen($data) && !$endRecord) {
|
||||
$recordInfo = unpack('Lsize/Sfunc', substr($data, $p, 6));
|
||||
$p += 6;
|
||||
// size of record given in WORDs (= 2 bytes)
|
||||
$size = $recordInfo['size'];
|
||||
// func is number of GDI function
|
||||
$func = $recordInfo['func'];
|
||||
if ($size > 3) {
|
||||
$parms = substr($data, $p, 2 * ($size - 3));
|
||||
$p += 2 * ($size - 3);
|
||||
}
|
||||
switch ($func) {
|
||||
case 0x020b: // SetWindowOrg
|
||||
// do not allow window origin to be changed
|
||||
// after drawing has begun
|
||||
if (!$wmfdata) {
|
||||
$wo = array_reverse(unpack('s2', $parms));
|
||||
}
|
||||
break;
|
||||
case 0x020c: // SetWindowExt
|
||||
// do not allow window extent to be changed
|
||||
// after drawing has begun
|
||||
if (!$wmfdata) {
|
||||
$we = array_reverse(unpack('s2', $parms));
|
||||
}
|
||||
break;
|
||||
case 0x02fc: // CreateBrushIndirect
|
||||
$brush = unpack('sstyle/Cr/Cg/Cb/Ca/Shatch', $parms);
|
||||
$brush['type'] = 'B';
|
||||
$this->_AddGDIObject($brush);
|
||||
break;
|
||||
case 0x02fa: // CreatePenIndirect
|
||||
$pen = unpack('Sstyle/swidth/sdummy/Cr/Cg/Cb/Ca', $parms);
|
||||
// convert width from twips to user unit
|
||||
$pen['width'] /= (20 * $k);
|
||||
$pen['type'] = 'P';
|
||||
$this->_AddGDIObject($pen);
|
||||
break;
|
||||
|
||||
// MUST create other GDI objects even if we don't handle them
|
||||
case 0x06fe: // CreateBitmap
|
||||
case 0x02fd: // CreateBitmapIndirect
|
||||
case 0x00f8: // CreateBrush
|
||||
case 0x02fb: // CreateFontIndirect
|
||||
case 0x00f7: // CreatePalette
|
||||
case 0x01f9: // CreatePatternBrush
|
||||
case 0x06ff: // CreateRegion
|
||||
case 0x0142: // DibCreatePatternBrush
|
||||
$dummyObject = ['type' => 'D'];
|
||||
$this->_AddGDIObject($dummyObject);
|
||||
break;
|
||||
case 0x0106: // SetPolyFillMode
|
||||
$polyFillMode = unpack('smode', $parms);
|
||||
$polyFillMode = $polyFillMode['mode'];
|
||||
break;
|
||||
case 0x01f0: // DeleteObject
|
||||
$idx = unpack('Sidx', $parms);
|
||||
$idx = $idx['idx'];
|
||||
$this->_DeleteGDIObject($idx);
|
||||
break;
|
||||
case 0x012d: // SelectObject
|
||||
$idx = unpack('Sidx', $parms);
|
||||
$idx = $idx['idx'];
|
||||
$obj = $this->_GetGDIObject($idx);
|
||||
switch ($obj['type']) {
|
||||
case 'B':
|
||||
$nullBrush = false;
|
||||
if ($obj['style'] == 1) {
|
||||
$nullBrush = true;
|
||||
} else {
|
||||
$wmfdata .= $this->mpdf->SetFColor($this->colorConverter->convert('rgb(' . $obj['r'] . ',' . $obj['g'] . ',' . $obj['b'] . ')', $this->mpdf->PDFAXwarnings), true) . "\n";
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
$nullPen = false;
|
||||
$dashArray = [];
|
||||
// dash parameters are custom
|
||||
switch ($obj['style']) {
|
||||
case 0: // PS_SOLID
|
||||
break;
|
||||
case 1: // PS_DASH
|
||||
$dashArray = [3, 1];
|
||||
break;
|
||||
case 2: // PS_DOT
|
||||
$dashArray = [0.5, 0.5];
|
||||
break;
|
||||
case 3: // PS_DASHDOT
|
||||
$dashArray = [2, 1, 0.5, 1];
|
||||
break;
|
||||
case 4: // PS_DASHDOTDOT
|
||||
$dashArray = [2, 1, 0.5, 1, 0.5, 1];
|
||||
break;
|
||||
case 5: // PS_NULL
|
||||
$nullPen = true;
|
||||
break;
|
||||
}
|
||||
if (!$nullPen) {
|
||||
$wmfdata .= $this->mpdf->SetDColor($this->colorConverter->convert('rgb(' . $obj['r'] . ',' . $obj['g'] . ',' . $obj['b'] . ')', $this->mpdf->PDFAXwarnings), true) . "\n";
|
||||
$wmfdata .= sprintf("%.3F w\n", $obj['width'] * $k);
|
||||
}
|
||||
if (!empty($dashArray)) {
|
||||
$s = '[';
|
||||
for ($i = 0; $i < count($dashArray); $i++) {
|
||||
$s .= $dashArray[$i] * $k;
|
||||
if ($i != count($dashArray) - 1) {
|
||||
$s .= ' ';
|
||||
}
|
||||
}
|
||||
$s .= '] 0 d';
|
||||
$wmfdata .= $s . "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0325: // Polyline
|
||||
case 0x0324: // Polygon
|
||||
$coords = unpack('s' . ($size - 3), $parms);
|
||||
$numpoints = $coords[1];
|
||||
for ($i = $numpoints; $i > 0; $i--) {
|
||||
$px = $coords[2 * $i];
|
||||
$py = $coords[2 * $i + 1];
|
||||
|
||||
if ($i < $numpoints) {
|
||||
$wmfdata .= $this->_LineTo($px, $py);
|
||||
} else {
|
||||
$wmfdata .= $this->_MoveTo($px, $py);
|
||||
}
|
||||
}
|
||||
if ($func == 0x0325) {
|
||||
$op = 's';
|
||||
} elseif ($func == 0x0324) {
|
||||
if ($nullPen) {
|
||||
if ($nullBrush) {
|
||||
$op = 'n';
|
||||
} // no op
|
||||
else {
|
||||
$op = 'f';
|
||||
} // fill
|
||||
} else {
|
||||
if ($nullBrush) {
|
||||
$op = 's';
|
||||
} // stroke
|
||||
else {
|
||||
$op = 'b';
|
||||
} // stroke and fill
|
||||
}
|
||||
if ($polyFillMode == 1 && ($op == 'b' || $op == 'f')) {
|
||||
$op .= '*';
|
||||
} // use even-odd fill rule
|
||||
}
|
||||
$wmfdata .= $op . "\n";
|
||||
break;
|
||||
case 0x0538: // PolyPolygon
|
||||
$coords = unpack('s' . ($size - 3), $parms);
|
||||
$numpolygons = $coords[1];
|
||||
$adjustment = $numpolygons;
|
||||
for ($j = 1; $j <= $numpolygons; $j++) {
|
||||
$numpoints = $coords[$j + 1];
|
||||
for ($i = $numpoints; $i > 0; $i--) {
|
||||
$px = $coords[2 * $i + $adjustment];
|
||||
$py = $coords[2 * $i + 1 + $adjustment];
|
||||
if ($i == $numpoints) {
|
||||
$wmfdata .= $this->_MoveTo($px, $py);
|
||||
} else {
|
||||
$wmfdata .= $this->_LineTo($px, $py);
|
||||
}
|
||||
}
|
||||
$adjustment += $numpoints * 2;
|
||||
}
|
||||
|
||||
if ($nullPen) {
|
||||
if ($nullBrush) {
|
||||
$op = 'n';
|
||||
} // no op
|
||||
else {
|
||||
$op = 'f';
|
||||
} // fill
|
||||
} else {
|
||||
if ($nullBrush) {
|
||||
$op = 's';
|
||||
} // stroke
|
||||
else {
|
||||
$op = 'b';
|
||||
} // stroke and fill
|
||||
}
|
||||
if ($polyFillMode == 1 && ($op == 'b' || $op == 'f')) {
|
||||
$op .= '*';
|
||||
} // use even-odd fill rule
|
||||
$wmfdata .= $op . "\n";
|
||||
break;
|
||||
case 0x0000:
|
||||
$endRecord = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [1, $wmfdata, $wo, $we];
|
||||
}
|
||||
|
||||
function _MoveTo($x, $y)
|
||||
{
|
||||
return "$x $y m\n";
|
||||
}
|
||||
|
||||
// a line must have been started using _MoveTo() first
|
||||
function _LineTo($x, $y)
|
||||
{
|
||||
return "$x $y l\n";
|
||||
}
|
||||
|
||||
function _AddGDIObject($obj)
|
||||
{
|
||||
// find next available slot
|
||||
$idx = 0;
|
||||
if (!empty($this->gdiObjectArray)) {
|
||||
$empty = false;
|
||||
$i = 0;
|
||||
while (!$empty) {
|
||||
$empty = !isset($this->gdiObjectArray[$i]);
|
||||
$i++;
|
||||
}
|
||||
$idx = $i - 1;
|
||||
}
|
||||
$this->gdiObjectArray[$idx] = $obj;
|
||||
}
|
||||
|
||||
function _GetGDIObject($idx)
|
||||
{
|
||||
return $this->gdiObjectArray[$idx];
|
||||
}
|
||||
|
||||
function _DeleteGDIObject($idx)
|
||||
{
|
||||
unset($this->gdiObjectArray[$idx]);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
|
|
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
|
|||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
|
|
@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
|
|||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
|
|
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
|
|||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
|
|
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
|
|||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
|
|
@ -225,7 +225,7 @@ impose that choice.
|
|||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
|
|
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
|||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
|
|
@ -277,64 +277,4 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
END OF TERMS AND CONDITIONS
|
||||
546
Mpdf/Language/LanguageToFont.php
Normal file
546
Mpdf/Language/LanguageToFont.php
Normal file
|
|
@ -0,0 +1,546 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Language;
|
||||
|
||||
class LanguageToFont implements \Mpdf\Language\LanguageToFontInterface
|
||||
{
|
||||
|
||||
public function getLanguageOptions($llcc, $adobeCJK)
|
||||
{
|
||||
$tags = explode('-', $llcc);
|
||||
$lang = strtolower($tags[0]);
|
||||
$country = '';
|
||||
$script = '';
|
||||
if (!empty($tags[1])) {
|
||||
if (strlen($tags[1]) === 4) {
|
||||
$script = strtolower($tags[1]);
|
||||
} else {
|
||||
$country = strtolower($tags[1]);
|
||||
}
|
||||
}
|
||||
if (!empty($tags[2])) {
|
||||
$country = strtolower($tags[2]);
|
||||
}
|
||||
|
||||
$unifont = '';
|
||||
$coreSuitable = false;
|
||||
|
||||
switch ($lang) {
|
||||
/* European */
|
||||
case 'en':
|
||||
case 'eng': // English // LATIN
|
||||
case 'eu':
|
||||
case 'eus': // Basque
|
||||
case 'br':
|
||||
case 'bre': // Breton
|
||||
case 'ca':
|
||||
case 'cat': // Catalan
|
||||
case 'co':
|
||||
case 'cos': // Corsican
|
||||
case 'kw':
|
||||
case 'cor': // Cornish
|
||||
case 'cy':
|
||||
case 'cym': // Welsh
|
||||
case 'cs':
|
||||
case 'ces': // Czech
|
||||
case 'da':
|
||||
case 'dan': // Danish
|
||||
case 'nl':
|
||||
case 'nld': // Dutch
|
||||
case 'et':
|
||||
case 'est': // Estonian
|
||||
case 'fo':
|
||||
case 'fao': // Faroese
|
||||
case 'fi':
|
||||
case 'fin': // Finnish
|
||||
case 'fr':
|
||||
case 'fra': // French
|
||||
case 'gl':
|
||||
case 'glg': // Galician
|
||||
case 'de':
|
||||
case 'deu': // German
|
||||
case 'ht':
|
||||
case 'hat': // Haitian; Haitian Creole
|
||||
case 'hu':
|
||||
case 'hun': // Hungarian
|
||||
case 'ga':
|
||||
case 'gle': // Irish
|
||||
case 'is':
|
||||
case 'isl': // Icelandic
|
||||
case 'it':
|
||||
case 'ita': // Italian
|
||||
case 'la':
|
||||
case 'lat': // Latin
|
||||
case 'lb':
|
||||
case 'ltz': // Luxembourgish
|
||||
case 'li':
|
||||
case 'lim': // Limburgish
|
||||
case 'lt':
|
||||
case 'lit': // Lithuanian
|
||||
case 'lv':
|
||||
case 'lav': // Latvian
|
||||
case 'gv':
|
||||
case 'glv': // Manx
|
||||
case 'no':
|
||||
case 'nor': // Norwegian
|
||||
case 'nn':
|
||||
case 'nno': // Norwegian Nynorsk
|
||||
case 'nb':
|
||||
case 'nob': // Norwegian Bokmål
|
||||
case 'pl':
|
||||
case 'pol': // Polish
|
||||
case 'pt':
|
||||
case 'por': // Portuguese
|
||||
case 'ro':
|
||||
case 'ron': // Romanian
|
||||
case 'gd':
|
||||
case 'gla': // Scottish Gaelic
|
||||
case 'es':
|
||||
case 'spa': // Spanish
|
||||
case 'sv':
|
||||
case 'swe': // Swedish
|
||||
case 'sl':
|
||||
case 'slv': // Slovene
|
||||
case 'sk':
|
||||
case 'slk': // Slovak
|
||||
$coreSuitable = true;
|
||||
break;
|
||||
|
||||
case 'ru':
|
||||
case 'rus': // Russian // CYRILLIC
|
||||
case 'ab':
|
||||
case 'abk': // Abkhaz
|
||||
case 'av':
|
||||
case 'ava': // Avaric
|
||||
case 'ba':
|
||||
case 'bak': // Bashkir
|
||||
case 'be':
|
||||
case 'bel': // Belarusian
|
||||
case 'bg':
|
||||
case 'bul': // Bulgarian
|
||||
case 'ce':
|
||||
case 'che': // Chechen
|
||||
case 'cv':
|
||||
case 'chv': // Chuvash
|
||||
case 'kk':
|
||||
case 'kaz': // Kazakh
|
||||
case 'kv':
|
||||
case 'kom': // Komi
|
||||
case 'ky':
|
||||
case 'kir': // Kyrgyz
|
||||
case 'mk':
|
||||
case 'mkd': // Macedonian
|
||||
case 'cu':
|
||||
case 'chu': // Old Church Slavonic
|
||||
case 'os':
|
||||
case 'oss': // Ossetian
|
||||
case 'sr':
|
||||
case 'srp': // Serbian
|
||||
case 'tg':
|
||||
case 'tgk': // Tajik
|
||||
case 'tt':
|
||||
case 'tat': // Tatar
|
||||
case 'tk':
|
||||
case 'tuk': // Turkmen
|
||||
case 'uk':
|
||||
case 'ukr': // Ukrainian
|
||||
$unifont = 'dejavusanscondensed'; /* freeserif best coverage for supplements etc. */
|
||||
break;
|
||||
|
||||
case 'hy':
|
||||
case 'hye': // ARMENIAN
|
||||
$unifont = 'dejavusans';
|
||||
break;
|
||||
case 'ka':
|
||||
case 'kat': // GEORGIAN
|
||||
$unifont = 'dejavusans';
|
||||
break;
|
||||
|
||||
case 'el':
|
||||
case 'ell': // GREEK
|
||||
$unifont = 'dejavusanscondensed';
|
||||
break;
|
||||
case 'cop': // COPTIC
|
||||
$unifont = 'quivira';
|
||||
break;
|
||||
|
||||
case 'got': // GOTHIC
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
|
||||
/* African */
|
||||
case 'nqo': // NKO
|
||||
$unifont = 'dejavusans';
|
||||
break;
|
||||
//CASE 'bax': // BAMUM
|
||||
//CASE 'ha': CASE 'hau': // Hausa
|
||||
case 'vai': // VAI
|
||||
$unifont = 'freesans';
|
||||
break;
|
||||
case 'am':
|
||||
case 'amh': // Amharic ETHIOPIC
|
||||
case 'ti':
|
||||
case 'tir': // Tigrinya ETHIOPIC
|
||||
$unifont = 'abyssinicasil';
|
||||
break;
|
||||
|
||||
/* Middle Eastern */
|
||||
case 'ar':
|
||||
case 'ara': // Arabic NB Arabic text identified by Autofont will be marked as und-Arab
|
||||
$unifont = 'xbriyaz';
|
||||
break;
|
||||
case 'fa':
|
||||
case 'fas': // Persian (Farsi)
|
||||
$unifont = 'xbriyaz';
|
||||
break;
|
||||
case 'ps':
|
||||
case 'pus': // Pashto
|
||||
$unifont = 'xbriyaz';
|
||||
break;
|
||||
case 'ku':
|
||||
case 'kur': // Kurdish
|
||||
$unifont = 'xbriyaz';
|
||||
break;
|
||||
case 'ur':
|
||||
case 'urd': // Urdu
|
||||
$unifont = 'xbriyaz';
|
||||
break;
|
||||
case 'he':
|
||||
case 'heb': // HEBREW
|
||||
case 'yi':
|
||||
case 'yid': // Yiddish
|
||||
$unifont = 'taameydavidclm'; // dejavusans,dejavusanscondensed,freeserif are fine if you do not need cantillation marks
|
||||
break;
|
||||
|
||||
case 'syr': // SYRIAC
|
||||
$unifont = 'estrangeloedessa';
|
||||
break;
|
||||
|
||||
//CASE 'arc': // IMPERIAL_ARAMAIC
|
||||
//CASE ''ae: // AVESTAN
|
||||
case 'xcr': // CARIAN
|
||||
$unifont = 'aegean';
|
||||
break;
|
||||
case 'xlc': // LYCIAN
|
||||
$unifont = 'aegean';
|
||||
break;
|
||||
case 'xld': // LYDIAN
|
||||
$unifont = 'aegean';
|
||||
break;
|
||||
//CASE 'mid': // MANDAIC
|
||||
//CASE 'peo': // OLD_PERSIAN
|
||||
case 'phn': // PHOENICIAN
|
||||
$unifont = 'aegean';
|
||||
break;
|
||||
//CASE 'smp': // SAMARITAN
|
||||
case 'uga': // UGARITIC
|
||||
$unifont = 'aegean';
|
||||
break;
|
||||
|
||||
/* Central Asian */
|
||||
case 'bo':
|
||||
case 'bod': // TIBETAN
|
||||
case 'dz':
|
||||
case 'dzo': // Dzongkha
|
||||
$unifont = 'jomolhari';
|
||||
break;
|
||||
|
||||
//CASE 'mn': CASE 'mon': // MONGOLIAN (Vertical script)
|
||||
//CASE 'ug': CASE 'uig': // Uyghur
|
||||
//CASE 'uz': CASE 'uzb': // Uzbek
|
||||
//CASE 'az': CASE 'azb': // South Azerbaijani
|
||||
|
||||
/* South Asian */
|
||||
case 'as':
|
||||
case 'asm': // Assamese
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'bn':
|
||||
case 'ben': // BENGALI; Bangla
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'ks':
|
||||
case 'kas': // Kashmiri
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'hi':
|
||||
case 'hin': // Hindi DEVANAGARI
|
||||
case 'bh':
|
||||
case 'bih': // Bihari (Bhojpuri, Magahi, and Maithili)
|
||||
case 'sa':
|
||||
case 'san': // Sanskrit
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'gu':
|
||||
case 'guj': // Gujarati
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'pa':
|
||||
case 'pan': // Panjabi, Punjabi GURMUKHI
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'kn':
|
||||
case 'kan': // Kannada
|
||||
$unifont = 'lohitkannada';
|
||||
break;
|
||||
case 'mr':
|
||||
case 'mar': // Marathi
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'ml':
|
||||
case 'mal': // MALAYALAM
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'ne':
|
||||
case 'nep': // Nepali
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'or':
|
||||
case 'ori': // ORIYA
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'si':
|
||||
case 'sin': // SINHALA
|
||||
$unifont = 'kaputaunicode';
|
||||
break;
|
||||
case 'ta':
|
||||
case 'tam': // TAMIL
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
case 'te':
|
||||
case 'tel': // TELUGU
|
||||
$unifont = 'pothana2000';
|
||||
break;
|
||||
|
||||
// Sindhi (Arabic or Devanagari)
|
||||
case 'sd':
|
||||
case 'snd': // Sindhi
|
||||
$unifont = 'lateef';
|
||||
if ($country === 'in') {
|
||||
$unifont = 'freeserif';
|
||||
}
|
||||
break;
|
||||
|
||||
//CASE 'ccp': // CHAKMA
|
||||
//CASE 'lep': // LEPCHA
|
||||
case 'lif': // LIMBU
|
||||
$unifont = 'sun-exta';
|
||||
break;
|
||||
//CASE 'sat': // OL_CHIKI
|
||||
//CASE 'saz': // SAURASHTRA
|
||||
case 'syl': // SYLOTI_NAGRI
|
||||
$unifont = 'mph2bdamase';
|
||||
break;
|
||||
//CASE 'dgo': // TAKRI
|
||||
case 'dv':
|
||||
case 'div': // Divehi; Maldivian THAANA
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
|
||||
/* South East Asian */
|
||||
case 'km':
|
||||
case 'khm': // KHMER
|
||||
$unifont = 'khmeros';
|
||||
break;
|
||||
case 'lo':
|
||||
case 'lao': // LAO
|
||||
$unifont = 'dhyana';
|
||||
break;
|
||||
case 'my':
|
||||
case 'mya': // MYANMAR Burmese
|
||||
$unifont = 'tharlon'; // zawgyi-one is non-unicode compliant but in wide usage
|
||||
// ayar is also not strictly compliant
|
||||
// padaukbook is unicode compliant
|
||||
break;
|
||||
case 'th':
|
||||
case 'tha': // THAI
|
||||
$unifont = 'garuda';
|
||||
break;
|
||||
|
||||
// VIETNAMESE
|
||||
case 'vi':
|
||||
case 'vie': // Vietnamese
|
||||
$unifont = 'dejavusanscondensed';
|
||||
break;
|
||||
|
||||
//CASE 'ms': CASE 'msa': // Malay
|
||||
//CASE 'ban': // BALINESE
|
||||
//CASE 'bya': // BATAK
|
||||
case 'bug': // BUGINESE
|
||||
$unifont = 'freeserif';
|
||||
break;
|
||||
//CASE 'cjm': // CHAM
|
||||
//CASE 'jv': // JAVANESE
|
||||
case 'su': // SUNDANESE
|
||||
$unifont = 'sundaneseunicode';
|
||||
break;
|
||||
case 'tdd': // TAI_LE
|
||||
$unifont = 'tharlon';
|
||||
break;
|
||||
case 'blt': // TAI_VIET
|
||||
$unifont = 'taiheritagepro';
|
||||
break;
|
||||
|
||||
/* Phillipine */
|
||||
case 'bku': // BUHID
|
||||
$unifont = 'quivira';
|
||||
break;
|
||||
case 'hnn': // HANUNOO
|
||||
$unifont = 'quivira';
|
||||
break;
|
||||
case 'tl': // TAGALOG
|
||||
$unifont = 'quivira';
|
||||
break;
|
||||
case 'tbw': // TAGBANWA
|
||||
$unifont = 'quivira';
|
||||
break;
|
||||
|
||||
/* East Asian */
|
||||
case 'zh':
|
||||
case 'zho': // Chinese
|
||||
$unifont = 'sun-exta';
|
||||
if ($adobeCJK) {
|
||||
$unifont = 'gb';
|
||||
if ($country === 'hk' || $country === 'tw') {
|
||||
$unifont = 'big5';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'ko':
|
||||
case 'kor': // HANGUL Korean
|
||||
$unifont = 'unbatang';
|
||||
if ($adobeCJK) {
|
||||
$unifont = 'uhc';
|
||||
}
|
||||
break;
|
||||
case 'ja':
|
||||
case 'jpn': // Japanese HIRAGANA KATAKANA
|
||||
$unifont = 'sun-exta';
|
||||
if ($adobeCJK) {
|
||||
$unifont = 'sjis';
|
||||
}
|
||||
break;
|
||||
case 'ii':
|
||||
case 'iii': // Nuosu; Yi
|
||||
$unifont = 'sun-exta';
|
||||
if ($adobeCJK) {
|
||||
$unifont = 'gb';
|
||||
}
|
||||
break;
|
||||
case 'lis': // LISU
|
||||
$unifont = 'quivira';
|
||||
break;
|
||||
|
||||
/* American */
|
||||
case 'chr': // CHEROKEE
|
||||
case 'oj':
|
||||
case 'oji': // Ojibwe; Chippewa
|
||||
case 'cr':
|
||||
case 'cre': // Cree CANADIAN_ABORIGINAL
|
||||
case 'iu':
|
||||
case 'iku': // Inuktitut
|
||||
$unifont = 'aboriginalsans';
|
||||
break;
|
||||
|
||||
/* Undetermined language - script used */
|
||||
case 'und':
|
||||
$unifont = $this->fontByScript($script, $adobeCJK);
|
||||
break;
|
||||
}
|
||||
|
||||
return [$coreSuitable, $unifont];
|
||||
}
|
||||
|
||||
protected function fontByScript($script, $adobeCJK)
|
||||
{
|
||||
switch ($script) {
|
||||
/* European */
|
||||
case 'latn': // LATIN
|
||||
return 'dejavusanscondensed';
|
||||
case 'cyrl': // CYRILLIC
|
||||
return 'dejavusanscondensed'; /* freeserif best coverage for supplements etc. */
|
||||
case 'cprt': // CYPRIOT
|
||||
return 'aegean';
|
||||
case 'glag': // GLAGOLITIC
|
||||
return 'mph2bdamase';
|
||||
case 'linb': // LINEAR_B
|
||||
return 'aegean';
|
||||
case 'ogam': // OGHAM
|
||||
return 'dejavusans';
|
||||
case 'ital': // OLD_ITALIC
|
||||
return 'aegean';
|
||||
case 'runr': // RUNIC
|
||||
return 'sun-exta';
|
||||
case 'shaw': // SHAVIAN
|
||||
return 'mph2bdamase';
|
||||
|
||||
/* African */
|
||||
case 'egyp': // EGYPTIAN_HIEROGLYPHS
|
||||
return 'aegyptus';
|
||||
case 'ethi': // ETHIOPIC
|
||||
return 'abyssinicasil';
|
||||
//CASE 'merc': // MEROITIC_CURSIVE
|
||||
//CASE 'mero': // MEROITIC_HIEROGLYPHS
|
||||
case 'osma': // OSMANYA
|
||||
return 'mph2bdamase';
|
||||
case 'tfng': // TIFINAGH
|
||||
return 'dejavusans';
|
||||
|
||||
/* Middle Eastern */
|
||||
case 'arab': // ARABIC
|
||||
return 'xbriyaz';
|
||||
case 'xsux': // CUNEIFORM
|
||||
return 'akkadian';
|
||||
//CASE 'sarb': // OLD_SOUTH_ARABIAN
|
||||
//CASE 'prti': // INSCRIPTIONAL_PARTHIAN
|
||||
//CASE 'phli': // INSCRIPTIONAL_PAHLAVI
|
||||
|
||||
|
||||
/* Central Asian */
|
||||
//CASE 'orkh': // OLD_TURKIC
|
||||
//CASE 'phag': // PHAGS_PA (Vertical script)
|
||||
|
||||
/* South Asian */
|
||||
//CASE 'brah': // BRAHMI
|
||||
//CASE 'kthi': // KAITHI
|
||||
case 'khar': // KHAROSHTHI
|
||||
return 'mph2bdamase';
|
||||
case 'mtei': // MEETEI_MAYEK
|
||||
return 'eeyekunicode';
|
||||
//CASE 'shrd': // SHARADA
|
||||
//CASE 'sora': // SORA_SOMPENG
|
||||
|
||||
/* South East Asian */
|
||||
case 'kali': // KAYAH_LI
|
||||
return 'freemono';
|
||||
//CASE 'rjng': // REJANG
|
||||
case 'lana': // TAI_THAM
|
||||
return 'lannaalif';
|
||||
case 'talu': // NEW_TAI_LUE
|
||||
return 'daibannasilbook';
|
||||
|
||||
/* East Asian */
|
||||
case 'hans': // HAN (SIMPLIFIED)
|
||||
if ($adobeCJK) {
|
||||
return 'gb';
|
||||
}
|
||||
return 'sun-exta';
|
||||
case 'bopo': // BOPOMOFO
|
||||
return 'sun-exta';
|
||||
//CASE 'plrd': // MIAO
|
||||
case 'yiii': // YI
|
||||
return 'sun-exta';
|
||||
|
||||
/* American */
|
||||
case 'dsrt': // DESERET
|
||||
return 'mph2bdamase';
|
||||
|
||||
/* Other */
|
||||
case 'brai': // BRAILLE
|
||||
return 'dejavusans';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
29
Mpdf/Language/LanguageToFontInterface.php
Normal file
29
Mpdf/Language/LanguageToFontInterface.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Language;
|
||||
|
||||
/**
|
||||
* mPDF recognises IETF language tags as:
|
||||
* - a single primary language subtag composed of a two letter language code from ISO 639-1 (2002),
|
||||
* or a three letter code from ISO 639-2 (1998), ISO 639-3 (2007) or ISO 639-5 (2008) (usually written in lower case);
|
||||
* - an optional script subtag, composed of a four letter script code from ISO 15924 (usually written in title case);
|
||||
* - an optional region subtag composed of a two letter country code from ISO 3166-1 alpha-2 (usually written in upper case),
|
||||
* or a three digit code from UN M.49 for geographical regions;
|
||||
*
|
||||
* Subtags are not case sensitive, but the specification recommends using the same case as in the Language Subtag Registry,
|
||||
* where region subtags are uppercase, script subtags are titlecase and all other subtags are lowercase.
|
||||
*
|
||||
* Region subtags are often deprecated by the registration of specific primary language subtags from ISO 639-3 which are now
|
||||
* "preferred values". For example, "ar-DZ" is deprecated with the preferred value "arq" for Algerian Spoken Arabic;
|
||||
*
|
||||
* Example: Serbian written in the Cyrillic (sr-Cyrl) or Latin (sr-Latn) script
|
||||
*
|
||||
* und (for undetermined or undefined) is used in situations in which a script must be indicated but the language cannot be identified.
|
||||
* e.g. und-Cyrl is an undefined language written in Cyrillic script.
|
||||
*/
|
||||
interface LanguageToFontInterface
|
||||
{
|
||||
|
||||
public function getLanguageOptions($llcc, $adobeCJK);
|
||||
|
||||
}
|
||||
141
Mpdf/Language/ScriptToLanguage.php
Normal file
141
Mpdf/Language/ScriptToLanguage.php
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Language;
|
||||
|
||||
use Mpdf\Ucdn;
|
||||
|
||||
class ScriptToLanguage implements \Mpdf\Language\ScriptToLanguageInterface
|
||||
{
|
||||
|
||||
private $scriptDelimiterMap = [
|
||||
'viet' => "\x{01A0}\x{01A1}\x{01AF}\x{01B0}\x{1EA0}-\x{1EF1}",
|
||||
'persian' => "\x{067E}\x{0686}\x{0698}\x{06AF}",
|
||||
'urdu' => "\x{0679}\x{0688}\x{0691}\x{06BA}\x{06BE}\x{06C1}\x{06D2}",
|
||||
'pashto' => "\x{067C}\x{0681}\x{0685}\x{0689}\x{0693}\x{0696}\x{069A}\x{06BC}\x{06D0}", // ? and U+06AB, U+06CD
|
||||
'sindhi' => "\x{067A}\x{067B}\x{067D}\x{067F}\x{0680}\x{0684}\x{068D}\x{068A}\x{068F}\x{068C}\x{0687}\x{0683}\x{0699}\x{06AA}\x{06A6}\x{06BB}\x{06B1}\x{06B3}",
|
||||
];
|
||||
|
||||
private $scriptToLanguageMap = [
|
||||
/* European */
|
||||
Ucdn::SCRIPT_LATIN => 'und-Latn',
|
||||
Ucdn::SCRIPT_ARMENIAN => 'hy',
|
||||
Ucdn::SCRIPT_CYRILLIC => 'und-Cyrl',
|
||||
Ucdn::SCRIPT_GEORGIAN => 'ka',
|
||||
Ucdn::SCRIPT_GREEK => 'el',
|
||||
Ucdn::SCRIPT_COPTIC => 'cop',
|
||||
Ucdn::SCRIPT_GOTHIC => 'got',
|
||||
Ucdn::SCRIPT_CYPRIOT => 'und-Cprt',
|
||||
Ucdn::SCRIPT_GLAGOLITIC => 'und-Glag',
|
||||
Ucdn::SCRIPT_LINEAR_B => 'und-Linb',
|
||||
Ucdn::SCRIPT_OGHAM => 'und-Ogam',
|
||||
Ucdn::SCRIPT_OLD_ITALIC => 'und-Ital',
|
||||
Ucdn::SCRIPT_RUNIC => 'und-Runr',
|
||||
Ucdn::SCRIPT_SHAVIAN => 'und-Shaw',
|
||||
/* African */
|
||||
Ucdn::SCRIPT_ETHIOPIC => 'und-Ethi',
|
||||
Ucdn::SCRIPT_NKO => 'nqo',
|
||||
Ucdn::SCRIPT_BAMUM => 'bax',
|
||||
Ucdn::SCRIPT_VAI => 'vai',
|
||||
Ucdn::SCRIPT_EGYPTIAN_HIEROGLYPHS => 'und-Egyp',
|
||||
Ucdn::SCRIPT_MEROITIC_CURSIVE => 'und-Merc',
|
||||
Ucdn::SCRIPT_MEROITIC_HIEROGLYPHS => 'und-Mero',
|
||||
Ucdn::SCRIPT_OSMANYA => 'und-Osma',
|
||||
Ucdn::SCRIPT_TIFINAGH => 'und-Tfng',
|
||||
/* Middle Eastern */
|
||||
Ucdn::SCRIPT_ARABIC => 'und-Arab',
|
||||
Ucdn::SCRIPT_HEBREW => 'he',
|
||||
Ucdn::SCRIPT_SYRIAC => 'syr',
|
||||
Ucdn::SCRIPT_IMPERIAL_ARAMAIC => 'arc',
|
||||
Ucdn::SCRIPT_AVESTAN => 'ae',
|
||||
Ucdn::SCRIPT_CARIAN => 'xcr',
|
||||
Ucdn::SCRIPT_LYCIAN => 'xlc',
|
||||
Ucdn::SCRIPT_LYDIAN => 'xld',
|
||||
Ucdn::SCRIPT_MANDAIC => 'mid',
|
||||
Ucdn::SCRIPT_OLD_PERSIAN => 'peo',
|
||||
Ucdn::SCRIPT_PHOENICIAN => 'phn',
|
||||
Ucdn::SCRIPT_SAMARITAN => 'smp',
|
||||
Ucdn::SCRIPT_UGARITIC => 'uga',
|
||||
Ucdn::SCRIPT_CUNEIFORM => 'und-Xsux',
|
||||
Ucdn::SCRIPT_OLD_SOUTH_ARABIAN => 'und-Sarb',
|
||||
Ucdn::SCRIPT_INSCRIPTIONAL_PARTHIAN => 'und-Prti',
|
||||
Ucdn::SCRIPT_INSCRIPTIONAL_PAHLAVI => 'und-Phli',
|
||||
/* Central Asian */
|
||||
Ucdn::SCRIPT_MONGOLIAN => 'mn',
|
||||
Ucdn::SCRIPT_TIBETAN => 'bo',
|
||||
Ucdn::SCRIPT_OLD_TURKIC => 'und-Orkh',
|
||||
Ucdn::SCRIPT_PHAGS_PA => 'und-Phag',
|
||||
/* South Asian */
|
||||
Ucdn::SCRIPT_BENGALI => 'bn',
|
||||
Ucdn::SCRIPT_DEVANAGARI => 'hi',
|
||||
Ucdn::SCRIPT_GUJARATI => 'gu',
|
||||
Ucdn::SCRIPT_GURMUKHI => 'pa',
|
||||
Ucdn::SCRIPT_KANNADA => 'kn',
|
||||
Ucdn::SCRIPT_MALAYALAM => 'ml',
|
||||
Ucdn::SCRIPT_ORIYA => 'or',
|
||||
Ucdn::SCRIPT_SINHALA => 'si',
|
||||
Ucdn::SCRIPT_TAMIL => 'ta',
|
||||
Ucdn::SCRIPT_TELUGU => 'te',
|
||||
Ucdn::SCRIPT_CHAKMA => 'ccp',
|
||||
Ucdn::SCRIPT_LEPCHA => 'lep',
|
||||
Ucdn::SCRIPT_LIMBU => 'lif',
|
||||
Ucdn::SCRIPT_OL_CHIKI => 'sat',
|
||||
Ucdn::SCRIPT_SAURASHTRA => 'saz',
|
||||
Ucdn::SCRIPT_SYLOTI_NAGRI => 'syl',
|
||||
Ucdn::SCRIPT_TAKRI => 'dgo',
|
||||
Ucdn::SCRIPT_THAANA => 'dv',
|
||||
Ucdn::SCRIPT_BRAHMI => 'und-Brah',
|
||||
Ucdn::SCRIPT_KAITHI => 'und-Kthi',
|
||||
Ucdn::SCRIPT_KHAROSHTHI => 'und-Khar',
|
||||
Ucdn::SCRIPT_MEETEI_MAYEK => 'und-Mtei', /* or omp-Mtei */
|
||||
Ucdn::SCRIPT_SHARADA => 'und-Shrd',
|
||||
Ucdn::SCRIPT_SORA_SOMPENG => 'und-Sora',
|
||||
/* South East Asian */
|
||||
Ucdn::SCRIPT_KHMER => 'km',
|
||||
Ucdn::SCRIPT_LAO => 'lo',
|
||||
Ucdn::SCRIPT_MYANMAR => 'my',
|
||||
Ucdn::SCRIPT_THAI => 'th',
|
||||
Ucdn::SCRIPT_BALINESE => 'ban',
|
||||
Ucdn::SCRIPT_BATAK => 'bya',
|
||||
Ucdn::SCRIPT_BUGINESE => 'bug',
|
||||
Ucdn::SCRIPT_CHAM => 'cjm',
|
||||
Ucdn::SCRIPT_JAVANESE => 'jv',
|
||||
Ucdn::SCRIPT_KAYAH_LI => 'und-Kali',
|
||||
Ucdn::SCRIPT_REJANG => 'und-Rjng',
|
||||
Ucdn::SCRIPT_SUNDANESE => 'su',
|
||||
Ucdn::SCRIPT_TAI_LE => 'tdd',
|
||||
Ucdn::SCRIPT_TAI_THAM => 'und-Lana',
|
||||
Ucdn::SCRIPT_TAI_VIET => 'blt',
|
||||
Ucdn::SCRIPT_NEW_TAI_LUE => 'und-Talu',
|
||||
/* Phillipine */
|
||||
Ucdn::SCRIPT_BUHID => 'bku',
|
||||
Ucdn::SCRIPT_HANUNOO => 'hnn',
|
||||
Ucdn::SCRIPT_TAGALOG => 'tl',
|
||||
Ucdn::SCRIPT_TAGBANWA => 'tbw',
|
||||
/* East Asian */
|
||||
Ucdn::SCRIPT_HAN => 'und-Hans', // und-Hans (simplified) or und-Hant (Traditional)
|
||||
Ucdn::SCRIPT_HANGUL => 'ko',
|
||||
Ucdn::SCRIPT_HIRAGANA => 'ja',
|
||||
Ucdn::SCRIPT_KATAKANA => 'ja',
|
||||
Ucdn::SCRIPT_LISU => 'lis',
|
||||
Ucdn::SCRIPT_BOPOMOFO => 'und-Bopo', // zh-CN, zh-TW, zh-HK
|
||||
Ucdn::SCRIPT_MIAO => 'und-Plrd',
|
||||
Ucdn::SCRIPT_YI => 'und-Yiii',
|
||||
/* American */
|
||||
Ucdn::SCRIPT_CHEROKEE => 'chr',
|
||||
Ucdn::SCRIPT_CANADIAN_ABORIGINAL => 'cr',
|
||||
Ucdn::SCRIPT_DESERET => 'und-Dsrt',
|
||||
/* Other */
|
||||
Ucdn::SCRIPT_BRAILLE => 'und-Brai',
|
||||
];
|
||||
|
||||
public function getLanguageByScript($script)
|
||||
{
|
||||
return isset($this->scriptToLanguageMap[$script]) ? $this->scriptToLanguageMap[$script] : null;
|
||||
}
|
||||
|
||||
public function getLanguageDelimiters($language)
|
||||
{
|
||||
return isset($this->scriptDelimiterMap[$language]) ? $this->scriptDelimiterMap[$language] : null;
|
||||
}
|
||||
|
||||
}
|
||||
12
Mpdf/Language/ScriptToLanguageInterface.php
Normal file
12
Mpdf/Language/ScriptToLanguageInterface.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Language;
|
||||
|
||||
interface ScriptToLanguageInterface
|
||||
{
|
||||
|
||||
public function getLanguageByScript($script);
|
||||
|
||||
public function getLanguageDelimiters($language);
|
||||
|
||||
}
|
||||
22
Mpdf/Log/Context.php
Normal file
22
Mpdf/Log/Context.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Log;
|
||||
|
||||
class Context
|
||||
{
|
||||
|
||||
const STATISTICS = 'statistics';
|
||||
|
||||
const PDFA_PDFX = 'pdfa_pdfx';
|
||||
|
||||
const UTF8 = 'utf8';
|
||||
|
||||
const REMOTE_CONTENT = 'remote_content';
|
||||
|
||||
const IMAGES = 'images';
|
||||
|
||||
const CSS_SIZE_CONVERSION = 'css_size_conversion';
|
||||
|
||||
const HTML_MARKUP = 'html_markup';
|
||||
|
||||
}
|
||||
27332
Mpdf/Mpdf.php
Normal file
27332
Mpdf/Mpdf.php
Normal file
File diff suppressed because it is too large
Load Diff
8
Mpdf/MpdfException.php
Normal file
8
Mpdf/MpdfException.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class MpdfException extends \ErrorException
|
||||
{
|
||||
|
||||
}
|
||||
8
Mpdf/MpdfImageException.php
Normal file
8
Mpdf/MpdfImageException.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class MpdfImageException extends \Mpdf\MpdfException
|
||||
{
|
||||
|
||||
}
|
||||
6211
Mpdf/Otl.php
Normal file
6211
Mpdf/Otl.php
Normal file
File diff suppressed because it is too large
Load Diff
4369
Mpdf/OtlDump.php
Normal file
4369
Mpdf/OtlDump.php
Normal file
File diff suppressed because it is too large
Load Diff
15
Mpdf/Output/Destination.php
Normal file
15
Mpdf/Output/Destination.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Output;
|
||||
|
||||
class Destination
|
||||
{
|
||||
|
||||
const FILE = 'F';
|
||||
|
||||
const DOWNLOAD = 'D';
|
||||
|
||||
const STRING_RETURN = 'S';
|
||||
|
||||
const INLINE = 'I';
|
||||
}
|
||||
83
Mpdf/PageFormat.php
Normal file
83
Mpdf/PageFormat.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
class PageFormat
|
||||
{
|
||||
|
||||
/**
|
||||
* This method returns an array of width and height of given named format.
|
||||
*
|
||||
* Returned values are milimeters multiplied by scale factor of 72 / 25.4
|
||||
*
|
||||
* @param string $name
|
||||
* @return float[] Width and height of given format
|
||||
*/
|
||||
public static function getSizeFromName($name)
|
||||
{
|
||||
$format = strtoupper($name);
|
||||
$formats = [
|
||||
'4A0' => [4767.87, 6740.79],
|
||||
'2A0' => [3370.39, 4767.87],
|
||||
'A0' => [2383.94, 3370.39],
|
||||
'A1' => [1683.78, 2383.94],
|
||||
'A2' => [1190.55, 1683.78],
|
||||
'A3' => [841.89, 1190.55],
|
||||
'A4' => [595.28, 841.89],
|
||||
'A5' => [419.53, 595.28],
|
||||
'A6' => [297.64, 419.53],
|
||||
'A7' => [209.76, 297.64],
|
||||
'A8' => [147.40, 209.76],
|
||||
'A9' => [104.88, 147.40],
|
||||
'A10' => [73.70, 104.88],
|
||||
'B0' => [2834.65, 4008.19],
|
||||
'B1' => [2004.09, 2834.65],
|
||||
'B2' => [1417.32, 2004.09],
|
||||
'B3' => [1000.63, 1417.32],
|
||||
'B4' => [708.66, 1000.63],
|
||||
'B5' => [498.90, 708.66],
|
||||
'B6' => [354.33, 498.90],
|
||||
'B7' => [249.45, 354.33],
|
||||
'B8' => [175.75, 249.45],
|
||||
'B9' => [124.72, 175.75],
|
||||
'B10' => [87.87, 124.72],
|
||||
'C0' => [2599.37, 3676.54],
|
||||
'C1' => [1836.85, 2599.37],
|
||||
'C2' => [1298.27, 1836.85],
|
||||
'C3' => [918.43, 1298.27],
|
||||
'C4' => [649.13, 918.43],
|
||||
'C5' => [459.21, 649.13],
|
||||
'C6' => [323.15, 459.21],
|
||||
'C7' => [229.61, 323.15],
|
||||
'C8' => [161.57, 229.61],
|
||||
'C9' => [113.39, 161.57],
|
||||
'C10' => [79.37, 113.39],
|
||||
'RA0' => [2437.80, 3458.27],
|
||||
'RA1' => [1729.13, 2437.80],
|
||||
'RA2' => [1218.90, 1729.13],
|
||||
'RA3' => [864.57, 1218.90],
|
||||
'RA4' => [609.45, 864.57],
|
||||
'SRA0' => [2551.18, 3628.35],
|
||||
'SRA1' => [1814.17, 2551.18],
|
||||
'SRA2' => [1275.59, 1814.17],
|
||||
'SRA3' => [907.09, 1275.59],
|
||||
'SRA4' => [637.80, 907.09],
|
||||
'LETTER' => [612.00, 792.00],
|
||||
'LEGAL' => [612.00, 1008.00],
|
||||
'LEDGER' => [1224.00, 792.00],
|
||||
'TABLOID' => [792.00, 1224.00],
|
||||
'EXECUTIVE' => [521.86, 756.00],
|
||||
'FOLIO' => [612.00, 936.00],
|
||||
'B' => [362.83, 561.26], // 'B' format paperback size 128x198mm
|
||||
'A' => [314.65, 504.57], // 'A' format paperback size 111x178mm
|
||||
'DEMY' => [382.68, 612.28], // 'Demy' format paperback size 135x216mm
|
||||
'ROYAL' => [433.70, 663.30], // 'Royal' format paperback size 153x234mm
|
||||
];
|
||||
|
||||
if (!isset($formats[$format])) {
|
||||
throw new \Mpdf\MpdfException(sprintf('Unknown page format %s', $format));
|
||||
}
|
||||
|
||||
return $formats[$format];
|
||||
}
|
||||
}
|
||||
360
Mpdf/Pdf/Protection.php
Normal file
360
Mpdf/Pdf/Protection.php
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Pdf;
|
||||
|
||||
use Mpdf\Pdf\Protection\UniqidGenerator;
|
||||
|
||||
class Protection
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $lastRc4Key;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $lastRc4KeyC;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $useRC128Encryption;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $encryptionKey;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $padding;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $uniqid;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $oValue;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $uValue;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $pValue;
|
||||
|
||||
/**
|
||||
* @var int[] Array of permission => byte representation
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Pdf\Protection\UniqidGenerator
|
||||
*/
|
||||
private $uniqidGenerator;
|
||||
|
||||
public function __construct(UniqidGenerator $uniqidGenerator)
|
||||
{
|
||||
if (!function_exists('random_int') || !function_exists('random_bytes')) {
|
||||
throw new \Mpdf\MpdfException(
|
||||
'Unable to set PDF file protection, CSPRNG Functions are not available. '
|
||||
. 'Use paragonie/random_compat polyfill or upgrade to PHP 7.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->uniqidGenerator = $uniqidGenerator;
|
||||
|
||||
$this->lastRc4Key = '';
|
||||
|
||||
$this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08" .
|
||||
"\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
|
||||
|
||||
$this->useRC128Encryption = false;
|
||||
|
||||
$this->options = [
|
||||
'print' => 4, // bit 3
|
||||
'modify' => 8, // bit 4
|
||||
'copy' => 16, // bit 5
|
||||
'annot-forms' => 32, // bit 6
|
||||
'fill-forms' => 256, // bit 9
|
||||
'extract' => 512, // bit 10
|
||||
'assemble' => 1024, // bit 11
|
||||
'print-highres' => 2048 // bit 12
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $permissions
|
||||
* @param string $user_pass
|
||||
* @param string $owner_pass
|
||||
* @param int $length
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setProtection($permissions = [], $user_pass = '', $owner_pass = null, $length = 40)
|
||||
{
|
||||
if (is_string($permissions) && strlen($permissions) > 0) {
|
||||
$permissions = [$permissions];
|
||||
} elseif (!is_array($permissions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$protection = $this->getProtectionBitsFromOptions($permissions);
|
||||
|
||||
if ($length === 128) {
|
||||
$this->useRC128Encryption = true;
|
||||
} elseif ($length !== 40) {
|
||||
throw new \Mpdf\MpdfException('PDF protection only allows lenghts of 40 or 128');
|
||||
}
|
||||
|
||||
if ($owner_pass === null) {
|
||||
$owner_pass = bin2hex(random_bytes(23));
|
||||
}
|
||||
|
||||
$this->generateEncryptionKey($user_pass, $owner_pass, $protection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute key depending on object number where the encrypted data is stored
|
||||
*
|
||||
* @param int $n
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function objectKey($n)
|
||||
{
|
||||
if ($this->useRC128Encryption) {
|
||||
$len = 16;
|
||||
} else {
|
||||
$len = 10;
|
||||
}
|
||||
|
||||
return substr($this->md5toBinary($this->encryptionKey . pack('VXxx', $n)), 0, $len);
|
||||
}
|
||||
|
||||
/**
|
||||
* RC4 is the standard encryption algorithm used in PDF format
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function rc4($key, $text)
|
||||
{
|
||||
if ($this->lastRc4Key != $key) {
|
||||
$k = str_repeat($key, 256 / strlen($key) + 1);
|
||||
$rc4 = range(0, 255);
|
||||
$j = 0;
|
||||
for ($i = 0; $i < 256; $i++) {
|
||||
$t = $rc4[$i];
|
||||
$j = ($j + $t + ord($k[$i])) % 256;
|
||||
$rc4[$i] = $rc4[$j];
|
||||
$rc4[$j] = $t;
|
||||
}
|
||||
$this->lastRc4Key = $key;
|
||||
$this->lastRc4KeyC = $rc4;
|
||||
} else {
|
||||
$rc4 = $this->lastRc4KeyC;
|
||||
}
|
||||
|
||||
$len = strlen($text);
|
||||
$a = 0;
|
||||
$b = 0;
|
||||
$out = '';
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$a = ($a + 1) % 256;
|
||||
$t = $rc4[$a];
|
||||
$b = ($b + $t) % 256;
|
||||
$rc4[$a] = $rc4[$b];
|
||||
$rc4[$b] = $t;
|
||||
$k = $rc4[($rc4[$a] + $rc4[$b]) % 256];
|
||||
$out .= chr(ord($text[$i]) ^ $k);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUseRC128Encryption()
|
||||
{
|
||||
return $this->useRC128Encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUniqid()
|
||||
{
|
||||
return $this->uniqid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOValue()
|
||||
{
|
||||
return $this->oValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getUValue()
|
||||
{
|
||||
return $this->uValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPValue()
|
||||
{
|
||||
return $this->pValue;
|
||||
}
|
||||
|
||||
private function getProtectionBitsFromOptions($permissions)
|
||||
{
|
||||
// bit 31 = 1073741824
|
||||
// bit 32 = 2147483648
|
||||
// bits 13-31 = 2147479552
|
||||
// bits 13-32 = 4294963200 + 192 = 4294963392
|
||||
|
||||
$protection = 4294963392; // bits 7, 8, 13-32
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
if (!isset($this->options[$permission])) {
|
||||
throw new \Mpdf\MpdfException(sprintf('Invalid permission type "%s"', $permission));
|
||||
}
|
||||
if ($this->options[$permission] > 32) {
|
||||
$this->useRC128Encryption = true;
|
||||
}
|
||||
if (isset($this->options[$permission])) {
|
||||
$protection += $this->options[$permission];
|
||||
}
|
||||
}
|
||||
|
||||
return $protection;
|
||||
}
|
||||
|
||||
private function oValue($user_pass, $owner_pass)
|
||||
{
|
||||
$tmp = $this->md5toBinary($owner_pass);
|
||||
if ($this->useRC128Encryption) {
|
||||
for ($i = 0; $i < 50; ++$i) {
|
||||
$tmp = $this->md5toBinary($tmp);
|
||||
}
|
||||
}
|
||||
if ($this->useRC128Encryption) {
|
||||
$keybytelen = (128 / 8);
|
||||
} else {
|
||||
$keybytelen = (40 / 8);
|
||||
}
|
||||
$owner_rc4_key = substr($tmp, 0, $keybytelen);
|
||||
$enc = $this->rc4($owner_rc4_key, $user_pass);
|
||||
if ($this->useRC128Encryption) {
|
||||
$len = strlen($owner_rc4_key);
|
||||
for ($i = 1; $i <= 19; ++$i) {
|
||||
$key = '';
|
||||
for ($j = 0; $j < $len; ++$j) {
|
||||
$key .= chr(ord($owner_rc4_key[$j]) ^ $i);
|
||||
}
|
||||
$enc = $this->rc4($key, $enc);
|
||||
}
|
||||
}
|
||||
|
||||
return $enc;
|
||||
}
|
||||
|
||||
private function uValue()
|
||||
{
|
||||
if ($this->useRC128Encryption) {
|
||||
$tmp = $this->md5toBinary($this->padding . $this->hexToString($this->uniqid));
|
||||
$enc = $this->rc4($this->encryptionKey, $tmp);
|
||||
$len = strlen($tmp);
|
||||
for ($i = 1; $i <= 19; ++$i) {
|
||||
$key = '';
|
||||
for ($j = 0; $j < $len; ++$j) {
|
||||
$key .= chr(ord($this->encryptionKey[$j]) ^ $i);
|
||||
}
|
||||
$enc = $this->rc4($key, $enc);
|
||||
}
|
||||
$enc .= str_repeat("\x00", 16);
|
||||
|
||||
return substr($enc, 0, 32);
|
||||
} else {
|
||||
return $this->rc4($this->encryptionKey, $this->padding);
|
||||
}
|
||||
}
|
||||
|
||||
private function generateEncryptionKey($user_pass, $owner_pass, $protection)
|
||||
{
|
||||
// Pad passwords
|
||||
$user_pass = substr($user_pass . $this->padding, 0, 32);
|
||||
$owner_pass = substr($owner_pass . $this->padding, 0, 32);
|
||||
|
||||
$this->oValue = $this->oValue($user_pass, $owner_pass);
|
||||
|
||||
$this->uniqid = $this->uniqidGenerator->generate();
|
||||
|
||||
// Compute encyption key
|
||||
if ($this->useRC128Encryption) {
|
||||
$keybytelen = (128 / 8);
|
||||
} else {
|
||||
$keybytelen = (40 / 8);
|
||||
}
|
||||
|
||||
$prot = sprintf('%032b', $protection);
|
||||
|
||||
$perms = chr(bindec(substr($prot, 24, 8)));
|
||||
$perms .= chr(bindec(substr($prot, 16, 8)));
|
||||
$perms .= chr(bindec(substr($prot, 8, 8)));
|
||||
$perms .= chr(bindec(substr($prot, 0, 8)));
|
||||
|
||||
$tmp = $this->md5toBinary($user_pass . $this->oValue . $perms . $this->hexToString($this->uniqid));
|
||||
|
||||
if ($this->useRC128Encryption) {
|
||||
for ($i = 0; $i < 50; ++$i) {
|
||||
$tmp = $this->md5toBinary(substr($tmp, 0, $keybytelen));
|
||||
}
|
||||
}
|
||||
|
||||
$this->encryptionKey = substr($tmp, 0, $keybytelen);
|
||||
|
||||
$this->uValue = $this->uValue();
|
||||
$this->pValue = $protection;
|
||||
}
|
||||
|
||||
private function md5toBinary($string)
|
||||
{
|
||||
return pack('H*', md5($string));
|
||||
}
|
||||
|
||||
private function hexToString($hs)
|
||||
{
|
||||
$s = '';
|
||||
$len = strlen($hs);
|
||||
if (($len % 2) != 0) {
|
||||
$hs .= '0';
|
||||
++$len;
|
||||
}
|
||||
for ($i = 0; $i < $len; $i += 2) {
|
||||
$s .= chr(hexdec($hs[$i] . $hs[($i + 1)]));
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
32
Mpdf/Pdf/Protection/UniqidGenerator.php
Normal file
32
Mpdf/Pdf/Protection/UniqidGenerator.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf\Pdf\Protection;
|
||||
|
||||
class UniqidGenerator
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (!function_exists('random_int') || !function_exists('random_bytes')) {
|
||||
throw new \Mpdf\MpdfException(
|
||||
'Unable to set PDF file protection, CSPRNG Functions are not available. '
|
||||
. 'Use paragonie/random_compat polyfill or upgrade to PHP 7.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function generate()
|
||||
{
|
||||
$chars = 'ABCDEF1234567890';
|
||||
$id = '';
|
||||
|
||||
for ($i = 0; $i < 32; $i++) {
|
||||
$id .= $chars[random_int(0, 15)];
|
||||
}
|
||||
|
||||
return md5($id);
|
||||
}
|
||||
}
|
||||
148
Mpdf/RemoteContentFetcher.php
Normal file
148
Mpdf/RemoteContentFetcher.php
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
namespace Mpdf;
|
||||
|
||||
use Mpdf\Utils\Arrays;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Mpdf\Log\Context as LogContext;
|
||||
|
||||
class RemoteContentFetcher implements \Psr\Log\LoggerAwareInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Mpdf\Mpdf
|
||||
*/
|
||||
private $mpdf;
|
||||
|
||||
/**
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
public function __construct(Mpdf $mpdf, LoggerInterface $logger)
|
||||
{
|
||||
$this->mpdf = $mpdf;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function getFileContentsByCurl($url)
|
||||
{
|
||||
$this->logger->debug(sprintf('Fetching (cURL) content of remote URL "%s"', $url), ['context' => LogContext::REMOTE_CONTENT]);
|
||||
|
||||
$ch = curl_init($url);
|
||||
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $this->mpdf->curlUserAgent);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->mpdf->curlTimeout);
|
||||
|
||||
if ($this->mpdf->curlFollowLocation) {
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
|
||||
}
|
||||
|
||||
if ($this->mpdf->curlAllowUnsafeSslRequests) {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
}
|
||||
|
||||
if (is_file($this->mpdf->curlCaCertificate)) {
|
||||
curl_setopt($ch, CURLOPT_CAINFO, $this->mpdf->curlCaCertificate);
|
||||
}
|
||||
|
||||
if ($this->mpdf->curlProxy) {
|
||||
curl_setopt($ch, CURLOPT_PROXY, $this->mpdf->curlProxy);
|
||||
if ($this->mpdf->curlProxyAuth) {
|
||||
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $this->mpdf->curlProxyAuth);
|
||||
}
|
||||
}
|
||||
|
||||
$data = curl_exec($ch);
|
||||
|
||||
if (curl_error($ch)) {
|
||||
$message = sprintf('cURL error: "%s"', curl_error($ch));
|
||||
$this->logger->error($message, ['context' => LogContext::REMOTE_CONTENT]);
|
||||
|
||||
if ($this->mpdf->debug) {
|
||||
throw new \Mpdf\MpdfException($message);
|
||||
}
|
||||
}
|
||||
|
||||
$info = curl_getinfo($ch);
|
||||
if (isset($info['http_code']) && $info['http_code'] !== 200) {
|
||||
$message = sprintf('HTTP error: %d', $info['http_code']);
|
||||
$this->logger->error($message, ['context' => LogContext::REMOTE_CONTENT]);
|
||||
|
||||
if ($this->mpdf->debug) {
|
||||
throw new \Mpdf\MpdfException($message);
|
||||
}
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getFileContentsBySocket($url)
|
||||
{
|
||||
$this->logger->debug(sprintf('Fetching (socket) content of remote URL "%s"', $url), ['context' => LogContext::REMOTE_CONTENT]);
|
||||
// mPDF 5.7.3
|
||||
|
||||
$timeout = 1;
|
||||
$p = parse_url($url);
|
||||
|
||||
$file = Arrays::get($p, 'path', '');
|
||||
$scheme = Arrays::get($p, 'scheme', '');
|
||||
$port = Arrays::get($p, 'port', 80);
|
||||
$prefix = '';
|
||||
|
||||
if ($scheme === 'https') {
|
||||
$prefix = 'ssl://';
|
||||
$port = Arrays::get($p, 'port', 443);
|
||||
}
|
||||
|
||||
$query = Arrays::get($p, 'query', null);
|
||||
if ($query) {
|
||||
$file .= '?' . $query;
|
||||
}
|
||||
|
||||
if (!($fh = @fsockopen($prefix . $p['host'], $port, $errno, $errstr, $timeout))) {
|
||||
$this->logger->error(sprintf('Socket error "%s": "%s"', $errno, $errstr), ['context' => LogContext::REMOTE_CONTENT]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$getstring = 'GET ' . $file . " HTTP/1.0 \r\n" .
|
||||
'Host: ' . $p['host'] . " \r\n" .
|
||||
"Connection: close\r\n\r\n";
|
||||
|
||||
fwrite($fh, $getstring);
|
||||
|
||||
// Get rid of HTTP header
|
||||
$s = fgets($fh, 1024);
|
||||
if (!$s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!feof($fh)) {
|
||||
$s = fgets($fh, 1024);
|
||||
if ($s === "\r\n") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$data = '';
|
||||
|
||||
while (!feof($fh)) {
|
||||
$data .= fgets($fh, 1024);
|
||||
}
|
||||
|
||||
fclose($fh);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function setLogger(LoggerInterface $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user