Example #1
0
 function image($img, $x, $y, $w, $h, $resolution = "normal")
 {
     list($width, $height, $type) = dompdf_getimagesize($img, $this->_dompdf->get_http_context());
     $debug_png = $this->_dompdf->get_option("debug_png");
     if ($debug_png) {
         print "[image:{$img}|{$width}|{$height}|{$type}]";
     }
     switch ($type) {
         case IMAGETYPE_JPEG:
             if ($debug_png) {
                 print '!!!jpg!!!';
             }
             $this->_pdf->addJpegFromFile($img, $x, $this->y($y) - $h, $w, $h);
             break;
         case IMAGETYPE_GIF:
         case IMAGETYPE_BMP:
             if ($debug_png) {
                 print '!!!bmp or gif!!!';
             }
             // @todo use cache for BMP and GIF
             $img = $this->_convert_gif_bmp_to_png($img, $type);
         case IMAGETYPE_PNG:
             if ($debug_png) {
                 print '!!!png!!!';
             }
             $this->_pdf->addPngFromFile($img, $x, $this->y($y) - $h, $w, $h);
             break;
         default:
             if ($debug_png) {
                 print '!!!unknown!!!';
             }
     }
 }
Example #2
0
 /**
  * load and parse a CSS file
  *
  * @param string $file
  */
 function load_css_file($file)
 {
     global $_dompdf_warnings;
     // Prevent circular references
     if (isset($this->_loaded_files[$file])) {
         return;
     }
     $this->_loaded_files[$file] = true;
     $parsed_url = explode_url($file);
     list($this->_protocol, $this->_base_host, $this->_base_path, $filename) = $parsed_url;
     if (!DOMPDF_ENABLE_REMOTE && ($this->_protocol != "" && $this->_protocol !== "file://")) {
         record_warnings(E_USER_WARNING, "Remote CSS file '{$file}' requested, but DOMPDF_ENABLE_REMOTE is false.", __FILE__, __LINE__);
         return;
     }
     // Fix submitted by Nick Oostveen for aliased directory support:
     if ($this->_protocol == "") {
         $file = $this->_base_path . $filename;
     } else {
         $file = build_url($this->_protocol, $this->_base_host, $this->_base_path, $filename);
     }
     set_error_handler("record_warnings");
     $css = file_get_contents($file, null, $this->_dompdf->get_http_context());
     restore_error_handler();
     if ($css == "") {
         record_warnings(E_USER_WARNING, "Unable to load css file {$file}", __FILE__, __LINE__);
         return;
     }
     $this->_parse_css($css);
 }
Example #3
0
 /**
  * load and parse a CSS file
  *
  * @param string $file
  */
 function load_css_file($file, $origin = self::ORIG_AUTHOR)
 {
     global $_dompdf_warnings;
     if ($origin) {
         $this->_current_origin = $origin;
     }
     // Prevent circular references
     if (isset($this->_loaded_files[$file])) {
         return;
     }
     $this->_loaded_files[$file] = true;
     $parsed_url = explode_url($file);
     list($this->_protocol, $this->_base_host, $this->_base_path, $filename) = $parsed_url;
     // Fix submitted by Nick Oostveen for aliased directory support:
     if ($this->_protocol == "") {
         $file = $this->_base_path . $filename;
     } else {
         $file = build_url($this->_protocol, $this->_base_host, $this->_base_path, $filename);
     }
     set_error_handler("record_warnings");
     $css = file_get_contents($file, null, $this->_dompdf->get_http_context());
     restore_error_handler();
     if ($css == "") {
         record_warnings(E_USER_WARNING, "Unable to load css file {$file}", __FILE__, __LINE__);
         return;
     }
     $this->_parse_css($css);
 }
  /**
   * load and parse a CSS file
   *
   * @param string $file
   * @param int    $origin
   */
  function load_css_file($file, $origin = self::ORIG_AUTHOR) {
    if ( $origin ) {
      $this->_current_origin = $origin;
    }

    // Prevent circular references
    if ( isset($this->_loaded_files[$file]) ) {
      return;
    }

    $this->_loaded_files[$file] = true;

    if ( strpos($file, "data:") === 0) {
      $parsed = parse_data_uri($file);
      $css = $parsed["data"];
    }
    else {
      $parsed_url = explode_url($file);

      list($this->_protocol, $this->_base_host, $this->_base_path, $filename) = $parsed_url;

      // Fix submitted by Nick Oostveen for aliased directory support:
      if ( $this->_protocol == "" ) {
        $file = $this->_base_path . $filename;
      }
      else {
        $file = build_url($this->_protocol, $this->_base_host, $this->_base_path, $filename);
      }

      set_error_handler("record_warnings");
      $css = file_get_contents($file, null, $this->_dompdf->get_http_context());
      restore_error_handler();

      $good_mime_type = true;

      // See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
      if ( isset($http_response_header) && !$this->_dompdf->get_quirksmode() ) {
        foreach($http_response_header as $_header) {
          if ( preg_match("@Content-Type:\s*([\w/]+)@i", $_header, $matches) &&
              ($matches[1] !== "text/css") ) {
            $good_mime_type = false;
          }
        }
      }

      if ( !$good_mime_type || $css == "" ) {
        record_warnings(E_USER_WARNING, "Unable to load css file $file", __FILE__, __LINE__);
        return;
      }
    }

    $this->_parse_css($css);
  }
 function image($img_url, $x, $y, $w, $h, $resolution = "normal")
 {
     $w = (int) $w;
     $h = (int) $h;
     $img_type = Image_Cache::detect_type($img_url, $this->_dompdf->get_http_context());
     $img_ext = Image_Cache::type_to_ext($img_type);
     if (!isset($this->_imgs[$img_url])) {
         $this->_imgs[$img_url] = $this->_pdf->load_image($img_ext, $img_url, "");
     }
     $img = $this->_imgs[$img_url];
     $y = $this->y($y) - $h;
     $this->_pdf->fit_image($img, $x, $y, 'boxsize={' . "{$w} {$h}" . '} fitmethod=entire');
 }
