protected static function _resolve_target($node, $target, $value) { if ($target[0] === "!") { $func = "_" . m_mb_substr($target, 1); return self::$func($node, $value); } return $value ? sprintf($target, $value) : ""; }
static function getArray($colour) { $c = array(null, null, null, null, "hex" => null); if (is_array($colour)) { $c = $colour; $c["c"] = $c[0]; $c["m"] = $c[1]; $c["y"] = $c[2]; $c["k"] = $c[3]; $c["hex"] = "cmyk({$c['0']},{$c['1']},{$c['2']},{$c['3']})"; } else { $c[0] = hexdec(m_mb_substr($colour, 0, 2)) / 0xff; $c[1] = hexdec(m_mb_substr($colour, 2, 2)) / 0xff; $c[2] = hexdec(m_mb_substr($colour, 4, 2)) / 0xff; $c["r"] = $c[0]; $c["g"] = $c[1]; $c["b"] = $c[2]; $c["hex"] = "#{$colour}"; } return $c; }
protected function _layout_line() { $frame = $this->_frame; $style = $frame->get_style(); $text = $frame->get_text(); $size = $style->font_size; $font = $style->font_family; $style->height = Font_Metrics::get_font_height($font, $size); $split = false; $add_line = false; switch (strtolower($style->text_transform)) { default: break; case "capitalize": $text = mb_convert_case($text, MB_CASE_TITLE); break; case "uppercase": $text = mb_convert_case($text, MB_CASE_UPPER); break; case "lowercase": $text = mb_convert_case($text, MB_CASE_LOWER); break; } switch ($style->white_space) { default: case "normal": $frame->set_text($text = $this->_collapse_white_space($text)); if ($text == "") { break; } $split = $this->_line_break($text); break; case "pre": $split = $this->_newline_break($text); $add_line = $split !== false; break; case "nowrap": $frame->set_text($text = $this->_collapse_white_space($text)); break; case "pre-wrap": $split = $this->_newline_break($text); if (($tmp = $this->_line_break($text)) !== false) { $add_line = $split < $tmp; $split = min($tmp, $split); } else { $add_line = true; } break; case "pre-line": $frame->set_text($text = preg_replace("/[ \t]+/u", " ", $text)); if ($text == "") { break; } $split = $this->_newline_break($text); if (($tmp = $this->_line_break($text)) !== false) { $add_line = $split < $tmp; $split = min($tmp, $split); } else { $add_line = true; } break; } if ($text === "") { return; } if ($split !== false) { if ($split == 0 && $text === " ") { $frame->set_text(""); return; } if ($split == 0) { $this->_block_parent->add_line(); $frame->position(); $this->_layout_line(); } else { if ($split < mb_strlen($frame->get_text())) { $frame->split_text($split); $t = $frame->get_text(); if ($split > 1 && $t[$split - 1] === "\n" && !$frame->is_pre()) { $frame->set_text(m_mb_substr($t, 0, -1)); } } } if ($add_line) { $this->_block_parent->add_line(); $frame->position(); } } else { $t = $frame->get_text(); $parent = $frame->get_parent(); $is_inline_frame = get_class($parent) === 'Inline_Frame_Decorator'; if (!$is_inline_frame && !$frame->get_next_sibling() || $is_inline_frame && !$parent->get_next_sibling()) { $t = rtrim($t); } if (!$is_inline_frame && !$frame->get_prev_sibling()) { $t = ltrim($t); } $frame->set_text($t); } $width = $frame->recalculate_width(); }
function install_font_family($fontname, $normal, $bold = null, $italic = null, $bold_italic = null) { Font_Metrics::init(); if (!is_readable($normal)) { throw new DOMPDF_Exception("Unable to read '{$normal}'."); } $dir = dirname($normal); $basename = basename($normal); $last_dot = strrpos($basename, '.'); if ($last_dot !== false) { $file = substr($basename, 0, $last_dot); $ext = strtolower(substr($basename, $last_dot)); } else { $file = $basename; $ext = ''; } if (!in_array($ext, array(".ttf", ".otf"))) { throw new DOMPDF_Exception("Unable to process fonts of type '{$ext}'."); } $path = "{$dir}/{$file}"; $patterns = array("bold" => array("_Bold", "b", "B", "bd", "BD"), "italic" => array("_Italic", "i", "I"), "bold_italic" => array("_Bold_Italic", "bi", "BI", "ib", "IB")); foreach ($patterns as $type => $_patterns) { if (!isset(${$type}) || !is_readable(${$type})) { foreach ($_patterns as $_pattern) { if (is_readable("{$path}{$_pattern}{$ext}")) { ${$type} = "{$path}{$_pattern}{$ext}"; break; } } if (is_null(${$type})) { echo "Unable to find {$type} face file.\n"; } } } $fonts = compact("normal", "bold", "italic", "bold_italic"); $entry = array(); foreach ($fonts as $var => $src) { if (is_null($src)) { $entry[$var] = DOMPDF_FONT_DIR . m_mb_substr(basename($normal), 0, -4); continue; } if (!is_readable($src)) { throw new DOMPDF_Exception("Requested font '{$src}' is not readable"); } $dest = DOMPDF_FONT_DIR . basename($src); if (!is_writeable(dirname($dest))) { throw new DOMPDF_Exception("Unable to write to destination '{$dest}'."); } echo "Copying {$src} to {$dest}...\n"; if (!copy($src, $dest)) { throw new DOMPDF_Exception("Unable to copy '{$src}' to '{$dest}'"); } $entry_name = m_mb_substr($dest, 0, -4); echo "Generating Adobe Font Metrics for {$entry_name}...\n"; $font_obj = Font::load($dest); $font_obj->saveAdobeFontMetrics("{$entry_name}.ufm"); $entry[$var] = $entry_name; } Font_Metrics::set_font_family($fontname, $entry); Font_Metrics::save_font_families(); }
function addPngFromBuf($file, $x, $y, $w = 0, $h = 0, &$data, $is_mask = false, $mask = null) { if (isset($this->imagelist[$file])) { $data = null; $info['width'] = $this->imagelist[$file]['w']; $info['height'] = $this->imagelist[$file]['h']; $label = $this->imagelist[$file]['label']; } else { if ($data == null) { $this->addMessage('addPngFromBuf error - (' . $imgname . ') data not present!'); return; } $error = 0; if (!$error) { $header = chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10); if (m_mb_substr($data, 0, 8, '8bit') != $header) { $error = 1; if (DEBUGPNG) { print '[addPngFromFile this file does not have a valid header ' . $file . ']'; } $errormsg = 'this file does not have a valid header'; } } if (!$error) { $p = 8; $len = mb_strlen($data, '8bit'); $haveHeader = 0; $info = array(); $idata = ''; $pdata = ''; while ($p < $len) { $chunkLen = $this->PRVT_getBytes($data, $p, 4); $chunkType = m_mb_substr($data, $p + 4, 4, '8bit'); switch ($chunkType) { case 'IHDR': $info['width'] = $this->PRVT_getBytes($data, $p + 8, 4); $info['height'] = $this->PRVT_getBytes($data, $p + 12, 4); $info['bitDepth'] = ord($data[$p + 16]); $info['colorType'] = ord($data[$p + 17]); $info['compressionMethod'] = ord($data[$p + 18]); $info['filterMethod'] = ord($data[$p + 19]); $info['interlaceMethod'] = ord($data[$p + 20]); $haveHeader = 1; if ($info['compressionMethod'] != 0) { $error = 1; if (DEBUGPNG) { print '[addPngFromFile unsupported compression method ' . $file . ']'; } $errormsg = 'unsupported compression method'; } if ($info['filterMethod'] != 0) { $error = 1; if (DEBUGPNG) { print '[addPngFromFile unsupported filter method ' . $file . ']'; } $errormsg = 'unsupported filter method'; } break; case 'PLTE': $pdata .= m_mb_substr($data, $p + 8, $chunkLen, '8bit'); break; case 'IDAT': $idata .= m_mb_substr($data, $p + 8, $chunkLen, '8bit'); break; case 'tRNS': $transparency = array(); switch ($info['colorType']) { case 3: $transparency['type'] = 'indexed'; $numPalette = mb_strlen($pdata, '8bit') / 3; $trans = 0; for ($i = $chunkLen; $i >= 0; $i--) { if (ord($data[$p + 8 + $i]) == 0) { $trans = $i; } } $transparency['data'] = $trans; break; case 0: $transparency['type'] = 'indexed'; $transparency['data'] = ord($data[$p + 8 + 1]); break; case 2: $transparency['r'] = $this->PRVT_getBytes($data, $p + 8, 2); $transparency['g'] = $this->PRVT_getBytes($data, $p + 10, 2); $transparency['b'] = $this->PRVT_getBytes($data, $p + 12, 2); $transparency['type'] = 'color-key'; break; default: if (DEBUGPNG) { print '[addPngFromFile unsupported transparency type ' . $file . ']'; } break; } break; default: break; } $p += $chunkLen + 12; } if (!$haveHeader) { $error = 1; if (DEBUGPNG) { print '[addPngFromFile information header is missing ' . $file . ']'; } $errormsg = 'information header is missing'; } if (isset($info['interlaceMethod']) && $info['interlaceMethod']) { $error = 1; if (DEBUGPNG) { print '[addPngFromFile no support for interlaced images in pdf ' . $file . ']'; } $errormsg = 'There appears to be no support for interlaced images in pdf.'; } } if (!$error && $info['bitDepth'] > 8) { $error = 1; if (DEBUGPNG) { print '[addPngFromFile bit depth of 8 or less is supported ' . $file . ']'; } $errormsg = 'only bit depth of 8 or less is supported'; } if (!$error) { switch ($info['colorType']) { case 3: $color = 'DeviceRGB'; $ncolor = 1; break; case 2: $color = 'DeviceRGB'; $ncolor = 3; break; case 0: $color = 'DeviceGray'; $ncolor = 1; break; default: $error = 1; if (DEBUGPNG) { print '[addPngFromFile alpha channel not supported: ' . $info['colorType'] . ' ' . $file . ']'; } $errormsg = 'transparancey alpha channel not supported, transparency only supported for palette images.'; } } if ($error) { $this->addMessage('PNG error - (' . $file . ') ' . $errormsg); return; } $this->numImages++; $im = $this->numImages; $label = "I{$im}"; $this->numObj++; $options = array('label' => $label, 'data' => $idata, 'bitsPerComponent' => $info['bitDepth'], 'pdata' => $pdata, 'iw' => $info['width'], 'ih' => $info['height'], 'type' => 'png', 'color' => $color, 'ncolor' => $ncolor, 'masked' => $mask, 'isMask' => $is_mask); if (isset($transparency)) { $options['transparency'] = $transparency; } $this->o_image($this->numObj, 'new', $options); $this->imagelist[$file] = array('label' => $label, 'w' => $info['width'], 'h' => $info['height']); } if ($is_mask) { return; } if ($w <= 0 && $h <= 0) { $w = $info['width']; $h = $info['height']; } if ($w <= 0) { $w = $h / $info['height'] * $info['width']; } if ($h <= 0) { $h = $w * $info['height'] / $info['width']; } $this->objects[$this->currentContents]['c'] .= sprintf("\nq\n%.3F 0 0 %.3F %.3F %.3F cm /%s Do\nQ", $w, $h, $x, $y, $label); }
function explode_url($url) { $protocol = ""; $host = ""; $path = ""; $file = ""; $arr = parse_url($url); if (isset($arr["scheme"]) && $arr["scheme"] !== "file" && strlen($arr["scheme"]) > 1) { $protocol = $arr["scheme"] . "://"; if (isset($arr["user"])) { $host .= $arr["user"]; if (isset($arr["pass"])) { $host .= "@" . $arr["pass"]; } $host .= ":"; } if (isset($arr["host"])) { $host .= $arr["host"]; } if (isset($arr["port"])) { $host .= ":" . $arr["port"]; } if (isset($arr["path"]) && $arr["path"] !== "") { if ($arr["path"][mb_strlen($arr["path"]) - 1] === "/") { $path = $arr["path"]; $file = ""; } else { $path = rtrim(dirname($arr["path"]), '/\\') . "/"; $file = basename($arr["path"]); } } if (isset($arr["query"])) { $file .= "?" . $arr["query"]; } if (isset($arr["fragment"])) { $file .= "#" . $arr["fragment"]; } } else { $i = mb_strpos($url, "file://"); if ($i !== false) { $url = m_mb_substr($url, $i + 7); } $protocol = ""; $host = ""; $file = basename($url); $path = dirname($url); if ($path !== false) { $path .= '/'; } else { $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://'; $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : php_uname("n"); if (substr($arr["path"], 0, 1) === '/') { $path = dirname($arr["path"]); } else { $path = '/' . rtrim(dirname($_SERVER["SCRIPT_NAME"]), '/') . '/' . $arr["path"]; } } } $ret = array($protocol, $host, $path, $file, "protocol" => $protocol, "host" => $host, "path" => $path, "file" => $file); return $ret; }
protected function _parse_content() { $re = "/\n" . "\\s(counters?\\([^)]*\\))|\n" . "\\A(counters?\\([^)]*\\))|\n" . "\\s([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?<!\\\\)\\3|\n" . "\\A([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?<!\\\\)\\5|\n" . "\\s([^\\s\"']+)|\n" . "\\A([^\\s\"']+)\n" . "/xi"; $content = $this->_frame->get_style()->content; $quotes = $this->_parse_quotes(); if (!preg_match_all($re, $content, $matches, PREG_SET_ORDER)) { return; } $text = ""; foreach ($matches as $match) { if (isset($match[2]) && $match[2] !== "") { $match[1] = $match[2]; } if (isset($match[6]) && $match[6] !== "") { $match[4] = $match[6]; } if (isset($match[8]) && $match[8] !== "") { $match[7] = $match[8]; } if (isset($match[1]) && $match[1] !== "") { $match[1] = mb_strtolower(trim($match[1])); $i = mb_strpos($match[1], ")"); if ($i === false) { continue; } $args = explode(",", m_mb_substr($match[1], 8, $i - 8)); $counter_id = $args[0]; if ($match[1][7] === "(") { if (isset($args[1])) { $type = trim($args[1]); } else { $type = null; } $p = $this->_frame->lookup_counter_frame($counter_id); $text .= $p->counter_value($counter_id, $type); } else { if ($match[1][7] === "s") { if (isset($args[1])) { $string = $this->_parse_string(trim($args[1])); } else { $string = ""; } if (isset($args[2])) { $type = $args[2]; } else { $type = null; } $p = $this->_frame->lookup_counter_frame($counter_id); $tmp = ""; while ($p) { $tmp = $p->counter_value($counter_id, $type) . $string . $tmp; $p = $p->lookup_counter_frame($counter_id); } $text .= $tmp; } else { continue; } } } else { if (isset($match[4]) && $match[4] !== "") { $text .= $this->_parse_string($match[4]); } else { if (isset($match[7]) && $match[7] !== "") { if ($match[7] === "open-quote") { $text .= $quotes[0][0]; } else { if ($match[7] === "close-quote") { $text .= $quotes[0][1]; } else { if ($match[7] === "no-open-quote") { } else { if ($match[7] === "no-close-quote") { } else { if (mb_strpos($match[7], "attr(") === 0) { $i = mb_strpos($match[7], ")"); if ($i === false) { continue; } $attr = m_mb_substr($match[7], 5, $i - 5); if ($attr == "") { continue; } $text .= $this->_frame->get_parent()->get_node()->getAttribute($attr); } else { continue; } } } } } } } } } return $text; }
function set_list_style($val) { $important = isset($this->_important_props["list_style"]); $arr = explode(" ", str_replace(",", " ", $val)); static $types = array("disc", "circle", "square", "decimal-leading-zero", "decimal", "1", "lower-roman", "upper-roman", "a", "A", "lower-greek", "lower-latin", "upper-latin", "lower-alpha", "upper-alpha", "armenian", "georgian", "hebrew", "cjk-ideographic", "hiragana", "katakana", "hiragana-iroha", "katakana-iroha", "none"); static $positions = array("inside", "outside"); foreach ($arr as $value) { if ($value === "none") { $this->_set_style("list_style_type", $value, $important); $this->_set_style("list_style_image", $value, $important); continue; } if (m_mb_substr($value, 0, 3) === "url") { $this->_set_style("list_style_image", $this->_image($value), $important); continue; } if (in_array($value, $types)) { $this->_set_style("list_style_type", $value, $important); } else { if (in_array($value, $positions)) { $this->_set_style("list_style_position", $value, $important); } } } $this->_prop_cache["list_style"] = null; $this->_props["list_style"] = $val; }
private function _parse_sections($str) { $patterns = array("/[\\s\n]+/", "/\\s+([>.:+#])\\s+/"); $replacements = array(" ", "\\1"); $str = preg_replace($patterns, $replacements, $str); $sections = explode("}", $str); if (DEBUGCSS) { print '[_parse_sections'; } foreach ($sections as $sect) { $i = mb_strpos($sect, "{"); $selectors = explode(",", m_mb_substr($sect, 0, $i)); if (DEBUGCSS) { print '[section'; } $style = $this->_parse_properties(trim(m_mb_substr($sect, $i + 1))); foreach ($selectors as $selector) { $selector = trim($selector); if ($selector == "") { if (DEBUGCSS) { print '#empty#'; } continue; } if (DEBUGCSS) { print '#' . $selector . '#'; } $this->add_style($selector, $style); } if (DEBUGCSS) { print 'section]'; } } if (DEBUGCSS) { print '_parse_sections]'; } }
function __toString() { $str = "<b>" . $this->_node->nodeName . ":</b><br/>"; $str .= "Id: " . $this->get_id() . "<br/>"; $str .= "Class: " . get_class($this) . "<br/>"; if ($this->is_text_node()) { $tmp = htmlspecialchars($this->_node->nodeValue); $str .= "<pre>'" . m_mb_substr($tmp, 0, 70) . (mb_strlen($tmp) > 70 ? "..." : "") . "'</pre>"; } elseif ($css_class = $this->_node->getAttribute("class")) { $tmp = htmlspecialchars($css_class); $str .= "CSS class: '{$css_class}'<br/>"; } if ($this->_parent) { $str .= "\nParent:" . $this->_parent->_node->nodeName . " (" . spl_object_hash($this->_parent->_node) . ") " . "<br/>"; } if ($this->_prev_sibling) { $str .= "Prev: " . $this->_prev_sibling->_node->nodeName . " (" . spl_object_hash($this->_prev_sibling->_node) . ") " . "<br/>"; } if ($this->_next_sibling) { $str .= "Next: " . $this->_next_sibling->_node->nodeName . " (" . spl_object_hash($this->_next_sibling->_node) . ") " . "<br/>"; } $d = $this->get_decorator(); while ($d && $d != $d->get_decorator()) { $str .= "Decorator: " . get_class($d) . "<br/>"; $d = $d->get_decorator(); } $str .= "Position: " . pre_r($this->_position, true); $str .= "\nContaining block: " . pre_r($this->_containing_block, true); $str .= "\nMargin width: " . pre_r($this->get_margin_width(), true); $str .= "\nMargin height: " . pre_r($this->get_margin_height(), true); $str .= "\nStyle: <pre>" . $this->_style->__toString() . "</pre>"; if ($this->_decorator instanceof Block_Frame_Decorator) { $str .= "Lines:<pre>"; foreach ($this->_decorator->get_line_boxes() as $line) { foreach ($line->get_frames() as $frame) { if ($frame instanceof Text_Frame_Decorator) { $str .= "\ntext: "; $str .= "'" . htmlspecialchars($frame->get_text()) . "'"; } else { $str .= "\nBlock: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")"; } } $str .= "\ny => " . $line->y . "\n" . "w => " . $line->w . "\n" . "h => " . $line->h . "\n" . "left => " . $line->left . "\n" . "right => " . $line->right . "\n"; } $str .= "</pre>"; } $str .= "\n"; if (php_sapi_name() === "cli") { $str = strip_tags(str_replace(array("<br/>", "<b>", "</b>"), array("\n", "", ""), $str)); } return $str; }