function render(Frame $frame) { if (!$this->_dompdf->get_option("enable_javascript")) { return; } $this->insert($frame->get_node()->nodeValue); }
function get_font_height($font, $size) { $fh = $this->_load_font($font); $this->_pdf->setfont($fh, $size); $asc = $this->_pdf->get_value("ascender", $fh); $desc = $this->_pdf->get_value("descender", $fh); // $desc is usually < 0, $ratio = $this->_dompdf->get_option("font_height_ratio"); return $size * ($asc - $desc) * $ratio; }
/** * parse @import{} sections * * @param string $url the url of the imported CSS file */ private function _parse_import($url) { $arr = preg_split("/[\s\n,]/", $url,-1, PREG_SPLIT_NO_EMPTY); $url = array_shift($arr); $accept = false; if ( count($arr) > 0 ) { $acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES; $acceptedmedia[] = $this->_dompdf->get_option("default_media_type"); // @import url media_type [media_type...] foreach ( $arr as $type ) { if ( in_array(mb_strtolower(trim($type)), $acceptedmedia) ) { $accept = true; break; } } } else { // unconditional import $accept = true; } if ( $accept ) { // Store our current base url properties in case the new url is elsewhere $protocol = $this->_protocol; $host = $this->_base_host; $path = $this->_base_path; // $url = str_replace(array('"',"url", "(", ")"), "", $url); // If the protocol is php, assume that we will import using file:// // $url = build_url($protocol == "php://" ? "file://" : $protocol, $host, $path, $url); // Above does not work for subfolders and absolute urls. // Todo: As above, do we need to replace php or file to an empty protocol for local files? $url = $this->_image($url); $this->load_css_file($url); // Restore the current base url $this->_protocol = $protocol; $this->_base_host = $host; $this->_base_path = $path; } }
function get_font_baseline($font, $size) { $ratio = $this->_dompdf->get_option("font_height_ratio"); return $this->get_font_height($font, $size) / $ratio; }
/** * Render a background image over a rectangular area * * @param string $url The background image to load * @param float $x The left edge of the rectangular area * @param float $y The top edge of the rectangular area * @param float $width The width of the rectangular area * @param float $height The height of the rectangular area * @param Style $style The associated Style object * * @throws Exception */ protected function _background_image($url, $x, $y, $width, $height, $style) { if (!function_exists("imagecreatetruecolor")) { throw new Exception("The PHP GD extension is required, but is not installed."); } $sheet = $style->get_stylesheet(); // Skip degenerate cases if ($width == 0 || $height == 0) { return; } $box_width = $width; $box_height = $height; //debugpng if (DEBUGPNG) { print '[_background_image ' . $url . ']'; } list($img, $type, ) = Image_Cache::resolve_url($url, $sheet->get_protocol(), $sheet->get_host(), $sheet->get_base_path(), $this->_dompdf); // Bail if the image is no good if (Image_Cache::is_broken($img)) { return; } //Try to optimize away reading and composing of same background multiple times //Postponing read with imagecreatefrom ...() //final composition parameters and name not known yet //Therefore read dimension directly from file, instead of creating gd object first. //$img_w = imagesx($src); $img_h = imagesy($src); list($img_w, $img_h) = dompdf_getimagesize($img); if (!isset($img_w) || $img_w == 0 || !isset($img_h) || $img_h == 0) { return; } $repeat = $style->background_repeat; $dpi = $this->_dompdf->get_option("dpi"); //Increase background resolution and dependent box size according to image resolution to be placed in //Then image can be copied in without resize $bg_width = round((double) ($width * $dpi) / 72); $bg_height = round((double) ($height * $dpi) / 72); //Need %bg_x, $bg_y as background pos, where img starts, converted to pixel list($bg_x, $bg_y) = $style->background_position; if (is_percent($bg_x)) { // The point $bg_x % from the left edge of the image is placed // $bg_x % from the left edge of the background rectangle $p = (double) $bg_x / 100.0; $x1 = $p * $img_w; $x2 = $p * $bg_width; $bg_x = $x2 - $x1; } else { $bg_x = (double) ($style->length_in_pt($bg_x) * $dpi) / 72; } $bg_x = round($bg_x + $style->length_in_pt($style->border_left_width) * $dpi / 72); if (is_percent($bg_y)) { // The point $bg_y % from the left edge of the image is placed // $bg_y % from the left edge of the background rectangle $p = (double) $bg_y / 100.0; $y1 = $p * $img_h; $y2 = $p * $bg_height; $bg_y = $y2 - $y1; } else { $bg_y = (double) ($style->length_in_pt($bg_y) * $dpi) / 72; } $bg_y = round($bg_y + $style->length_in_pt($style->border_top_width) * $dpi / 72); //clip background to the image area on partial repeat. Nothing to do if img off area //On repeat, normalize start position to the tile at immediate left/top or 0/0 of area //On no repeat with positive offset: move size/start to have offset==0 //Handle x/y Dimensions separately if ($repeat !== "repeat" && $repeat !== "repeat-x") { //No repeat x if ($bg_x < 0) { $bg_width = $img_w + $bg_x; } else { $x += $bg_x * 72 / $dpi; $bg_width = $bg_width - $bg_x; if ($bg_width > $img_w) { $bg_width = $img_w; } $bg_x = 0; } if ($bg_width <= 0) { return; } $width = (double) ($bg_width * 72) / $dpi; } else { //repeat x if ($bg_x < 0) { $bg_x = -(-$bg_x % $img_w); } else { $bg_x = $bg_x % $img_w; if ($bg_x > 0) { $bg_x -= $img_w; } } } if ($repeat !== "repeat" && $repeat !== "repeat-y") { //no repeat y if ($bg_y < 0) { $bg_height = $img_h + $bg_y; } else { $y += $bg_y * 72 / $dpi; $bg_height = $bg_height - $bg_y; if ($bg_height > $img_h) { $bg_height = $img_h; } $bg_y = 0; } if ($bg_height <= 0) { return; } $height = (double) ($bg_height * 72) / $dpi; } else { //repeat y if ($bg_y < 0) { $bg_y = -(-$bg_y % $img_h); } else { $bg_y = $bg_y % $img_h; if ($bg_y > 0) { $bg_y -= $img_h; } } } //Optimization, if repeat has no effect if ($repeat === "repeat" && $bg_y <= 0 && $img_h + $bg_y >= $bg_height) { $repeat = "repeat-x"; } if ($repeat === "repeat" && $bg_x <= 0 && $img_w + $bg_x >= $bg_width) { $repeat = "repeat-y"; } if ($repeat === "repeat-x" && $bg_x <= 0 && $img_w + $bg_x >= $bg_width || $repeat === "repeat-y" && $bg_y <= 0 && $img_h + $bg_y >= $bg_height) { $repeat = "no-repeat"; } //Use filename as indicator only //different names for different variants to have different copies in the pdf //This is not dependent of background color of box! .'_'.(is_array($bg_color) ? $bg_color["hex"] : $bg_color) //Note: Here, bg_* are the start values, not end values after going through the tile loops! $filedummy = $img; $is_png = false; $filedummy .= '_' . $bg_width . '_' . $bg_height . '_' . $bg_x . '_' . $bg_y . '_' . $repeat; //Optimization to avoid multiple times rendering the same image. //If check functions are existing and identical image already cached, //then skip creation of duplicate, because it is not needed by addImagePng if ($this->_canvas instanceof CPDF_Adapter && $this->_canvas->get_cpdf()->image_iscached($filedummy)) { $bg = null; } else { // Create a new image to fit over the background rectangle $bg = imagecreatetruecolor($bg_width, $bg_height); switch (strtolower($type)) { case IMAGETYPE_PNG: $is_png = true; imagesavealpha($bg, true); imagealphablending($bg, false); $src = imagecreatefrompng($img); break; case IMAGETYPE_JPEG: $src = imagecreatefromjpeg($img); break; case IMAGETYPE_GIF: $src = imagecreatefromgif($img); break; case IMAGETYPE_BMP: $src = imagecreatefrombmp($img); break; default: return; // Unsupported image type } if ($src == null) { return; } //Background color if box is not relevant here //Non transparent image: box clipped to real size. Background non relevant. //Transparent image: The image controls the transparency and lets shine through whatever background. //However on transparent image preset the composed image with the transparency color, //to keep the transparency when copying over the non transparent parts of the tiles. $ti = imagecolortransparent($src); if ($ti >= 0) { $tc = imagecolorsforindex($src, $ti); $ti = imagecolorallocate($bg, $tc['red'], $tc['green'], $tc['blue']); imagefill($bg, 0, 0, $ti); imagecolortransparent($bg, $ti); } //This has only an effect for the non repeatable dimension. //compute start of src and dest coordinates of the single copy if ($bg_x < 0) { $dst_x = 0; $src_x = -$bg_x; } else { $src_x = 0; $dst_x = $bg_x; } if ($bg_y < 0) { $dst_y = 0; $src_y = -$bg_y; } else { $src_y = 0; $dst_y = $bg_y; } //For historical reasons exchange meanings of variables: //start_* will be the start values, while bg_* will be the temporary start values in the loops $start_x = $bg_x; $start_y = $bg_y; // Copy regions from the source image to the background if ($repeat === "no-repeat") { // Simply place the image on the background imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h); } else { if ($repeat === "repeat-x") { for ($bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w) { if ($bg_x < 0) { $dst_x = 0; $src_x = -$bg_x; $w = $img_w + $bg_x; } else { $dst_x = $bg_x; $src_x = 0; $w = $img_w; } imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h); } } else { if ($repeat === "repeat-y") { for ($bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h) { if ($bg_y < 0) { $dst_y = 0; $src_y = -$bg_y; $h = $img_h + $bg_y; } else { $dst_y = $bg_y; $src_y = 0; $h = $img_h; } imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h); } } else { if ($repeat === "repeat") { for ($bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h) { for ($bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w) { if ($bg_x < 0) { $dst_x = 0; $src_x = -$bg_x; $w = $img_w + $bg_x; } else { $dst_x = $bg_x; $src_x = 0; $w = $img_w; } if ($bg_y < 0) { $dst_y = 0; $src_y = -$bg_y; $h = $img_h + $bg_y; } else { $dst_y = $bg_y; $src_y = 0; $h = $img_h; } imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $h); } } } else { print 'Unknown repeat!'; } } } } imagedestroy($src); } /* End optimize away creation of duplicates */ $this->_canvas->clipping_rectangle($x, $y, $box_width, $box_height); //img: image url string //img_w, img_h: original image size in px //width, height: box size in pt //bg_width, bg_height: box size in px //x, y: left/top edge of box on page in pt //start_x, start_y: placement of image relative to pattern //$repeat: repeat mode //$bg: GD object of result image //$src: GD object of original image //When using cpdf and optimization to direct png creation from gd object is available, //don't create temp file, but place gd object directly into the pdf if (!$is_png && $this->_canvas instanceof CPDF_Adapter) { // Note: CPDF_Adapter image converts y position $this->_canvas->get_cpdf()->addImagePng($filedummy, $x, $this->_canvas->get_height() - $y - $height, $width, $height, $bg); } else { $tmp_dir = $this->_dompdf->get_option("temp_dir"); $tmp_name = tempnam($tmp_dir, "bg_dompdf_img_"); @unlink($tmp_name); $tmp_file = "{$tmp_name}.png"; //debugpng if (DEBUGPNG) { print '[_background_image ' . $tmp_file . ']'; } imagepng($bg, $tmp_file); $this->_canvas->image($tmp_file, $x, $y, $width, $height); imagedestroy($bg); //debugpng if (DEBUGPNG) { print '[_background_image unlink ' . $tmp_file . ']'; } if (!DEBUGKEEPTEMP) { unlink($tmp_file); } } $this->_canvas->clipping_end(); }
function get_font_height($font, $size) { $this->_pdf->selectFont($font); $ratio = $this->_dompdf->get_option("font_height_ratio"); return $this->_pdf->getFontHeight($size) * $ratio; }
/** * Resolve and fetch an image for use. * * @param string $url The url of the image * @param string $protocol Default protocol if none specified in $url * @param string $host Default host if none specified in $url * @param string $base_path Default path if none specified in $url * @param DOMPDF $dompdf The DOMPDF instance * * @throws DOMPDF_Image_Exception * @return array An array with two elements: The local path to the image and the image extension */ static function resolve_url($url, $protocol, $host, $base_path, DOMPDF $dompdf) { $parsed_url = explode_url($url); $message = null; $remote = $protocol && $protocol !== "file://" || $parsed_url['protocol'] != ""; $data_uri = strpos($parsed_url['protocol'], "data:") === 0; $full_url = null; $enable_remote = $dompdf->get_option("enable_remote"); try { // Remote not allowed and is not DataURI if (!$enable_remote && $remote && !$data_uri) { throw new DOMPDF_Image_Exception("DOMPDF_ENABLE_REMOTE is set to FALSE"); } elseif ($enable_remote && $remote || $data_uri) { // Download remote files to a temporary directory $full_url = build_url($protocol, $host, $base_path, $url); // From cache if (isset(self::$_cache[$full_url])) { $resolved_url = self::$_cache[$full_url]; } else { $tmp_dir = $dompdf->get_option("temp_dir"); $resolved_url = tempnam($tmp_dir, "ca_dompdf_img_"); $image = ""; if ($data_uri) { if ($parsed_data_uri = parse_data_uri($url)) { $image = $parsed_data_uri['data']; } } else { set_error_handler("record_warnings"); $image = file_get_contents($full_url); restore_error_handler(); } // Image not found or invalid if (strlen($image) == 0) { $msg = $data_uri ? "Data-URI could not be parsed" : "Image not found"; throw new DOMPDF_Image_Exception($msg); } else { //e.g. fetch.php?media=url.jpg&cache=1 //- Image file name might be one of the dynamic parts of the url, don't strip off! //- a remote url does not need to have a file extension at all //- local cached file does not have a matching file extension //Therefore get image type from the content file_put_contents($resolved_url, $image); } } } else { $resolved_url = build_url($protocol, $host, $base_path, $url); } // Check if the local file is readable if (!is_readable($resolved_url) || !filesize($resolved_url)) { throw new DOMPDF_Image_Exception("Image not readable or empty"); } else { list($width, $height, $type) = dompdf_getimagesize($resolved_url); // Known image type if ($width && $height && in_array($type, array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP))) { //Don't put replacement image into cache - otherwise it will be deleted on cache cleanup. //Only execute on successful caching of remote image. if ($enable_remote && $remote || $data_uri) { self::$_cache[$full_url] = $resolved_url; } } else { throw new DOMPDF_Image_Exception("Image type unknown"); } } } catch (DOMPDF_Image_Exception $e) { $resolved_url = self::$broken_image; $type = IMAGETYPE_PNG; $message = $e->getMessage() . " \n {$url}"; } return array($resolved_url, $type, $message); }