Example #6
0
 /**
  * parse @font-face{} sections
  * http://www.w3.org/TR/css3-fonts/#the-font-face-rule
  * 
  * @param string $str CSS @font-face rules
  * @return Style
  */
 private function _parse_font_face($str)
 {
     $descriptors = $this->_parse_properties($str);
     preg_match_all("/(url|local)\\s*\\([\"\\']?([^\"\\'\\)]+)[\"\\']?\\)\\s*(format\\s*\\([\"\\']?([^\"\\'\\)]+)[\"\\']?\\))?/i", $descriptors->src, $src);
     $sources = array();
     $valid_sources = array();
     foreach ($src[0] as $i => $value) {
         $source = array("local" => strtolower($src[1][$i]) === "local", "uri" => $src[2][$i], "format" => $src[4][$i], "path" => build_url($this->_protocol, $this->_base_host, $this->_base_path, $src[2][$i]));
         if (!$source["local"] && in_array($source["format"], array("", "truetype"))) {
             $valid_sources[] = $source;
         }
         $sources[] = $source;
     }
     // No valid sources
     if (empty($valid_sources)) {
         return;
     }
     $style = array("family" => $descriptors->get_font_family_raw(), "weight" => $descriptors->font_weight, "style" => $descriptors->font_style);
     Font_Metrics::register_font($style, $valid_sources[0]["path"], $this->_dompdf->get_http_context());
 }
Example #7
0
 /**
  * Add an image to the pdf.
  * The image is placed at the specified x and y coordinates with the
  * given width and height.
  *
  * @param string $img_url the path to the image
  * @param float  $x       x position
  * @param float  $y       y position
  * @param int    $w       width (in pixels)
  * @param int    $h       height (in pixels)
  * @param string $resolution
  *
  * @return void
  * @internal param string $img_type the type (e.g. extension) of the image
  */
 function image($img_url, $x, $y, $w, $h, $resolution = "normal")
 {
     $img_type = Image_Cache::detect_type($img_url, $this->_dompdf->get_http_context());
     $img_ext = Image_Cache::type_to_ext($img_type);
     if (!$img_ext) {
         return;
     }
     $func = "imagecreatefrom{$img_ext}";
     $src = @$func($img_url);
     if (!$src) {
         return;
         // Probably should add to $_dompdf_errors or whatever here
     }
     // Scale by the AA factor
     $x *= $this->_aa_factor;
     $y *= $this->_aa_factor;
     $w *= $this->_aa_factor;
     $h *= $this->_aa_factor;
     $img_w = imagesx($src);
     $img_h = imagesy($src);
     imagecopyresampled($this->_img, $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h);
 }
 /**
  * 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, $this->_dompdf->get_http_context());
     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();
 }
Example #9
0
 /**
  * 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)
 {
     $protocol = mb_strtolower($protocol);
     $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");
         } else {
             if ($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, null, $dompdf->get_http_context());
                         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, $dompdf->get_http_context());
             // 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 = "Image not found or type unknown";
         $_dompdf_warnings[] = $e->getMessage() . " :: {$url}";
     }
     return array($resolved_url, $type, $message);
 }