diff --git a/libraries/fpdf/fpdf.php b/libraries/fpdf/fpdf.php index 1e49e856f..f5b967c18 100644 --- a/libraries/fpdf/fpdf.php +++ b/libraries/fpdf/fpdf.php @@ -1,1887 +1,1629 @@ _dochecks(); - // Initialization of properties - $this->page = 0; - $this->n = 2; - $this->buffer = ''; - $this->pages = array(); - $this->OrientationChanges = array(); - $this->state = 0; - $this->fonts = array(); - $this->FontFiles = array(); - $this->diffs = array(); - $this->images = array(); - $this->links = array(); - $this->InFooter = false; - $this->lasth = 0; - $this->FontFamily = ''; - $this->FontStyle = ''; - $this->FontSizePt = 12; - $this->underline = false; - $this->DrawColor = '0 G'; - $this->FillColor = '0 g'; - $this->TextColor = '0 g'; - $this->ColorFlag = false; - $this->ws = 0; - // Standard fonts - $this->CoreFonts = array('courier' => 'Courier', 'courierB' => 'Courier-Bold', 'courierI' => 'Courier-Oblique', 'courierBI' => 'Courier-BoldOblique', - 'helvetica' => 'Helvetica', 'helveticaB' => 'Helvetica-Bold', 'helveticaI' => 'Helvetica-Oblique', 'helveticaBI' => 'Helvetica-BoldOblique', - 'times' => 'Times-Roman', 'timesB' => 'Times-Bold', 'timesI' => 'Times-Italic', 'timesBI' => 'Times-BoldItalic', - 'symbol' => 'Symbol', 'zapfdingbats' => 'ZapfDingbats'); - // Scale factor - if ($unit == 'pt') { - $this->k = 1; - } elseif ($unit == 'mm') { - $this->k = 72 / 25.4; - } elseif ($unit == 'cm') { - $this->k = 72 / 2.54; - } elseif ($unit == 'in') { - $this->k = 72; - } else { - $this->Error('Incorrect unit: ' . $unit); - } - // Page format - if (is_string($format)) { - $format = strtolower($format); - - if ($format == 'a3') { - $format = array(841.89, 1190.55); - } elseif ($format == 'a4') { - $format = array(595.28, 841.89); - } elseif ($format == 'a5') { - $format = array(420.94, 595.28); - } elseif ($format == 'letter') { - $format = array(612, 792); - } elseif ($format == 'legal') { - $format = array(612, 1008); - } else { - $this->Error('Unknown page format: ' . $format); - } - - $this->fwPt = $format[0]; - $this->fhPt = $format[1]; - } else { - $this->fwPt = $format[0] * $this->k; - $this->fhPt = $format[1] * $this->k; - } - - $this->fw = $this->fwPt / $this->k; - $this->fh = $this->fhPt / $this->k; - // Page orientation - $orientation = strtolower($orientation); - - if ($orientation == 'p' or $orientation == 'portrait') { - $this->DefOrientation = 'P'; - $this->wPt = $this->fwPt; - $this->hPt = $this->fhPt; - } elseif ($orientation == 'l' or $orientation == 'landscape') { - $this->DefOrientation = 'L'; - $this->wPt = $this->fhPt; - $this->hPt = $this->fwPt; - } else { - $this->Error('Incorrect orientation: ' . $orientation); - } - $this->CurOrientation = $this->DefOrientation; - $this->w = $this->wPt / $this->k; - $this->h = $this->hPt / $this->k; - // Page margins (1 cm) - $margin = 28.35 / $this->k; - - $this->SetMargins($margin, $margin); - // Interior cell margin (1 mm) - $this->cMargin = $margin / 10; - // Line width (0.2 mm) - $this->LineWidth = .567 / $this->k; - // Automatic page break - $this->SetAutoPageBreak(true, 2 * $margin); - // Full width display mode - $this->SetDisplayMode('fullwidth'); - // Compression - $this->SetCompression(true); - } - - function SetMargins($left, $top, $right = -1) - { - // Set left, top and right margins - $this->lMargin = $left; - - $this->tMargin = $top; - - if ($right == -1) { - $right = $left; - } - - $this->rMargin = $right; - } - - function SetLeftMargin($margin) - { - // Set left margin - $this->lMargin = $margin; - - if ($this->page > 0 and $this->x < $margin) { - $this->x = $margin; - } - } - - function SetTopMargin($margin) - { - // Set top margin - $this->tMargin = $margin; - } - - function SetRightMargin($margin) - { - // Set right margin - $this->rMargin = $margin; - } - - function SetAutoPageBreak($auto, $margin = 0) - { - // Set auto page break mode and triggering margin - $this->AutoPageBreak = $auto; - $this->bMargin = $margin; - $this->PageBreakTrigger = $this->h - $margin; - } - - function SetDisplayMode($zoom, $layout = 'continuous') - { - // Set display mode in viewer - if ($zoom == 'fullpage' or $zoom == 'fullwidth' or $zoom == 'real' or $zoom == 'default' or !is_string($zoom)) { - $this->ZoomMode = $zoom; - } else { - $this->Error('Incorrect zoom display mode: ' . $zoom); - } - - if ($layout == 'single' or $layout == 'continuous' or $layout == 'two' or $layout == 'default') { - $this->LayoutMode = $layout; - } else { - $this->Error('Incorrect layout display mode: ' . $layout); - } - } - - function SetCompression($compress) - { - // Set page compression - if (function_exists('gzcompress')) { - $this->compress = $compress; - } else { - $this->compress = false; - } - } - - function SetTitle($title) - { - // Title of document - $this->title = $title; - } - - function SetSubject($subject) - { - // Subject of document - $this->subject = $subject; - } - - function SetAuthor($author) - { - // Author of document - $this->author = $author; - } - - function SetKeywords($keywords) - { - // Keywords of document - $this->keywords = $keywords; - } - - function SetCreator($creator) - { - // Creator of document - $this->creator = $creator; - } - - function AliasNbPages($alias = '{nb}') - { - // Define an alias for total number of pages - $this->AliasNbPages = $alias; - } - - function Error($msg) - { - // Fatal error - die('FPDF error: ' . $msg); - } - - function Open() - { - // Begin document - if ($this->state == 0) { - $this->_begindoc(); - } - } - - function Close() - { - // Terminate document - if ($this->state == 3) { - return; - } - - if ($this->page == 0) { - $this->AddPage(); - } - // Page footer - $this->InFooter = true; - $this->Footer(); - $this->InFooter = false; - // Close page - $this->_endpage(); - // Close document - $this->_enddoc(); - } - - function AddPage($orientation = '') - { - // Start a new page - if ($this->state == 0) { - $this->Open(); - } - - $family = $this->FontFamily; - $style = $this->FontStyle . ($this->underline ? 'U' : ''); - $size = $this->FontSizePt; - $lw = $this->LineWidth; - $dc = $this->DrawColor; - $fc = $this->FillColor; - $tc = $this->TextColor; - $cf = $this->ColorFlag; - - if ($this->page > 0) { - // Page footer - $this->InFooter = true; - $this->Footer(); - $this->InFooter = false; - // Close page - $this->_endpage(); - } - // Start new page - $this->_beginpage($orientation); - // Set line cap style to square - $this->_out('2 J'); - // Set line width - $this->LineWidth = $lw; - - $this->_out(sprintf('%.2f w', $lw * $this->k)); - // Set font - if ($family) { - $this->SetFont($family, $style, $size); - } - // Set colors - $this->DrawColor = $dc; - - if ($dc != '0 G') { - $this->_out($dc); - } - - $this->FillColor = $fc; - - if ($fc != '0 g') { - $this->_out($fc); - } - - $this->TextColor = $tc; - $this->ColorFlag = $cf; - // Page header - $this->Header(); - // Restore line width - if ($this->LineWidth != $lw) { - $this->LineWidth = $lw; - $this->_out(sprintf('%.2f w', $lw * $this->k)); - } - // Restore font - if ($family) { - $this->SetFont($family, $style, $size); - } - // Restore colors - if ($this->DrawColor != $dc) { - $this->DrawColor = $dc; - $this->_out($dc); - } - - if ($this->FillColor != $fc) { - $this->FillColor = $fc; - $this->_out($fc); - } - - $this->TextColor = $tc; - $this->ColorFlag = $cf; - } - - function Header() - { - // To be implemented in your own inherited class - } - - function Footer() - { - // To be implemented in your own inherited class - } - - function PageNo() - { - // Get current page number - return $this->page; - } - - function SetDrawColor($r, $g = -1, $b = -1) - { - // Set color for all stroking operations - if (($r == 0 and $g == 0 and $b == 0) or $g == -1) { - $this->DrawColor = sprintf('%.3f G', $r / 255); - } else { - $this->DrawColor = sprintf('%.3f %.3f %.3f RG', $r / 255, $g / 255, $b / 255); - } - - if ($this->page > 0) { - $this->_out($this->DrawColor); - } - } - - function SetFillColor($r, $g = -1, $b = -1) - { - // Set color for all filling operations - if (($r == 0 and $g == 0 and $b == 0) or $g == -1) { - $this->FillColor = sprintf('%.3f g', $r / 255); - } else { - $this->FillColor = sprintf('%.3f %.3f %.3f rg', $r / 255, $g / 255, $b / 255); - } - - $this->ColorFlag = ($this->FillColor != $this->TextColor); - - if ($this->page > 0) { - $this->_out($this->FillColor); - } - } - - function SetTextColor($r, $g = -1, $b = -1) - { - // Set color for text - if (($r == 0 and $g == 0 and $b == 0) or $g == -1) { - $this->TextColor = sprintf('%.3f g', $r / 255); - } else { - $this->TextColor = sprintf('%.3f %.3f %.3f rg', $r / 255, $g / 255, $b / 255); - } - - $this->ColorFlag = ($this->FillColor != $this->TextColor); - } - - function GetStringWidth($s) - { - // Get width of a string in the current font - $s = (string)$s; - $cw = &$this->CurrentFont['cw']; - $w = 0; - $l = strlen($s); - - for ($i = 0;$i < $l;$i++) { - $w += $cw[$s{$i}]; - } - - return $w * $this->FontSize / 1000; - } - - function SetLineWidth($width) - { - // Set line width - $this->LineWidth = $width; - - if ($this->page > 0) { - $this->_out(sprintf('%.2f w', $width * $this->k)); - } - } - - function Line($x1, $y1, $x2, $y2) - { - // Draw a line - $this->_out(sprintf('%.2f %.2f m %.2f %.2f l S', $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k)); - } - - function Rect($x, $y, $w, $h, $style = '') - { - // Draw a rectangle - if ($style == 'F') { - $op = 'f'; - } elseif ($style == 'FD' or $style == 'DF') { - $op = 'B'; - } else { - $op = 'S'; - } - - $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s', $x * $this->k, ($this->h - $y) * $this->k, $w * $this->k, - $h * $this->k, $op)); - } - - function AddFont($family, $style = '', $file = '') - { - // Add a TrueType or Type1 font - $family = strtolower($family); - - if ($family == 'arial') { - $family = 'helvetica'; - } - - $style = strtoupper($style); - - if ($style == 'IB') { - $style = 'BI'; - } - - if (isset($this->fonts[$family . $style])) { - $this->Error('Font already added: ' . $family . ' ' . $style); - } - - if ($file == '') { - $file = str_replace(' ', '', $family) . strtolower($style) . '.php'; - } - - if (defined('FPDF_FONTPATH')) { - $file = FPDF_FONTPATH . $file; - } - - include($file); - - if (!isset($name)) { - $this->Error('Could not include font definition file'); - } - - $i = count($this->fonts) + 1; - $this->fonts[$family . $style] = array('i' => $i, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'enc' => $enc, 'file' => $file); - - if ($diff) { - // Search existing encodings - $d = 0; - $nb = count($this->diffs); - - for ($i = 1;$i <= $nb;$i++) { - if ($this->diffs[$i] == $diff) { - $d = $i; - break; - } - } - - if ($d == 0) { - $d = $nb + 1; - $this->diffs[$d] = $diff; - } - - $this->fonts[$family . $style]['diff'] = $d; - } - - if ($file) { - if ($type == 'TrueType') { - $this->FontFiles[$file] = array('length1' => $originalsize); - } else { - $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2); - } - } - } - - function SetFont($family, $style = '', $size = 0) - { - // Select a font; size given in points - global $fpdf_charwidths; - - $family = strtolower($family); - - if ($family == '') { - $family = $this->FontFamily; - } - - if ($family == 'arial') { - $family = 'helvetica'; - } elseif ($family == 'symbol' or $family == 'zapfdingbats') { - $style = ''; - } - - $style = strtoupper($style); - - if (is_int(strpos($style, 'U'))) { - $this->underline = true; - $style = str_replace('U', '', $style); - } else { - $this->underline = false; - } - - if ($style == 'IB') { - $style = 'BI'; - } - - if ($size == 0) { - $size = $this->FontSizePt; - } - // Test if font is already selected - if ($this->FontFamily == $family and $this->FontStyle == $style and $this->FontSizePt == $size) { - return; - } - // Test if used for the first time - $fontkey = $family . $style; - - if (!isset($this->fonts[$fontkey])) { - // Check if one of the standard fonts - if (isset($this->CoreFonts[$fontkey])) { - if (!isset($fpdf_charwidths[$fontkey])) { - // Load metric file - $file = $family; - - if ($family == 'times' or $family == 'helvetica') { - $file .= strtolower($style); - } - - $file .= '.php'; - - if (defined('FPDF_FONTPATH')) { - $file = FPDF_FONTPATH . $file; - } - - include($file); - - if (!isset($fpdf_charwidths[$fontkey])) { - $this->Error('Could not include font metric file'); - } - } - - $i = count($this->fonts) + 1; - $this->fonts[$fontkey] = array('i' => $i, 'type' => 'core', 'name' => $this->CoreFonts[$fontkey], 'up' => -100, 'ut' => 50, 'cw' => $fpdf_charwidths[$fontkey]); - } else { - $this->Error('Undefined font: ' . $family . ' ' . $style); - } - } - // Select it - $this->FontFamily = $family; - $this->FontStyle = $style; - $this->FontSizePt = $size; - $this->FontSize = $size / $this->k; - $this->CurrentFont = &$this->fonts[$fontkey]; - - if ($this->page > 0) { - $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); - } - } - - function SetFontSize($size) - { - // Set font size in points - if ($this->FontSizePt == $size) { - return; - } - - $this->FontSizePt = $size; - $this->FontSize = $size / $this->k; - - if ($this->page > 0) { - $this->_out(sprintf('BT /F%d %.2f Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); - } - } - - function AddLink() - { - // Create a new internal link - $n = count($this->links) + 1; - $this->links[$n] = array(0, 0); - return $n; - } - - function SetLink($link, $y = 0, $page = -1) - { - // Set destination of internal link - if ($y == -1) { - $y = $this->y; - } - - if ($page == -1) { - $page = $this->page; - } - - $this->links[$link] = array($page, $y); - } - - function Link($x, $y, $w, $h, $link) - { - // Put a link on the page - $this->PageLinks[$this->page][] = array($x * $this->k, $this->hPt - $y * $this->k, $w * $this->k, $h * $this->k, $link); - } - - function Text($x, $y, $txt) - { - // Output a string - $s = sprintf('BT %.2f %.2f Td (%s) Tj ET', $x * $this->k, ($this->h - $y) * $this->k, $this->_escape($txt)); - - if ($this->underline and $txt != '') { - $s .= ' ' . $this->_dounderline($x, $y, $txt); - } - - if ($this->ColorFlag) { - $s = 'q ' . $this->TextColor . ' ' . $s . ' Q'; - } - - $this->_out($s); - } - - function AcceptPageBreak() - { - // Accept automatic page break or not - return $this->AutoPageBreak; - } - - function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '') - { - // Output a cell - $k = $this->k; - - if ($this->y + $h > $this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) { - // Automatic page break - $x = $this->x; - $ws = $this->ws; - - if ($ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - - $this->AddPage($this->CurOrientation); - $this->x = $x; - - if ($ws > 0) { - $this->ws = $ws; - $this->_out(sprintf('%.3f Tw', $ws * $k)); - } - } - - if ($w == 0) { - $w = $this->w - $this->rMargin - $this->x; - } - - $s = ''; - - if ($fill == 1 or $border == 1) { - if ($fill == 1) { - $op = ($border == 1) ? 'B' : 'f'; - } else { - $op = 'S'; - } - - $s = sprintf('%.2f %.2f %.2f %.2f re %s ', $this->x * $k, ($this->h - $this->y) * $k, $w * $k, - $h * $k, $op); - } - - if (is_string($border)) { - $x = $this->x; - $y = $this->y; - - if (is_int(strpos($border, 'L'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - $y) * $k, $x * $k, ($this->h - ($y + $h)) * $k); - } - - if (is_int(strpos($border, 'T'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - $y) * $k); - } - - if (is_int(strpos($border, 'R'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', ($x + $w) * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); - } - - if (is_int(strpos($border, 'B'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - ($y + $h)) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); - } - } - - if ($txt != '') { - if ($align == 'R') { - $dx = $w - $this->cMargin - $this->GetStringWidth($txt); - } elseif ($align == 'C') { - $dx = ($w - $this->GetStringWidth($txt)) / 2; - } else { - $dx = $this->cMargin; - } - - if ($this->ColorFlag) { - $s .= 'q ' . $this->TextColor . ' '; - } - - $txt2 = str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $txt))); - - $s .= sprintf('BT %.2f %.2f Td (%s) Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $h + .3 * $this->FontSize)) * $k, $txt2); - - if ($this->underline) { - $s .= ' ' . $this->_dounderline($this->x + $dx, $this->y + .5 * $h + .3 * $this->FontSize, $txt); - } - - if ($this->ColorFlag) { - $s .= ' Q'; - } - - if ($link) { - $this->Link($this->x + $dx, $this->y + .5 * $h - .5 * $this->FontSize, $this->GetStringWidth($txt), $this->FontSize, $link); - } - } - - if ($s) { - $this->_out($s); - } - - $this->lasth = $h; - - if ($ln > 0) { - // Go to next line - $this->y += $h; - if ($ln == 1) { - $this->x = $this->lMargin; - } - } else { - $this->x += $w; - } - } - - function MultiCell($w, $h, $txt, $border = 0, $align = 'J', $fill = 0) - { - // Output text with automatic or explicit line breaks - $cw = &$this->CurrentFont['cw']; - - if ($w == 0) { - $w = $this->w - $this->rMargin - $this->x; - } - - $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize; - $s = str_replace("\r", '', $txt); - $nb = strlen($s); - - if ($nb > 0 and $s[$nb-1] == "\n") { - $nb--; - } - - $b = 0; - - if ($border) { - if ($border == 1) { - $border = 'LTRB'; - $b = 'LRT'; - $b2 = 'LR'; - } else { - $b2 = ''; - if (is_int(strpos($border, 'L'))) { - $b2 .= 'L'; - } - - if (is_int(strpos($border, 'R'))) { - $b2 .= 'R'; - } - - $b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2; - } - } - - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $ns = 0; - $nl = 1; - - while ($i < $nb) { - // Get next character - $c = $s{$i}; - - if ($c == "\n") { - // Explicit line break - if ($this->ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - - $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); - $i++; - $sep = -1; - $j = $i; - $l = 0; - $ns = 0; - $nl++; - - if ($border and $nl == 2) { - $b = $b2; - } - - continue; - } - - if ($c == ' ') { - $sep = $i; - $ls = $l; - $ns++; - } - - $l += isset($cw[ord($c)])?$cw[ord($c)]:0; - - if ($l > $wmax) { - // Automatic line break - if ($sep == -1) { - if ($i == $j) { - $i++; - } - - if ($this->ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - - $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); - } else { - if ($align == 'J') { - $this->ws = ($ns > 1) ? ($wmax - $ls) / 1000 * $this->FontSize / ($ns-1) : 0; - $this->_out(sprintf('%.3f Tw', $this->ws * $this->k)); - } - - $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill); - $i = $sep + 1; - } - - $sep = -1; - $j = $i; - $l = 0; - $ns = 0; - $nl++; - - if ($border and $nl == 2) { - $b = $b2; - } - } else { - $i++; - } - } - // Last chunk - if ($this->ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - - if ($border and is_int(strpos($border, 'B'))) { - $b .= 'B'; - } - - $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill); - $this->x = $this->lMargin; - } - - function Write($h, $txt, $link = '') - { - // Output text in flowing mode - $cw = &$this->CurrentFont['cw']; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize; - $s = str_replace("\r", '', $txt); - $nb = strlen($s); - $sep = -1; - $i = 0; - $j = 0; - $l = 0; - $nl = 1; - - while ($i < $nb) { - // Get next character - $c = $s{$i}; - - if ($c == "\n") { - // Explicit line break - $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link); - $i++; - $sep = -1; - $j = $i; - $l = 0; - - if ($nl == 1) { - $this->x = $this->lMargin; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize; - } - - $nl++; - continue; - } - - if ($c == ' ') { - $sep = $i; - } - - $l += $cw[$c]; - - if ($l > $wmax) { - // Automatic line break - if ($sep == -1) { - if ($this->x > $this->lMargin) { - // Move to next line - $this->x = $this->lMargin; - $this->y += $h; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize; - $i++; - $nl++; - continue; - } - - if ($i == $j) { - $i++; - } - - $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link); - } else { - $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', 0, $link); - $i = $sep + 1; - } - - $sep = -1; - $j = $i; - $l = 0; - - if ($nl == 1) { - $this->x = $this->lMargin; - $w = $this->w - $this->rMargin - $this->x; - $wmax = ($w-2 * $this->cMargin) * 1000 / $this->FontSize; - } - - $nl++; - } else { - $i++; - } - } - // Last chunk - if ($i != $j) { - $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j), 0, 0, '', 0, $link); - } - } - - function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '') - { - // Put an image on the page - if (!isset($this->images[$file])) { - // First use of image, get info - if ($type == '') { - $pos = strrpos($file, '.'); - if (!$pos) { - $this->Error('Image file has no extension and no type was specified: ' . $file); - } - - $type = substr($file, $pos + 1); - } - - $type = strtolower($type); - $mqr = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - - if ($type == 'jpg' or $type == 'jpeg') { - $info = $this->_parsejpg($file); - } elseif ($type == 'png') { - $info = $this->_parsepng($file); - } else { - // Allow for additional formats - $mtd = '_parse' . $type; - - if (!method_exists($this, $mtd)) { - $this->Error('Unsupported image type: ' . $type); - } - - $info = $this->$mtd($file); - } - - set_magic_quotes_runtime($mqr); - $info['i'] = count($this->images) + 1; - $this->images[$file] = $info; - } else { - $info = $this->images[$file]; - } - // Automatic width and height calculation if needed - if ($w == 0 and $h == 0) { - // Put image at 72 dpi - $w = $info['w'] / $this->k; - $h = $info['h'] / $this->k; - } - - if ($w == 0) { - $w = $h * $info['w'] / $info['h']; - } - - if ($h == 0) { - $h = $w * $info['h'] / $info['w']; - } - - $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', $w * $this->k, $h * $this->k, $x * $this->k, ($this->h - ($y + $h)) * $this->k, $info['i'])); - - if ($link) { - $this->Link($x, $y, $w, $h, $link); - } - } - - function Ln($h = '') - { - // Line feed; default value is last cell height - $this->x = $this->lMargin; - - if (is_string($h)) { - $this->y += $this->lasth; - } else { - $this->y += $h; - } - } - - function GetX() - { - // Get x position - return $this->x; - } - - function SetX($x) - { - // Set x position - if ($x >= 0) { - $this->x = $x; - } else { - $this->x = $this->w + $x; - } - } - - function GetY() - { - // Get y position - return $this->y; - } - - function SetY($y) - { - // Set y position and reset x - $this->x = $this->lMargin; - - if ($y >= 0) { - $this->y = $y; - } else { - $this->y = $this->h + $y; - } - } - - function SetXY($x, $y) - { - // Set x and y positions - $this->SetY($y); - $this->SetX($x); - } - - function Output($name = '', $dest = '') - { - // Output PDF to some destination - // lem9 - // global $HTTP_SERVER_VARS; - // Finish document if necessary - if ($this->state < 3) { - $this->Close(); - } - // Normalize parameters - if (is_bool($dest)) { - $dest = $dest ? 'D' : 'F'; - } - - $dest = strtoupper($dest); - - if ($dest == '') { - if ($name == '') { - $name = 'doc.pdf'; - $dest = 'I'; - } else { - $dest = 'F'; - } - } - - switch ($dest) { - case 'I': - // Send to standard output - // lem9 - // if (isset($HTTP_SERVER_VARS['SERVER_NAME'])) - if (isset($_SERVER['SERVER_NAME'])) { - // We send to a browser - header('Content-Type: application/pdf'); - - if (headers_sent()) { - $this->Error('Some data has already been output to browser, can\'t send PDF file'); - } - - header('Content-Length: ' . strlen($this->buffer)); - header('Content-disposition: inline; filename="' . $name . '"'); - } - - echo $this->buffer; - break; - - case 'D': - // Download file - // lem9 - // if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) and strpos($HTTP_SERVER_VARS['HTTP_USER_AGENT'], 'MSIE')) - if (isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) { - header('Content-Type: application/force-download'); - } else { - header('Content-Type: application/octet-stream'); - } - - if (headers_sent()) { - $this->Error('Some data has already been output to browser, can\'t send PDF file'); - } - - header('Content-Length: ' . strlen($this->buffer)); - header('Content-disposition: attachment; filename="' . $name . '"'); - echo $this->buffer; - break; - - case 'F': - // Save to local file - $f = fopen($name, 'wb'); - - if (!$f) { - $this->Error('Unable to create output file: ' . $name); - } - - fwrite($f, $this->buffer, strlen($this->buffer)); - fclose($f); - break; - - case 'S': - // Return as a string - return $this->buffer; - - default: - - $this->Error('Incorrect output destination: ' . $dest); - } - - return ''; - } - - /** - * Protected methods * - */ - - function _dochecks() - { - // Check for locale-related bug - if (1.1 == 1) { - $this->Error('Don\'t alter the locale before including class file'); - } - // Check for decimal separator - if (sprintf('%.1f', 1.0) != '1.0') { - setlocale(LC_NUMERIC, 'C'); - } - } - - function _begindoc() - { - // Start document - $this->state = 1; - $this->_out('%PDF-1.3'); - } - - function _strreplace($what, $to, $where) - { - return str_replace($what, $to, $where); - } - - function _putpages() - { - $nb = $this->page; - - if (!empty($this->AliasNbPages)) { - // Replace number of pages - for ($n = 1; $n <= $nb; $n++) { - $this->pages[$n] = $this->_strreplace($this->AliasNbPages, $nb, $this->pages[$n]); - } - } - - if ($this->DefOrientation == 'P') { - $wPt = $this->fwPt; - $hPt = $this->fhPt; - } else { - $wPt = $this->fhPt; - $hPt = $this->fwPt; - } - - $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; - - for ($n = 1; $n <= $nb; $n++) { - // Page - $this->_newobj(); - $this->_out('<_out('/Parent 1 0 R'); - - if (isset($this->OrientationChanges[$n])) { - $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]', $hPt, $wPt)); - } - - $this->_out('/Resources 2 0 R'); - - if (isset($this->PageLinks[$n])) { - // Links - $annots = '/Annots ['; - - foreach ($this->PageLinks[$n] as $pl) { - $rect = sprintf('%.2f %.2f %.2f %.2f', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]); - $annots .= '<_textstring($pl[4]) . '>>>>'; - } else { - $l = $this->links[$pl[4]]; - $h = isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt; - $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>', 1 + 2 * $l[0], $h - $l[1] * $this->k); - } - } - - $this->_out($annots . ']'); - } - - $this->_out('/Contents ' . ($this->n + 1) . ' 0 R>>'); - $this->_out('endobj'); - // Page content - $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; - $this->_newobj(); - $this->_out('<<' . $filter . '/Length ' . strlen($p) . '>>'); - $this->_putstream($p); - $this->_out('endobj'); - } - // Pages root - $this->offsets[1] = strlen($this->buffer); - $this->_out('1 0 obj'); - $this->_out('<_out($kids . ']'); - $this->_out('/Count ' . $nb); - $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]', $wPt, $hPt)); - $this->_out('>>'); - $this->_out('endobj'); - } - - function _putfonts() - { - $nf = $this->n; - - foreach ($this->diffs as $diff) { - // Encodings - $this->_newobj(); - $this->_out('<>'); - $this->_out('endobj'); - } - - $mqr = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - - foreach ($this->FontFiles as $file => $info) { - // Font file embedding - $this->_newobj(); - $this->FontFiles[$file]['n'] = $this->n; - - if (defined('FPDF_FONTPATH')) { - $file = FPDF_FONTPATH . $file; - } - - $size = filesize($file); - - if (!$size) { - $this->Error('Font file not found'); - } - - $this->_out('<_out('/Filter /FlateDecode'); - } - - $this->_out('/Length1 ' . $info['length1']); - - if (isset($info['length2'])) { - $this->_out('/Length2 ' . $info['length2'] . ' /Length3 0'); - } - - $this->_out('>>'); - $f = fopen($file, 'rb'); - $this->_putstream(fread($f, $size)); - fclose($f); - $this->_out('endobj'); - } - - set_magic_quotes_runtime($mqr); - - foreach ($this->fonts as $k => $font) { - // Font objects - $this->fonts[$k]['n'] = $this->n + 1; - $type = $font['type']; - $name = $font['name']; - - if ($type == 'core') { - // Standard font - $this->_newobj(); - $this->_out('<_out('/BaseFont /' . $name); - $this->_out('/Subtype /Type1'); - - if ($name != 'Symbol' and $name != 'ZapfDingbats') { - $this->_out('/Encoding /WinAnsiEncoding'); - } - - $this->_out('>>'); - $this->_out('endobj'); - } elseif ($type == 'Type1' or $type == 'TrueType') { - // Additional Type1 or TrueType font - $this->_newobj(); - $this->_out('<_out('/BaseFont /' . $name); - $this->_out('/Subtype /' . $type); - $this->_out('/FirstChar 32 /LastChar 255'); - $this->_out('/Widths ' . ($this->n + 1) . ' 0 R'); - $this->_out('/FontDescriptor ' . ($this->n + 2) . ' 0 R'); - - if ($font['enc']) { - if (isset($font['diff'])) { - $this->_out('/Encoding ' . ($nf + $font['diff']) . ' 0 R'); - } else { - $this->_out('/Encoding /WinAnsiEncoding'); - } - } - - $this->_out('>>'); - $this->_out('endobj'); - // Widths - $this->_newobj(); - $cw = &$font['cw']; - $s = '['; - - for ($i = 32; $i <= 255; $i++) { - $s .= $cw[chr($i)] . ' '; - } - - $this->_out($s . ']'); - $this->_out('endobj'); - // Descriptor - $this->_newobj(); - $s = '< $v) { - $s .= ' /' . $k . ' ' . $v; - } - - $file = $font['file']; - - if ($file) { - $s .= ' /FontFile' . ($type == 'Type1' ? '' : '2') . ' ' . $this->FontFiles[$file]['n'] . ' 0 R'; - } - - $this->_out($s . '>>'); - $this->_out('endobj'); - } else { - // Allow for additional types - $mtd = '_put' . strtolower($type); - - if (!method_exists($this, $mtd)) { - $this->Error('Unsupported font type: ' . $type); - } - - $this->$mtd($font); - } - } - } - - function _putimages() - { - $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; - reset($this->images); - - while (list($file, $info) = each($this->images)) { - $this->_newobj(); - $this->images[$file]['n'] = $this->n; - $this->_out('<_out('/Subtype /Image'); - $this->_out('/Width ' . $info['w']); - $this->_out('/Height ' . $info['h']); - - if ($info['cs'] == 'Indexed') { - $this->_out('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal']) / 3-1) . ' ' . ($this->n + 1) . ' 0 R]'); - } else { - $this->_out('/ColorSpace /' . $info['cs']); - if ($info['cs'] == 'DeviceCMYK') { - $this->_out('/Decode [1 0 1 0 1 0 1 0]'); - } - } - - $this->_out('/BitsPerComponent ' . $info['bpc']); - $this->_out('/Filter /' . $info['f']); - - if (isset($info['parms'])) { - $this->_out($info['parms']); - } - - if (isset($info['trns']) and is_array($info['trns'])) { - $trns = ''; - for ($i = 0; $i < count($info['trns']); $i++) { - $trns .= $info['trns'][$i] . ' ' . $info['trns'][$i] . ' '; - } - $this->_out('/Mask [' . $trns . ']'); - } - - $this->_out('/Length ' . strlen($info['data']) . '>>'); - $this->_putstream($info['data']); - unset($this->images[$file]['data']); - $this->_out('endobj'); - // Palette - if ($info['cs'] == 'Indexed') { - $this->_newobj(); - $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal']; - $this->_out('<<' . $filter . '/Length ' . strlen($pal) . '>>'); - $this->_putstream($pal); - $this->_out('endobj'); - } - } - } - - function _putresources() - { - $this->_putfonts(); - $this->_putimages(); - // Resource dictionary - $this->offsets[2] = strlen($this->buffer); - $this->_out('2 0 obj'); - $this->_out('<_out('/Font <<'); - - foreach ($this->fonts as $font) { - $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R'); - } - $this->_out('>>'); - if (count($this->images)) { - $this->_out('/XObject <<'); - foreach ($this->images as $image) { - $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R'); - } - $this->_out('>>'); - } - $this->_out('>>'); - $this->_out('endobj'); - } - - function _putinfo() - { - $this->_out('/Producer ' . $this->_textstring('FPDF ' . FPDF_VERSION)); - - if (!empty($this->title)) { - $this->_out('/Title ' . $this->_textstring($this->title)); - } - - if (!empty($this->subject)) { - $this->_out('/Subject ' . $this->_textstring($this->subject)); - } - - if (!empty($this->author)) { - $this->_out('/Author ' . $this->_textstring($this->author)); - } - - if (!empty($this->keywords)) { - $this->_out('/Keywords ' . $this->_textstring($this->keywords)); - } - - if (!empty($this->creator)) { - $this->_out('/Creator ' . $this->_textstring($this->creator)); - } - - $this->_out('/CreationDate ' . $this->_textstring('D:' . date('YmdHis'))); - } - - function _putcatalog() - { - $this->_out('/Type /Catalog'); - $this->_out('/Pages 1 0 R'); - - if ($this->ZoomMode == 'fullpage') { - $this->_out('/OpenAction [3 0 R /Fit]'); - } elseif ($this->ZoomMode == 'fullwidth') { - $this->_out('/OpenAction [3 0 R /FitH null]'); - } elseif ($this->ZoomMode == 'real') { - $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); - } elseif (!is_string($this->ZoomMode)) { - $this->_out('/OpenAction [3 0 R /XYZ null null ' . ($this->ZoomMode / 100) . ']'); - } - if ($this->LayoutMode == 'single') { - $this->_out('/PageLayout /SinglePage'); - } elseif ($this->LayoutMode == 'continuous') { - $this->_out('/PageLayout /OneColumn'); - } elseif ($this->LayoutMode == 'two') { - $this->_out('/PageLayout /TwoColumnLeft'); - } - } - - function _puttrailer() - { - $this->_out('/Size ' . ($this->n + 1)); - $this->_out('/Root ' . $this->n . ' 0 R'); - $this->_out('/Info ' . ($this->n-1) . ' 0 R'); - } - - function _enddoc() - { - $this->_putpages(); - $this->_putresources(); - // Info - $this->_newobj(); - $this->_out('<<'); - $this->_putinfo(); - $this->_out('>>'); - $this->_out('endobj'); - // Catalog - $this->_newobj(); - $this->_out('<<'); - $this->_putcatalog(); - $this->_out('>>'); - $this->_out('endobj'); - // Cross-ref - $o = strlen($this->buffer); - $this->_out('xref'); - $this->_out('0 ' . ($this->n + 1)); - $this->_out('0000000000 65535 f '); - for ($i = 1; $i <= $this->n; $i++) { - $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i])); - } - // Trailer - $this->_out('trailer'); - $this->_out('<<'); - $this->_puttrailer(); - $this->_out('>>'); - $this->_out('startxref'); - $this->_out($o); - $this->_out('%%EOF'); - $this->state = 3; - } - - function _beginpage($orientation) - { - $this->page++; - $this->pages[$this->page] = ''; - $this->state = 2; - $this->x = $this->lMargin; - $this->y = $this->tMargin; - $this->FontFamily = ''; - // Page orientation - if (!$orientation) { - $orientation = $this->DefOrientation; - } else { - $orientation = strtoupper($orientation{0}); - if ($orientation != $this->DefOrientation) { - $this->OrientationChanges[$this->page] = true; - } - } - - if ($orientation != $this->CurOrientation) { - // Change orientation - if ($orientation == 'P') { - $this->wPt = $this->fwPt; - $this->hPt = $this->fhPt; - $this->w = $this->fw; - $this->h = $this->fh; - } else { - $this->wPt = $this->fhPt; - $this->hPt = $this->fwPt; - $this->w = $this->fh; - $this->h = $this->fw; - } - - $this->PageBreakTrigger = $this->h - $this->bMargin; - $this->CurOrientation = $orientation; - } - } - - function _endpage() - { - // End of page contents - $this->state = 1; - } - - function _newobj() - { - // Begin a new object - $this->n++; - $this->offsets[$this->n] = strlen($this->buffer); - $this->_out($this->n . ' 0 obj'); - } - - function _dounderline($x, $y, $txt) - { - // Underline text - $up = $this->CurrentFont['up']; - $ut = $this->CurrentFont['ut']; - $w = $this->GetStringWidth($txt) + $this->ws * substr_count($txt, ' '); - return sprintf('%.2f %.2f %.2f %.2f re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, - $ut / 1000 * $this->FontSizePt); - } - - function _parsejpg($file) - { - // Extract info from a JPEG file - $a = GetImageSize($file); - - if (!$a) { - $this->Error('Missing or incorrect image file: ' . $file); - } - - if ($a[2] != 2) { - $this->Error('Not a JPEG file: ' . $file); - } - - if (!isset($a['channels']) or $a['channels'] == 3) { - $colspace = 'DeviceRGB'; - } elseif ($a['channels'] == 4) { - $colspace = 'DeviceCMYK'; - } else { - $colspace = 'DeviceGray'; - } - - $bpc = isset($a['bits']) ? $a['bits'] : 8; - // Read whole file - $f = fopen($file, 'rb'); - $data = ''; - - while (!feof($f)) { - $data .= fread($f, 4096); - } - - fclose($f); - - return array('w' => $a[0], 'h' => $a[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data); - } - - function _parsepng($file) - { - // Extract info from a PNG file - $f = fopen($file, 'rb'); - - if (!$f) { - $this->Error('Can\'t open image file: ' . $file); - } - // Check signature - if (fread($f, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10)) { - $this->Error('Not a PNG file: ' . $file); - } - // Read header chunk - fread($f, 4); - - if (fread($f, 4) != 'IHDR') { - $this->Error('Incorrect PNG file: ' . $file); - } - - $w = $this->_freadint($f); - $h = $this->_freadint($f); - $bpc = ord(fread($f, 1)); - - if ($bpc > 8) { - $this->Error('16-bit depth not supported: ' . $file); - } - - $ct = ord(fread($f, 1)); - - if ($ct == 0) { - $colspace = 'DeviceGray'; - } elseif ($ct == 2) { - $colspace = 'DeviceRGB'; - } elseif ($ct == 3) { - $colspace = 'Indexed'; - } else { - $this->Error('Alpha channel not supported: ' . $file); - } - - if (ord(fread($f, 1)) != 0) { - $this->Error('Unknown compression method: ' . $file); - } - - if (ord(fread($f, 1)) != 0) { - $this->Error('Unknown filter method: ' . $file); - } - - if (ord(fread($f, 1)) != 0) { - $this->Error('Interlacing not supported: ' . $file); - } - - fread($f, 4); - $parms = '/DecodeParms <>'; - // Scan chunks looking for palette, transparency and image data - $pal = ''; - $trns = ''; - $data = ''; - - do { - $n = $this->_freadint($f); - $type = fread($f, 4); - if ($type == 'PLTE') { - // Read palette - $pal = fread($f, $n); - fread($f, 4); - } elseif ($type == 'tRNS') { - // Read transparency info - $t = fread($f, $n); - if ($ct == 0) { - $trns = array(ord(substr($t, 1, 1))); - } elseif ($ct == 2) { - $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1))); - } else { - $pos = strpos($t, chr(0)); - if (is_int($pos)) { - $trns = array($pos); - } - } - fread($f, 4); - } elseif ($type == 'IDAT') { - // Read image data block - $data .= fread($f, $n); - fread($f, 4); - } elseif ($type == 'IEND') { - break; - } else { - fread($f, $n + 4); - } - } while ($n); { - if ($colspace == 'Indexed' and empty($pal)) { - $this->Error('Missing palette in ' . $file); - } - } - - fclose($f); - return array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $data); - } - - function _freadint($f) - { - // Read a 4-byte integer from file - $i = ord(fread($f, 1)) << 24; - $i += ord(fread($f, 1)) << 16; - $i += ord(fread($f, 1)) << 8; - $i += ord(fread($f, 1)); - return $i; - } - - function _textstring($s) - { - // Format a text string - return '(' . $this->_escape($s) . ')'; - } - - function _escape($s) - { - // Add \ before \, ( and ) - return str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $s))); - } - - function _putstream($s) - { - $this->_out('stream'); - $this->_out($s); - $this->_out('endstream'); - } - - function _out($s) - { - // Add a line to the document - if ($this->state == 2) { - $this->pages[$this->page] .= $s . "\n"; - } else { - $this->buffer .= $s . "\n"; - } - } - // End of class - } - // Handle special IE contype request - // lem9 - // if (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) and $HTTP_SERVER_VARS['HTTP_USER_AGENT']=='contype') - if (isset($_SERVER['HTTP_USER_AGENT']) and $_SERVER['HTTP_USER_AGENT'] == 'contype') { - Header('Content-Type: application/pdf'); - exit; - } -} - +/******************************************************************************* +* Software: FPDF * +* Version: 1.52 * +* Date: 2003-12-30 * +* Author: Olivier PLATHEY * +* License: Freeware * +* * +* You may use, modify and redistribute this software as you wish. * +*******************************************************************************/ + +if(!class_exists('FPDF')) +{ +define('FPDF_VERSION','1.52'); + +class FPDF +{ +//Private properties +var $page; //current page number +var $n; //current object number +var $offsets; //array of object offsets +var $buffer; //buffer holding in-memory PDF +var $pages; //array containing pages +var $state; //current document state +var $compress; //compression flag +var $DefOrientation; //default orientation +var $CurOrientation; //current orientation +var $OrientationChanges; //array indicating orientation changes +var $k; //scale factor (number of points in user unit) +var $fwPt,$fhPt; //dimensions of page format in points +var $fw,$fh; //dimensions of page format in user unit +var $wPt,$hPt; //current dimensions of page in points +var $w,$h; //current dimensions of page in user unit +var $lMargin; //left margin +var $tMargin; //top margin +var $rMargin; //right margin +var $bMargin; //page break margin +var $cMargin; //cell margin +var $x,$y; //current position in user unit for cell positioning +var $lasth; //height of last cell printed +var $LineWidth; //line width in user unit +var $CoreFonts; //array of standard font names +var $fonts; //array of used fonts +var $FontFiles; //array of font files +var $diffs; //array of encoding differences +var $images; //array of used images +var $PageLinks; //array of links in pages +var $links; //array of internal links +var $FontFamily; //current font family +var $FontStyle; //current font style +var $underline; //underlining flag +var $CurrentFont; //current font info +var $FontSizePt; //current font size in points +var $FontSize; //current font size in user unit +var $DrawColor; //commands for drawing color +var $FillColor; //commands for filling color +var $TextColor; //commands for text color +var $ColorFlag; //indicates whether fill and text colors are different +var $ws; //word spacing +var $AutoPageBreak; //automatic page breaking +var $PageBreakTrigger; //threshold used to trigger page breaks +var $InFooter; //flag set when processing footer +var $ZoomMode; //zoom display mode +var $LayoutMode; //layout display mode +var $title; //title +var $subject; //subject +var $author; //author +var $keywords; //keywords +var $creator; //creator +var $AliasNbPages; //alias for total number of pages + +/******************************************************************************* +* * +* Public methods * +* * +*******************************************************************************/ +function FPDF($orientation='P',$unit='mm',$format='A4') +{ + //Some checks + $this->_dochecks(); + //Initialization of properties + $this->page=0; + $this->n=2; + $this->buffer=''; + $this->pages=array(); + $this->OrientationChanges=array(); + $this->state=0; + $this->fonts=array(); + $this->FontFiles=array(); + $this->diffs=array(); + $this->images=array(); + $this->links=array(); + $this->InFooter=false; + $this->lasth=0; + $this->FontFamily=''; + $this->FontStyle=''; + $this->FontSizePt=12; + $this->underline=false; + $this->DrawColor='0 G'; + $this->FillColor='0 g'; + $this->TextColor='0 g'; + $this->ColorFlag=false; + $this->ws=0; + //Standard fonts + $this->CoreFonts=array('courier'=>'Courier','courierB'=>'Courier-Bold','courierI'=>'Courier-Oblique','courierBI'=>'Courier-BoldOblique', + 'helvetica'=>'Helvetica','helveticaB'=>'Helvetica-Bold','helveticaI'=>'Helvetica-Oblique','helveticaBI'=>'Helvetica-BoldOblique', + 'times'=>'Times-Roman','timesB'=>'Times-Bold','timesI'=>'Times-Italic','timesBI'=>'Times-BoldItalic', + 'symbol'=>'Symbol','zapfdingbats'=>'ZapfDingbats'); + //Scale factor + if($unit=='pt') + $this->k=1; + elseif($unit=='mm') + $this->k=72/25.4; + elseif($unit=='cm') + $this->k=72/2.54; + elseif($unit=='in') + $this->k=72; + else + $this->Error('Incorrect unit: '.$unit); + //Page format + if(is_string($format)) + { + $format=strtolower($format); + if($format=='a3') + $format=array(841.89,1190.55); + elseif($format=='a4') + $format=array(595.28,841.89); + elseif($format=='a5') + $format=array(420.94,595.28); + elseif($format=='letter') + $format=array(612,792); + elseif($format=='legal') + $format=array(612,1008); + else + $this->Error('Unknown page format: '.$format); + $this->fwPt=$format[0]; + $this->fhPt=$format[1]; + } + else + { + $this->fwPt=$format[0]*$this->k; + $this->fhPt=$format[1]*$this->k; + } + $this->fw=$this->fwPt/$this->k; + $this->fh=$this->fhPt/$this->k; + //Page orientation + $orientation=strtolower($orientation); + if($orientation=='p' or $orientation=='portrait') + { + $this->DefOrientation='P'; + $this->wPt=$this->fwPt; + $this->hPt=$this->fhPt; + } + elseif($orientation=='l' or $orientation=='landscape') + { + $this->DefOrientation='L'; + $this->wPt=$this->fhPt; + $this->hPt=$this->fwPt; + } + else + $this->Error('Incorrect orientation: '.$orientation); + $this->CurOrientation=$this->DefOrientation; + $this->w=$this->wPt/$this->k; + $this->h=$this->hPt/$this->k; + //Page margins (1 cm) + $margin=28.35/$this->k; + $this->SetMargins($margin,$margin); + //Interior cell margin (1 mm) + $this->cMargin=$margin/10; + //Line width (0.2 mm) + $this->LineWidth=.567/$this->k; + //Automatic page break + $this->SetAutoPageBreak(true,2*$margin); + //Full width display mode + $this->SetDisplayMode('fullwidth'); + //Compression + $this->SetCompression(true); +} + +function SetMargins($left,$top,$right=-1) +{ + //Set left, top and right margins + $this->lMargin=$left; + $this->tMargin=$top; + if($right==-1) + $right=$left; + $this->rMargin=$right; +} + +function SetLeftMargin($margin) +{ + //Set left margin + $this->lMargin=$margin; + if($this->page>0 and $this->x<$margin) + $this->x=$margin; +} + +function SetTopMargin($margin) +{ + //Set top margin + $this->tMargin=$margin; +} + +function SetRightMargin($margin) +{ + //Set right margin + $this->rMargin=$margin; +} + +function SetAutoPageBreak($auto,$margin=0) +{ + //Set auto page break mode and triggering margin + $this->AutoPageBreak=$auto; + $this->bMargin=$margin; + $this->PageBreakTrigger=$this->h-$margin; +} + +function SetDisplayMode($zoom,$layout='continuous') +{ + //Set display mode in viewer + if($zoom=='fullpage' or $zoom=='fullwidth' or $zoom=='real' or $zoom=='default' or !is_string($zoom)) + $this->ZoomMode=$zoom; + else + $this->Error('Incorrect zoom display mode: '.$zoom); + if($layout=='single' or $layout=='continuous' or $layout=='two' or $layout=='default') + $this->LayoutMode=$layout; + else + $this->Error('Incorrect layout display mode: '.$layout); +} + +function SetCompression($compress) +{ + //Set page compression + if(function_exists('gzcompress')) + $this->compress=$compress; + else + $this->compress=false; +} + +function SetTitle($title) +{ + //Title of document + $this->title=$title; +} + +function SetSubject($subject) +{ + //Subject of document + $this->subject=$subject; +} + +function SetAuthor($author) +{ + //Author of document + $this->author=$author; +} + +function SetKeywords($keywords) +{ + //Keywords of document + $this->keywords=$keywords; +} + +function SetCreator($creator) +{ + //Creator of document + $this->creator=$creator; +} + +function AliasNbPages($alias='{nb}') +{ + //Define an alias for total number of pages + $this->AliasNbPages=$alias; +} + +function Error($msg) +{ + //Fatal error + die('FPDF error: '.$msg); +} + +function Open() +{ + //Begin document + if($this->state==0) + $this->_begindoc(); +} + +function Close() +{ + //Terminate document + if($this->state==3) + return; + if($this->page==0) + $this->AddPage(); + //Page footer + $this->InFooter=true; + $this->Footer(); + $this->InFooter=false; + //Close page + $this->_endpage(); + //Close document + $this->_enddoc(); +} + +function AddPage($orientation='') +{ + //Start a new page + if($this->state==0) + $this->Open(); + $family=$this->FontFamily; + $style=$this->FontStyle.($this->underline ? 'U' : ''); + $size=$this->FontSizePt; + $lw=$this->LineWidth; + $dc=$this->DrawColor; + $fc=$this->FillColor; + $tc=$this->TextColor; + $cf=$this->ColorFlag; + if($this->page>0) + { + //Page footer + $this->InFooter=true; + $this->Footer(); + $this->InFooter=false; + //Close page + $this->_endpage(); + } + //Start new page + $this->_beginpage($orientation); + //Set line cap style to square + $this->_out('2 J'); + //Set line width + $this->LineWidth=$lw; + $this->_out(sprintf('%.2f w',$lw*$this->k)); + //Set font + if($family) + $this->SetFont($family,$style,$size); + //Set colors + $this->DrawColor=$dc; + if($dc!='0 G') + $this->_out($dc); + $this->FillColor=$fc; + if($fc!='0 g') + $this->_out($fc); + $this->TextColor=$tc; + $this->ColorFlag=$cf; + //Page header + $this->Header(); + //Restore line width + if($this->LineWidth!=$lw) + { + $this->LineWidth=$lw; + $this->_out(sprintf('%.2f w',$lw*$this->k)); + } + //Restore font + if($family) + $this->SetFont($family,$style,$size); + //Restore colors + if($this->DrawColor!=$dc) + { + $this->DrawColor=$dc; + $this->_out($dc); + } + if($this->FillColor!=$fc) + { + $this->FillColor=$fc; + $this->_out($fc); + } + $this->TextColor=$tc; + $this->ColorFlag=$cf; +} + +function Header() +{ + //To be implemented in your own inherited class +} + +function Footer() +{ + //To be implemented in your own inherited class +} + +function PageNo() +{ + //Get current page number + return $this->page; +} + +function SetDrawColor($r,$g=-1,$b=-1) +{ + //Set color for all stroking operations + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->DrawColor=sprintf('%.3f G',$r/255); + else + $this->DrawColor=sprintf('%.3f %.3f %.3f RG',$r/255,$g/255,$b/255); + if($this->page>0) + $this->_out($this->DrawColor); +} + +function SetFillColor($r,$g=-1,$b=-1) +{ + //Set color for all filling operations + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->FillColor=sprintf('%.3f g',$r/255); + else + $this->FillColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); + $this->ColorFlag=($this->FillColor!=$this->TextColor); + if($this->page>0) + $this->_out($this->FillColor); +} + +function SetTextColor($r,$g=-1,$b=-1) +{ + //Set color for text + if(($r==0 and $g==0 and $b==0) or $g==-1) + $this->TextColor=sprintf('%.3f g',$r/255); + else + $this->TextColor=sprintf('%.3f %.3f %.3f rg',$r/255,$g/255,$b/255); + $this->ColorFlag=($this->FillColor!=$this->TextColor); +} + +function GetStringWidth($s) +{ + //Get width of a string in the current font + $s=(string)$s; + $cw=&$this->CurrentFont['cw']; + $w=0; + $l=strlen($s); + for($i=0;$i<$l;$i++) + $w+=$cw[$s{$i}]; + return $w*$this->FontSize/1000; +} + +function SetLineWidth($width) +{ + //Set line width + $this->LineWidth=$width; + if($this->page>0) + $this->_out(sprintf('%.2f w',$width*$this->k)); +} + +function Line($x1,$y1,$x2,$y2) +{ + //Draw a line + $this->_out(sprintf('%.2f %.2f m %.2f %.2f l S',$x1*$this->k,($this->h-$y1)*$this->k,$x2*$this->k,($this->h-$y2)*$this->k)); +} + +function Rect($x,$y,$w,$h,$style='') +{ + //Draw a rectangle + if($style=='F') + $op='f'; + elseif($style=='FD' or $style=='DF') + $op='B'; + else + $op='S'; + $this->_out(sprintf('%.2f %.2f %.2f %.2f re %s',$x*$this->k,($this->h-$y)*$this->k,$w*$this->k,-$h*$this->k,$op)); +} + +function AddFont($family,$style='',$file='') +{ + //Add a TrueType or Type1 font + $family=strtolower($family); + if($family=='arial') + $family='helvetica'; + $style=strtoupper($style); + if($style=='IB') + $style='BI'; + if(isset($this->fonts[$family.$style])) + $this->Error('Font already added: '.$family.' '.$style); + if($file=='') + $file=str_replace(' ','',$family).strtolower($style).'.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($name)) + $this->Error('Could not include font definition file'); + $i=count($this->fonts)+1; + $this->fonts[$family.$style]=array('i'=>$i,'type'=>$type,'name'=>$name,'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw,'enc'=>$enc,'file'=>$file); + if($diff) + { + //Search existing encodings + $d=0; + $nb=count($this->diffs); + for($i=1;$i<=$nb;$i++) + if($this->diffs[$i]==$diff) + { + $d=$i; + break; + } + if($d==0) + { + $d=$nb+1; + $this->diffs[$d]=$diff; + } + $this->fonts[$family.$style]['diff']=$d; + } + if($file) + { + if($type=='TrueType') + $this->FontFiles[$file]=array('length1'=>$originalsize); + else + $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2); + } +} + +function SetFont($family,$style='',$size=0) +{ + //Select a font; size given in points + global $fpdf_charwidths; + + $family=strtolower($family); + if($family=='') + $family=$this->FontFamily; + if($family=='arial') + $family='helvetica'; + elseif($family=='symbol' or $family=='zapfdingbats') + $style=''; + $style=strtoupper($style); + if(is_int(strpos($style,'U'))) + { + $this->underline=true; + $style=str_replace('U','',$style); + } + else + $this->underline=false; + if($style=='IB') + $style='BI'; + if($size==0) + $size=$this->FontSizePt; + //Test if font is already selected + if($this->FontFamily==$family and $this->FontStyle==$style and $this->FontSizePt==$size) + return; + //Test if used for the first time + $fontkey=$family.$style; + if(!isset($this->fonts[$fontkey])) + { + //Check if one of the standard fonts + if(isset($this->CoreFonts[$fontkey])) + { + if(!isset($fpdf_charwidths[$fontkey])) + { + //Load metric file + $file=$family; + if($family=='times' or $family=='helvetica') + $file.=strtolower($style); + $file.='.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($fpdf_charwidths[$fontkey])) + $this->Error('Could not include font metric file'); + } + $i=count($this->fonts)+1; + $this->fonts[$fontkey]=array('i'=>$i,'type'=>'core','name'=>$this->CoreFonts[$fontkey],'up'=>-100,'ut'=>50,'cw'=>$fpdf_charwidths[$fontkey]); + } + else + $this->Error('Undefined font: '.$family.' '.$style); + } + //Select it + $this->FontFamily=$family; + $this->FontStyle=$style; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + $this->CurrentFont=&$this->fonts[$fontkey]; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function SetFontSize($size) +{ + //Set font size in points + if($this->FontSizePt==$size) + return; + $this->FontSizePt=$size; + $this->FontSize=$size/$this->k; + if($this->page>0) + $this->_out(sprintf('BT /F%d %.2f Tf ET',$this->CurrentFont['i'],$this->FontSizePt)); +} + +function AddLink() +{ + //Create a new internal link + $n=count($this->links)+1; + $this->links[$n]=array(0,0); + return $n; +} + +function SetLink($link,$y=0,$page=-1) +{ + //Set destination of internal link + if($y==-1) + $y=$this->y; + if($page==-1) + $page=$this->page; + $this->links[$link]=array($page,$y); +} + +function Link($x,$y,$w,$h,$link) +{ + //Put a link on the page + $this->PageLinks[$this->page][]=array($x*$this->k,$this->hPt-$y*$this->k,$w*$this->k,$h*$this->k,$link); +} + +function Text($x,$y,$txt) +{ + //Output a string + $s=sprintf('BT %.2f %.2f Td (%s) Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escape($txt)); + if($this->underline and $txt!='') + $s.=' '.$this->_dounderline($x,$y,$txt); + if($this->ColorFlag) + $s='q '.$this->TextColor.' '.$s.' Q'; + $this->_out($s); +} + +function AcceptPageBreak() +{ + //Accept automatic page break or not + return $this->AutoPageBreak; +} + +function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='') +{ + //Output a cell + $k=$this->k; + if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) + { + //Automatic page break + $x=$this->x; + $ws=$this->ws; + if($ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->AddPage($this->CurOrientation); + $this->x=$x; + if($ws>0) + { + $this->ws=$ws; + $this->_out(sprintf('%.3f Tw',$ws*$k)); + } + } + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $s=''; + if($fill==1 or $border==1) + { + if($fill==1) + $op=($border==1) ? 'B' : 'f'; + else + $op='S'; + $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); + } + if(is_string($border)) + { + $x=$this->x; + $y=$this->y; + if(is_int(strpos($border,'L'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'T'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); + if(is_int(strpos($border,'R'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'B'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + } + if($txt!='') + { + if($align=='R') + $dx=$w-$this->cMargin-$this->GetStringWidth($txt); + elseif($align=='C') + $dx=($w-$this->GetStringWidth($txt))/2; + else + $dx=$this->cMargin; + if($this->ColorFlag) + $s.='q '.$this->TextColor.' '; + $txt2=str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$txt))); + $s.=sprintf('BT %.2f %.2f Td (%s) Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txt2); + if($this->underline) + $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$txt); + if($this->ColorFlag) + $s.=' Q'; + if($link) + $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$this->GetStringWidth($txt),$this->FontSize,$link); + } + if($s) + $this->_out($s); + $this->lasth=$h; + if($ln>0) + { + //Go to next line + $this->y+=$h; + if($ln==1) + $this->x=$this->lMargin; + } + else + $this->x+=$w; +} + +function MultiCell($w,$h,$txt,$border=0,$align='J',$fill=0) +{ + //Output text with automatic or explicit line breaks + $cw=&$this->CurrentFont['cw']; + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $s=str_replace("\r",'',$txt); + $nb=strlen($s); + if($nb>0 and $s[$nb-1]=="\n") + $nb--; + $b=0; + if($border) + { + if($border==1) + { + $border='LTRB'; + $b='LRT'; + $b2='LR'; + } + else + { + $b2=''; + if(is_int(strpos($border,'L'))) + $b2.='L'; + if(is_int(strpos($border,'R'))) + $b2.='R'; + $b=is_int(strpos($border,'T')) ? $b2.'T' : $b2; + } + } + $sep=-1; + $i=0; + $j=0; + $l=0; + $ns=0; + $nl=1; + while($i<$nb) + { + //Get next character + $c=$s{$i}; + if($c=="\n") + { + //Explicit line break + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $i++; + $sep=-1; + $j=$i; + $l=0; + $ns=0; + $nl++; + if($border and $nl==2) + $b=$b2; + continue; + } + if($c==' ') + { + $sep=$i; + $ls=$l; + $ns++; + } + $l+=isset($cw[ord($c)])?$cw[ord($c)]:0; + if($l>$wmax) + { + //Automatic line break + if($sep==-1) + { + if($i==$j) + $i++; + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + } + else + { + if($align=='J') + { + $this->ws=($ns>1) ? ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0; + $this->_out(sprintf('%.3f Tw',$this->ws*$this->k)); + } + $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill); + $i=$sep+1; + } + $sep=-1; + $j=$i; + $l=0; + $ns=0; + $nl++; + if($border and $nl==2) + $b=$b2; + } + else + $i++; + } + //Last chunk + if($this->ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + if($border and is_int(strpos($border,'B'))) + $b.='B'; + $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill); + $this->x=$this->lMargin; +} + +function Write($h,$txt,$link='') +{ + //Output text in flowing mode + $cw=&$this->CurrentFont['cw']; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $s=str_replace("\r",'',$txt); + $nb=strlen($s); + $sep=-1; + $i=0; + $j=0; + $l=0; + $nl=1; + while($i<$nb) + { + //Get next character + $c=$s{$i}; + if($c=="\n") + { + //Explicit line break + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + $i++; + $sep=-1; + $j=$i; + $l=0; + if($nl==1) + { + $this->x=$this->lMargin; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + continue; + } + if($c==' ') + $sep=$i; + $l+=$cw[$c]; + if($l>$wmax) + { + //Automatic line break + if($sep==-1) + { + if($this->x>$this->lMargin) + { + //Move to next line + $this->x=$this->lMargin; + $this->y+=$h; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + $i++; + $nl++; + continue; + } + if($i==$j) + $i++; + $this->Cell($w,$h,substr($s,$j,$i-$j),0,2,'',0,$link); + } + else + { + $this->Cell($w,$h,substr($s,$j,$sep-$j),0,2,'',0,$link); + $i=$sep+1; + } + $sep=-1; + $j=$i; + $l=0; + if($nl==1) + { + $this->x=$this->lMargin; + $w=$this->w-$this->rMargin-$this->x; + $wmax=($w-2*$this->cMargin)*1000/$this->FontSize; + } + $nl++; + } + else + $i++; + } + //Last chunk + if($i!=$j) + $this->Cell($l/1000*$this->FontSize,$h,substr($s,$j),0,0,'',0,$link); +} + +function Image($file,$x,$y,$w=0,$h=0,$type='',$link='') +{ + //Put an image on the page + if(!isset($this->images[$file])) + { + //First use of image, get info + if($type=='') + { + $pos=strrpos($file,'.'); + if(!$pos) + $this->Error('Image file has no extension and no type was specified: '.$file); + $type=substr($file,$pos+1); + } + $type=strtolower($type); + $mqr=get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + if($type=='jpg' or $type=='jpeg') + $info=$this->_parsejpg($file); + elseif($type=='png') + $info=$this->_parsepng($file); + else + { + //Allow for additional formats + $mtd='_parse'.$type; + if(!method_exists($this,$mtd)) + $this->Error('Unsupported image type: '.$type); + $info=$this->$mtd($file); + } + set_magic_quotes_runtime($mqr); + $info['i']=count($this->images)+1; + $this->images[$file]=$info; + } + else + $info=$this->images[$file]; + //Automatic width and height calculation if needed + if($w==0 and $h==0) + { + //Put image at 72 dpi + $w=$info['w']/$this->k; + $h=$info['h']/$this->k; + } + if($w==0) + $w=$h*$info['w']/$info['h']; + if($h==0) + $h=$w*$info['h']/$info['w']; + $this->_out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',$w*$this->k,$h*$this->k,$x*$this->k,($this->h-($y+$h))*$this->k,$info['i'])); + if($link) + $this->Link($x,$y,$w,$h,$link); +} + +function Ln($h='') +{ + //Line feed; default value is last cell height + $this->x=$this->lMargin; + if(is_string($h)) + $this->y+=$this->lasth; + else + $this->y+=$h; +} + +function GetX() +{ + //Get x position + return $this->x; +} + +function SetX($x) +{ + //Set x position + if($x>=0) + $this->x=$x; + else + $this->x=$this->w+$x; +} + +function GetY() +{ + //Get y position + return $this->y; +} + +function SetY($y) +{ + //Set y position and reset x + $this->x=$this->lMargin; + if($y>=0) + $this->y=$y; + else + $this->y=$this->h+$y; +} + +function SetXY($x,$y) +{ + //Set x and y positions + $this->SetY($y); + $this->SetX($x); +} + +function Output($name='',$dest='') +{ + //Output PDF to some destination + // lem9 + //global $HTTP_SERVER_VARS; + + //Finish document if necessary + if($this->state<3) + $this->Close(); + //Normalize parameters + if(is_bool($dest)) + $dest=$dest ? 'D' : 'F'; + $dest=strtoupper($dest); + if($dest=='') + { + if($name=='') + { + $name='doc.pdf'; + $dest='I'; + } + else + $dest='F'; + } + switch($dest) + { + case 'I': + //Send to standard output + // lem9 + //if(isset($HTTP_SERVER_VARS['SERVER_NAME'])) + if(isset($_SERVER['SERVER_NAME'])) + { + //We send to a browser + Header('Content-Type: application/pdf'); + if(headers_sent()) + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + Header('Content-Length: '.strlen($this->buffer)); + Header('Content-disposition: inline; filename="'.$name.'"'); + } + echo $this->buffer; + break; + case 'D': + //Download file + // lem9 + //if(isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) and strpos($HTTP_SERVER_VARS['HTTP_USER_AGENT'],'MSIE')) + if(isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')) + Header('Content-Type: application/force-download'); + else + Header('Content-Type: application/octet-stream'); + if(headers_sent()) + $this->Error('Some data has already been output to browser, can\'t send PDF file'); + Header('Content-Length: '.strlen($this->buffer)); + Header('Content-disposition: attachment; filename="'.$name.'"'); + echo $this->buffer; + break; + case 'F': + //Save to local file + $f=fopen($name,'wb'); + if(!$f) + $this->Error('Unable to create output file: '.$name); + fwrite($f,$this->buffer,strlen($this->buffer)); + fclose($f); + break; + case 'S': + //Return as a string + return $this->buffer; + default: + $this->Error('Incorrect output destination: '.$dest); + } + return ''; +} + +/******************************************************************************* +* * +* Protected methods * +* * +*******************************************************************************/ +function _dochecks() +{ + //Check for locale-related bug + if(1.1==1) + $this->Error('Don\'t alter the locale before including class file'); + //Check for decimal separator + if(sprintf('%.1f',1.0)!='1.0') + setlocale(LC_NUMERIC,'C'); +} + +function _begindoc() +{ + //Start document + $this->state=1; + $this->_out('%PDF-1.3'); +} + +function _strreplace($what, $to, $where) { + return str_replace($what, $to, $where); +} + +function _putpages() +{ + $nb=$this->page; + if(!empty($this->AliasNbPages)) + { + //Replace number of pages + for($n=1;$n<=$nb;$n++) + $this->pages[$n]=$this->_strreplace($this->AliasNbPages,$nb,$this->pages[$n]); + } + if($this->DefOrientation=='P') + { + $wPt=$this->fwPt; + $hPt=$this->fhPt; + } + else + { + $wPt=$this->fhPt; + $hPt=$this->fwPt; + } + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + for($n=1;$n<=$nb;$n++) + { + //Page + $this->_newobj(); + $this->_out('<_out('/Parent 1 0 R'); + if(isset($this->OrientationChanges[$n])) + $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt)); + $this->_out('/Resources 2 0 R'); + if(isset($this->PageLinks[$n])) + { + //Links + $annots='/Annots ['; + foreach($this->PageLinks[$n] as $pl) + { + $rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]); + $annots.='<_textstring($pl[4]).'>>>>'; + else + { + $l=$this->links[$pl[4]]; + $h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt; + $annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k); + } + } + $this->_out($annots.']'); + } + $this->_out('/Contents '.($this->n+1).' 0 R>>'); + $this->_out('endobj'); + //Page content + $p=($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n]; + $this->_newobj(); + $this->_out('<<'.$filter.'/Length '.strlen($p).'>>'); + $this->_putstream($p); + $this->_out('endobj'); + } + //Pages root + $this->offsets[1]=strlen($this->buffer); + $this->_out('1 0 obj'); + $this->_out('<_out($kids.']'); + $this->_out('/Count '.$nb); + $this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt)); + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putfonts() +{ + $nf=$this->n; + foreach($this->diffs as $diff) + { + //Encodings + $this->_newobj(); + $this->_out('<>'); + $this->_out('endobj'); + } + $mqr=get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + foreach($this->FontFiles as $file=>$info) + { + //Font file embedding + $this->_newobj(); + $this->FontFiles[$file]['n']=$this->n; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + $size=filesize($file); + if(!$size) + $this->Error('Font file not found'); + $this->_out('<_out('/Filter /FlateDecode'); + $this->_out('/Length1 '.$info['length1']); + if(isset($info['length2'])) + $this->_out('/Length2 '.$info['length2'].' /Length3 0'); + $this->_out('>>'); + $f=fopen($file,'rb'); + $this->_putstream(fread($f,$size)); + fclose($f); + $this->_out('endobj'); + } + set_magic_quotes_runtime($mqr); + foreach($this->fonts as $k=>$font) + { + //Font objects + $this->fonts[$k]['n']=$this->n+1; + $type=$font['type']; + $name=$font['name']; + if($type=='core') + { + //Standard font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /Type1'); + if($name!='Symbol' and $name!='ZapfDingbats') + $this->_out('/Encoding /WinAnsiEncoding'); + $this->_out('>>'); + $this->_out('endobj'); + } + elseif($type=='Type1' or $type=='TrueType') + { + //Additional Type1 or TrueType font + $this->_newobj(); + $this->_out('<_out('/BaseFont /'.$name); + $this->_out('/Subtype /'.$type); + $this->_out('/FirstChar 32 /LastChar 255'); + $this->_out('/Widths '.($this->n+1).' 0 R'); + $this->_out('/FontDescriptor '.($this->n+2).' 0 R'); + if($font['enc']) + { + if(isset($font['diff'])) + $this->_out('/Encoding '.($nf+$font['diff']).' 0 R'); + else + $this->_out('/Encoding /WinAnsiEncoding'); + } + $this->_out('>>'); + $this->_out('endobj'); + //Widths + $this->_newobj(); + $cw=&$font['cw']; + $s='['; + for($i=32;$i<=255;$i++) + $s.=$cw[chr($i)].' '; + $this->_out($s.']'); + $this->_out('endobj'); + //Descriptor + $this->_newobj(); + $s='<$v) + $s.=' /'.$k.' '.$v; + $file=$font['file']; + if($file) + $s.=' /FontFile'.($type=='Type1' ? '' : '2').' '.$this->FontFiles[$file]['n'].' 0 R'; + $this->_out($s.'>>'); + $this->_out('endobj'); + } + else + { + //Allow for additional types + $mtd='_put'.strtolower($type); + if(!method_exists($this,$mtd)) + $this->Error('Unsupported font type: '.$type); + $this->$mtd($font); + } + } +} + +function _putimages() +{ + $filter=($this->compress) ? '/Filter /FlateDecode ' : ''; + reset($this->images); + while(list($file,$info)=each($this->images)) + { + $this->_newobj(); + $this->images[$file]['n']=$this->n; + $this->_out('<_out('/Subtype /Image'); + $this->_out('/Width '.$info['w']); + $this->_out('/Height '.$info['h']); + if($info['cs']=='Indexed') + $this->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->n+1).' 0 R]'); + else + { + $this->_out('/ColorSpace /'.$info['cs']); + if($info['cs']=='DeviceCMYK') + $this->_out('/Decode [1 0 1 0 1 0 1 0]'); + } + $this->_out('/BitsPerComponent '.$info['bpc']); + $this->_out('/Filter /'.$info['f']); + if(isset($info['parms'])) + $this->_out($info['parms']); + if(isset($info['trns']) and is_array($info['trns'])) + { + $trns=''; + for($i=0;$i_out('/Mask ['.$trns.']'); + } + $this->_out('/Length '.strlen($info['data']).'>>'); + $this->_putstream($info['data']); + unset($this->images[$file]['data']); + $this->_out('endobj'); + //Palette + if($info['cs']=='Indexed') + { + $this->_newobj(); + $pal=($this->compress) ? gzcompress($info['pal']) : $info['pal']; + $this->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); + $this->_putstream($pal); + $this->_out('endobj'); + } + } +} + +function _putresources() +{ + $this->_putfonts(); + $this->_putimages(); + //Resource dictionary + $this->offsets[2]=strlen($this->buffer); + $this->_out('2 0 obj'); + $this->_out('<_out('/Font <<'); + foreach($this->fonts as $font) + $this->_out('/F'.$font['i'].' '.$font['n'].' 0 R'); + $this->_out('>>'); + if(count($this->images)) + { + $this->_out('/XObject <<'); + foreach($this->images as $image) + $this->_out('/I'.$image['i'].' '.$image['n'].' 0 R'); + $this->_out('>>'); + } + $this->_out('>>'); + $this->_out('endobj'); +} + +function _putinfo() +{ + $this->_out('/Producer '.$this->_textstring('FPDF '.FPDF_VERSION)); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis'))); +} + +function _putcatalog() +{ + $this->_out('/Type /Catalog'); + $this->_out('/Pages 1 0 R'); + if($this->ZoomMode=='fullpage') + $this->_out('/OpenAction [3 0 R /Fit]'); + elseif($this->ZoomMode=='fullwidth') + $this->_out('/OpenAction [3 0 R /FitH null]'); + elseif($this->ZoomMode=='real') + $this->_out('/OpenAction [3 0 R /XYZ null null 1]'); + elseif(!is_string($this->ZoomMode)) + $this->_out('/OpenAction [3 0 R /XYZ null null '.($this->ZoomMode/100).']'); + if($this->LayoutMode=='single') + $this->_out('/PageLayout /SinglePage'); + elseif($this->LayoutMode=='continuous') + $this->_out('/PageLayout /OneColumn'); + elseif($this->LayoutMode=='two') + $this->_out('/PageLayout /TwoColumnLeft'); +} + +function _puttrailer() +{ + $this->_out('/Size '.($this->n+1)); + $this->_out('/Root '.$this->n.' 0 R'); + $this->_out('/Info '.($this->n-1).' 0 R'); +} + +function _enddoc() +{ + $this->_putpages(); + $this->_putresources(); + //Info + $this->_newobj(); + $this->_out('<<'); + $this->_putinfo(); + $this->_out('>>'); + $this->_out('endobj'); + //Catalog + $this->_newobj(); + $this->_out('<<'); + $this->_putcatalog(); + $this->_out('>>'); + $this->_out('endobj'); + //Cross-ref + $o=strlen($this->buffer); + $this->_out('xref'); + $this->_out('0 '.($this->n+1)); + $this->_out('0000000000 65535 f '); + for($i=1;$i<=$this->n;$i++) + $this->_out(sprintf('%010d 00000 n ',$this->offsets[$i])); + //Trailer + $this->_out('trailer'); + $this->_out('<<'); + $this->_puttrailer(); + $this->_out('>>'); + $this->_out('startxref'); + $this->_out($o); + $this->_out('%%EOF'); + $this->state=3; +} + +function _beginpage($orientation) +{ + $this->page++; + $this->pages[$this->page]=''; + $this->state=2; + $this->x=$this->lMargin; + $this->y=$this->tMargin; + $this->FontFamily=''; + //Page orientation + if(!$orientation) + $orientation=$this->DefOrientation; + else + { + $orientation=strtoupper($orientation{0}); + if($orientation!=$this->DefOrientation) + $this->OrientationChanges[$this->page]=true; + } + if($orientation!=$this->CurOrientation) + { + //Change orientation + if($orientation=='P') + { + $this->wPt=$this->fwPt; + $this->hPt=$this->fhPt; + $this->w=$this->fw; + $this->h=$this->fh; + } + else + { + $this->wPt=$this->fhPt; + $this->hPt=$this->fwPt; + $this->w=$this->fh; + $this->h=$this->fw; + } + $this->PageBreakTrigger=$this->h-$this->bMargin; + $this->CurOrientation=$orientation; + } +} + +function _endpage() +{ + //End of page contents + $this->state=1; +} + +function _newobj() +{ + //Begin a new object + $this->n++; + $this->offsets[$this->n]=strlen($this->buffer); + $this->_out($this->n.' 0 obj'); +} + +function _dounderline($x,$y,$txt) +{ + //Underline text + $up=$this->CurrentFont['up']; + $ut=$this->CurrentFont['ut']; + $w=$this->GetStringWidth($txt)+$this->ws*substr_count($txt,' '); + return sprintf('%.2f %.2f %.2f %.2f re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); +} + +function _parsejpg($file) +{ + //Extract info from a JPEG file + $a=GetImageSize($file); + if(!$a) + $this->Error('Missing or incorrect image file: '.$file); + if($a[2]!=2) + $this->Error('Not a JPEG file: '.$file); + if(!isset($a['channels']) or $a['channels']==3) + $colspace='DeviceRGB'; + elseif($a['channels']==4) + $colspace='DeviceCMYK'; + else + $colspace='DeviceGray'; + $bpc=isset($a['bits']) ? $a['bits'] : 8; + //Read whole file + $f=fopen($file,'rb'); + $data=''; + while(!feof($f)) + $data.=fread($f,4096); + fclose($f); + return array('w'=>$a[0],'h'=>$a[1],'cs'=>$colspace,'bpc'=>$bpc,'f'=>'DCTDecode','data'=>$data); +} + +function _parsepng($file) +{ + //Extract info from a PNG file + $f=fopen($file,'rb'); + if(!$f) + $this->Error('Can\'t open image file: '.$file); + //Check signature + if(fread($f,8)!=chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) + $this->Error('Not a PNG file: '.$file); + //Read header chunk + fread($f,4); + if(fread($f,4)!='IHDR') + $this->Error('Incorrect PNG file: '.$file); + $w=$this->_freadint($f); + $h=$this->_freadint($f); + $bpc=ord(fread($f,1)); + if($bpc>8) + $this->Error('16-bit depth not supported: '.$file); + $ct=ord(fread($f,1)); + if($ct==0) + $colspace='DeviceGray'; + elseif($ct==2) + $colspace='DeviceRGB'; + elseif($ct==3) + $colspace='Indexed'; + else + $this->Error('Alpha channel not supported: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Unknown compression method: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Unknown filter method: '.$file); + if(ord(fread($f,1))!=0) + $this->Error('Interlacing not supported: '.$file); + fread($f,4); + $parms='/DecodeParms <>'; + //Scan chunks looking for palette, transparency and image data + $pal=''; + $trns=''; + $data=''; + do + { + $n=$this->_freadint($f); + $type=fread($f,4); + if($type=='PLTE') + { + //Read palette + $pal=fread($f,$n); + fread($f,4); + } + elseif($type=='tRNS') + { + //Read transparency info + $t=fread($f,$n); + if($ct==0) + $trns=array(ord(substr($t,1,1))); + elseif($ct==2) + $trns=array(ord(substr($t,1,1)),ord(substr($t,3,1)),ord(substr($t,5,1))); + else + { + $pos=strpos($t,chr(0)); + if(is_int($pos)) + $trns=array($pos); + } + fread($f,4); + } + elseif($type=='IDAT') + { + //Read image data block + $data.=fread($f,$n); + fread($f,4); + } + elseif($type=='IEND') + break; + else + fread($f,$n+4); + } + while($n); + if($colspace=='Indexed' and empty($pal)) + $this->Error('Missing palette in '.$file); + fclose($f); + return array('w'=>$w,'h'=>$h,'cs'=>$colspace,'bpc'=>$bpc,'f'=>'FlateDecode','parms'=>$parms,'pal'=>$pal,'trns'=>$trns,'data'=>$data); +} + +function _freadint($f) +{ + //Read a 4-byte integer from file + $i=ord(fread($f,1))<<24; + $i+=ord(fread($f,1))<<16; + $i+=ord(fread($f,1))<<8; + $i+=ord(fread($f,1)); + return $i; +} + +function _textstring($s) +{ + //Format a text string + return '('.$this->_escape($s).')'; +} + +function _escape($s) +{ + //Add \ before \, ( and ) + return str_replace(')','\\)',str_replace('(','\\(',str_replace('\\','\\\\',$s))); +} + +function _putstream($s) +{ + $this->_out('stream'); + $this->_out($s); + $this->_out('endstream'); +} + +function _out($s) +{ + //Add a line to the document + if($this->state==2) + $this->pages[$this->page].=$s."\n"; + else + $this->buffer.=$s."\n"; +} +//End of class +} + +//Handle special IE contype request +// lem9 +//if(isset($HTTP_SERVER_VARS['HTTP_USER_AGENT']) and $HTTP_SERVER_VARS['HTTP_USER_AGENT']=='contype') +if(isset($_SERVER['HTTP_USER_AGENT']) and $_SERVER['HTTP_USER_AGENT']=='contype') +{ + Header('Content-Type: application/pdf'); + exit; +} + +} ?> diff --git a/libraries/fpdf/ufpdf.php b/libraries/fpdf/ufpdf.php index d01220409..a6fff165e 100644 --- a/libraries/fpdf/ufpdf.php +++ b/libraries/fpdf/ufpdf.php @@ -1,592 +1,483 @@ * - * - * License: GPL * - * - * - * - * UFPDF is a modification of FPDF to support Unicode through UTF-8. * - */ - -if (!class_exists('UFPDF')) { - define('UFPDF_VERSION', '0.1'); - - include_once './libraries/fpdf/fpdf.php'; - - class UFPDF extends FPDF { - /** - * Public methods * - */ - - function UFPDF($orientation = 'P', $unit = 'mm', $format = 'A4') - { - FPDF::FPDF($orientation, $unit, $format); - } - - function GetStringWidth($s) - { - // Get width of a string in the current font - $s = (string)$s; - $codepoints = $this->utf8_to_codepoints($s); - $cw = &$this->CurrentFont['cw']; - $w = 0; - - foreach ($codepoints as $cp) { - $w += isset($cw[$cp])?$cw[$cp]:0; - } - - return $w * $this->FontSize / 1000; - } - - function AddFont($family, $style = '', $file = '') - { - // Add a TrueType or Type1 font - $family = strtolower($family); - - if ($family == 'arial') { - $family = 'helvetica'; - } - - $style = strtoupper($style); - - if ($style == 'IB') { - $style = 'BI'; - } - - if (isset($this->fonts[$family . $style])) { - $this->Error('Font already added: ' . $family . ' ' . $style); - } - - if ($file == '') { - $file = str_replace(' ', '', $family) . strtolower($style) . '.php'; - } - - if (defined('FPDF_FONTPATH')) { - $file = FPDF_FONTPATH . $file; - } - - include($file); - - if (!isset($name)) { - $this->Error('Could not include font definition file'); - } - - $i = count($this->fonts) + 1; - $this->fonts[$family . $style] = array('i' => $i, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'file' => $file, 'ctg' => $ctg); - - if ($file) { - if ($type == 'TrueTypeUnicode') { - $this->FontFiles[$file] = array('length1' => $originalsize); - } else { - $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2); - } - } - } - - function Text($x, $y, $txt) - { - // Output a string - $s = sprintf('BT %.2f %.2f Td %s Tj ET', $x * $this->k, ($this->h - $y) * $this->k, $this->_escapetext($txt)); - - if ($this->underline and $txt != '') { - $s .= ' ' . $this->_dounderline($x, $y, $this->GetStringWidth($txt), $txt); - } - - if ($this->ColorFlag) { - $s = 'q ' . $this->TextColor . ' ' . $s . ' Q'; - } - - $this->_out($s); - } - - function AcceptPageBreak() - { - // Accept automatic page break or not - return $this->AutoPageBreak; - } - - function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '') - { - // Output a cell - $k = $this->k; - - if ($this->y + $h > $this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) { - // Automatic page break - $x = $this->x; - $ws = $this->ws; - - if ($ws > 0) { - $this->ws = 0; - $this->_out('0 Tw'); - } - - $this->AddPage($this->CurOrientation); - $this->x = $x; - - if ($ws > 0) { - $this->ws = $ws; - $this->_out(sprintf('%.3f Tw', $ws * $k)); - } - } - - if ($w == 0) { - $w = $this->w - $this->rMargin - $this->x; - } - - $s = ''; - - if ($fill == 1 or $border == 1) { - if ($fill == 1) { - $op = ($border == 1) ? 'B' : 'f'; - } else { - $op = 'S'; - } - - $s = sprintf('%.2f %.2f %.2f %.2f re %s ', $this->x * $k, ($this->h - $this->y) * $k, $w * $k, - $h * $k, $op); - } - - if (is_string($border)) { - $x = $this->x; - $y = $this->y; - - if (is_int(strpos($border, 'L'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - $y) * $k, $x * $k, ($this->h - ($y + $h)) * $k); - } - - if (is_int(strpos($border, 'T'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - $y) * $k); - } - - if (is_int(strpos($border, 'R'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', ($x + $w) * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); - } - - if (is_int(strpos($border, 'B'))) { - $s .= sprintf('%.2f %.2f m %.2f %.2f l S ', $x * $k, ($this->h - ($y + $h)) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k); - } - } - - if ($txt != '') { - $width = $this->GetStringWidth($txt); - - if ($align == 'R') { - $dx = $w - $this->cMargin - $width; - } elseif ($align == 'C') { - $dx = ($w - $width) / 2; - } else { - $dx = $this->cMargin; - } - - if ($this->ColorFlag) { - $s .= 'q ' . $this->TextColor . ' '; - } - - $txtstring = $this->_escapetext($txt); - $s .= sprintf('BT %.2f %.2f Td %s Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $h + .3 * $this->FontSize)) * $k, $txtstring); - - if ($this->underline) { - $s .= ' ' . $this->_dounderline($this->x + $dx, $this->y + .5 * $h + .3 * $this->FontSize, $width, $txt); - } - - if ($this->ColorFlag) { - $s .= ' Q'; - } - - if ($link) { - $this->Link($this->x + $dx, $this->y + .5 * $h - .5 * $this->FontSize, $width, $this->FontSize, $link); - } - } - - if ($s) { - $this->_out($s); - } - - $this->lasth = $h; - - if ($ln > 0) { - // Go to next line - $this->y += $h; - - if ($ln == 1) { - $this->x = $this->lMargin; - } - } else { - $this->x += $w; - } - } - - /** - * Protected methods * - */ - - function _puttruetypeunicode($font) - { - // Type0 Font - $this->_newobj(); - $this->_out('<_out('/Subtype /Type0'); - $this->_out('/BaseFont /' . $font['name'] . '-UCS'); - $this->_out('/Encoding /Identity-H'); - $this->_out('/DescendantFonts [' . ($this->n + 1) . ' 0 R]'); - $this->_out('>>'); - $this->_out('endobj'); - // CIDFont - $this->_newobj(); - $this->_out('<_out('/Subtype /CIDFontType2'); - $this->_out('/BaseFont /' . $font['name']); - $this->_out('/CIDSystemInfo <>'); - $this->_out('/FontDescriptor ' . ($this->n + 1) . ' 0 R'); - $c = 0; - $widths = ''; - - foreach ($font['cw'] as $i => $w) { - $widths .= $i . ' [' . $w . '] '; - } - - $this->_out('/W [' . $widths . ']'); - $this->_out('/CIDToGIDMap ' . ($this->n + 2) . ' 0 R'); - $this->_out('>>'); - $this->_out('endobj'); - // Font descriptor - $this->_newobj(); - $this->_out('<_out('/FontName /' . $font['name']); - $s = ''; - - foreach ($font['desc'] as $k => $v) { - $s .= ' /' . $k . ' ' . $v; - } - - if ($font['file']) { - $s .= ' /FontFile2 ' . $this->FontFiles[$font['file']]['n'] . ' 0 R'; - } - - $this->_out($s); - $this->_out('>>'); - $this->_out('endobj'); - // Embed CIDToGIDMap - $this->_newobj(); - - if (defined('FPDF_FONTPATH')) { - $file = FPDF_FONTPATH . $font['ctg']; - } else { - $file = $font['ctg']; - } - - $size = filesize($file); - - if (!$size) { - $this->Error('Font file not found'); - } - - $this->_out('<_out('/Filter /FlateDecode'); - } - - $this->_out('>>'); - $f = fopen($file, 'rb'); - $this->_putstream(fread($f, $size)); - fclose($f); - $this->_out('endobj'); - } - - function _dounderline($x, $y, $width, $txt) - { - // Underline text - $up = $this->CurrentFont['up']; - $ut = $this->CurrentFont['ut']; - $w = $width + $this->ws * substr_count($txt, ' '); - return sprintf('%.2f %.2f %.2f %.2f re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, - $ut / 1000 * $this->FontSizePt); - } - - function _textstring($s) - { - // Convert to UTF-16BE - $s = $this->utf8_to_utf16be($s); - // Escape necessary characters - return '(' . strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\')) . ')'; - } - - function _strreplace($what, $to, $where) - { - $to = '' . $to; - return str_replace($this->utf8_to_utf16be($what, false), $this->utf8_to_utf16be($to, false), $where); - } - - function _escapetext($s) - { - // Convert to UTF-16BE - $s = $this->utf8_to_utf16be($s, false); - // Escape necessary characters - return '(' . strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\')) . ')'; - } - - function _putinfo() - { - $this->_out('/Producer ' . $this->_textstring('UFPDF ' . UFPDF_VERSION)); - - if (!empty($this->title)) { - $this->_out('/Title ' . $this->_textstring($this->title)); - } - - if (!empty($this->subject)) { - $this->_out('/Subject ' . $this->_textstring($this->subject)); - } - - if (!empty($this->author)) { - $this->_out('/Author ' . $this->_textstring($this->author)); - } - - if (!empty($this->keywords)) { - $this->_out('/Keywords ' . $this->_textstring($this->keywords)); - } - - if (!empty($this->creator)) { - $this->_out('/Creator ' . $this->_textstring($this->creator)); - } - - $this->_out('/CreationDate ' . $this->_textstring('D:' . date('YmdHis'))); - } - // UTF-8 to UTF-16BE conversion. - // Correctly handles all illegal UTF-8 sequences. - function utf8_to_utf16be(&$txt, $bom = true) - { - $l = strlen($txt); - $out = $bom ? "\xFE\xFF" : ''; - - for ($i = 0; $i < $l; ++$i) { - $c = ord($txt{$i}); - // ASCII - if ($c < 0x80) { - $out .= "\x00" . $txt{$i}; - } - // Lost continuation byte - elseif ($c < 0xC0) { - $out .= "\xFF\xFD"; - - continue; - } - // Multibyte sequence leading byte - else { - if ($c < 0xE0) { - $s = 2; - } elseif ($c < 0xF0) { - $s = 3; - } elseif ($c < 0xF8) { - $s = 4; - } - // 5/6 byte sequences not possible for Unicode. - else { - $out .= "\xFF\xFD"; - - while (ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { - ++$i; - } - - continue; - } - - $q = array($c); - // Fetch rest of sequence - $l = strlen($txt); - - while ($i + 1 < $l && ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { - ++$i; - $q[] = ord($txt{$i}); - } - // Check length - if (count($q) != $s) { - $out .= "\xFF\xFD"; - - continue; - } - - switch ($s) { - case 2: - - $cp = (($q[0] ^ 0xC0) << 6) | ($q[1] ^ 0x80); - // Overlong sequence - if ($cp < 0x80) { - $out .= "\xFF\xFD"; - } else { - $out .= chr($cp >> 8); - - $out .= chr($cp &0xFF); - } - - continue; - - case 3: - - $cp = (($q[0] ^ 0xE0) << 12) | (($q[1] ^ 0x80) << 6) | ($q[2] ^ 0x80); - // Overlong sequence - if ($cp < 0x800) { - $out .= "\xFF\xFD"; - } - // Check for UTF-8 encoded surrogates (caused by a bad UTF-8 encoder) - elseif ($c > 0xD800 && $c < 0xDFFF) { - $out .= "\xFF\xFD"; - } else { - $out .= chr($cp >> 8); - - $out .= chr($cp &0xFF); - } - - continue; - - case 4: - - $cp = (($q[0] ^ 0xF0) << 18) | (($q[1] ^ 0x80) << 12) | (($q[2] ^ 0x80) << 6) | ($q[3] ^ 0x80); - // Overlong sequence - if ($cp < 0x10000) { - $out .= "\xFF\xFD"; - } - // Outside of the Unicode range - elseif ($cp >= 0x10FFFF) { - $out .= "\xFF\xFD"; - } else { - // Use surrogates - $cp -= 0x10000; - - $s1 = 0xD800 | ($cp >> 10); - - $s2 = 0xDC00 | ($cp &0x3FF); - - $out .= chr($s1 >> 8); - - $out .= chr($s1 &0xFF); - - $out .= chr($s2 >> 8); - - $out .= chr($s2 &0xFF); - } - - continue; - } - } - } - - return $out; - } - // UTF-8 to codepoint array conversion. - // Correctly handles all illegal UTF-8 sequences. - function utf8_to_codepoints(&$txt) - { - $l = strlen($txt); - $out = array(); - - for ($i = 0; $i < $l; ++$i) { - $c = ord($txt{$i}); - // ASCII - if ($c < 0x80) { - $out[] = ord($txt{$i}); - } - // Lost continuation byte - elseif ($c < 0xC0) { - $out[] = 0xFFFD; - - continue; - } - // Multibyte sequence leading byte - else { - if ($c < 0xE0) { - $s = 2; - } elseif ($c < 0xF0) { - $s = 3; - } elseif ($c < 0xF8) { - $s = 4; - } - // 5/6 byte sequences not possible for Unicode. - else { - $out[] = 0xFFFD; - - while (ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { - ++$i; - } - - continue; - } - - $q = array($c); - // Fetch rest of sequence - $l = strlen($txt); - - while ($i + 1 < $l && ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { - ++$i; - $q[] = ord($txt{$i}); - } - // Check length - if (count($q) != $s) { - $out[] = 0xFFFD; - - continue; - } - - switch ($s) { - case 2: - - $cp = (($q[0] ^ 0xC0) << 6) | ($q[1] ^ 0x80); - // Overlong sequence - if ($cp < 0x80) { - $out[] = 0xFFFD; - } else { - $out[] = $cp; - } - - continue; - - case 3: - - $cp = (($q[0] ^ 0xE0) << 12) | (($q[1] ^ 0x80) << 6) | ($q[2] ^ 0x80); - // Overlong sequence - if ($cp < 0x800) { - $out[] = 0xFFFD; - } - // Check for UTF-8 encoded surrogates (caused by a bad UTF-8 encoder) - elseif ($c > 0xD800 && $c < 0xDFFF) { - $out[] = 0xFFFD; - } else { - $out[] = $cp; - } - - continue; - - case 4: - - $cp = (($q[0] ^ 0xF0) << 18) | (($q[1] ^ 0x80) << 12) | (($q[2] ^ 0x80) << 6) | ($q[3] ^ 0x80); - // Overlong sequence - if ($cp < 0x10000) { - $out[] = 0xFFFD; - } - // Outside of the Unicode range - elseif ($cp >= 0x10FFFF) { - $out[] = 0xFFFD; - } else { - $out[] = $cp; - } - - continue; - } - } - } - - return $out; - } - // End of class - } -} - +/******************************************************************************* +* Software: UFPDF, Unicode Free PDF generator * +* Version: 0.1 * +* based on FPDF 1.52 by Olivier PLATHEY * +* Date: 2004-09-01 * +* Author: Steven Wittens * +* License: GPL * +* * +* UFPDF is a modification of FPDF to support Unicode through UTF-8. * +* * +*******************************************************************************/ + +if(!class_exists('UFPDF')) +{ +define('UFPDF_VERSION','0.1'); + +include_once './libraries/fpdf/fpdf.php'; + +class UFPDF extends FPDF +{ + +/******************************************************************************* +* * +* Public methods * +* * +*******************************************************************************/ +function UFPDF($orientation='P',$unit='mm',$format='A4') +{ + FPDF::FPDF($orientation, $unit, $format); +} + +function GetStringWidth($s) +{ + //Get width of a string in the current font + $s = (string)$s; + $codepoints=$this->utf8_to_codepoints($s); + $cw=&$this->CurrentFont['cw']; + $w=0; + foreach($codepoints as $cp) + $w+=isset($cw[$cp])?$cw[$cp]:0; + return $w*$this->FontSize/1000; +} + +function AddFont($family,$style='',$file='') +{ + //Add a TrueType or Type1 font + $family=strtolower($family); + if($family=='arial') + $family='helvetica'; + $style=strtoupper($style); + if($style=='IB') + $style='BI'; + if(isset($this->fonts[$family.$style])) + $this->Error('Font already added: '.$family.' '.$style); + if($file=='') + $file=str_replace(' ','',$family).strtolower($style).'.php'; + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$file; + include($file); + if(!isset($name)) + $this->Error('Could not include font definition file'); + $i=count($this->fonts)+1; + $this->fonts[$family.$style]=array('i'=>$i,'type'=>$type,'name'=>$name,'desc'=>$desc,'up'=>$up,'ut'=>$ut,'cw'=>$cw,'file'=>$file,'ctg'=>$ctg); + if($file) + { + if($type=='TrueTypeUnicode') + $this->FontFiles[$file]=array('length1'=>$originalsize); + else + $this->FontFiles[$file]=array('length1'=>$size1,'length2'=>$size2); + } +} + +function Text($x,$y,$txt) +{ + //Output a string + $s=sprintf('BT %.2f %.2f Td %s Tj ET',$x*$this->k,($this->h-$y)*$this->k,$this->_escapetext($txt)); + if($this->underline and $txt!='') + $s.=' '.$this->_dounderline($x,$y,$this->GetStringWidth($txt),$txt); + if($this->ColorFlag) + $s='q '.$this->TextColor.' '.$s.' Q'; + $this->_out($s); +} + +function AcceptPageBreak() +{ + //Accept automatic page break or not + return $this->AutoPageBreak; +} + +function Cell($w,$h=0,$txt='',$border=0,$ln=0,$align='',$fill=0,$link='') +{ + //Output a cell + $k=$this->k; + if($this->y+$h>$this->PageBreakTrigger and !$this->InFooter and $this->AcceptPageBreak()) + { + //Automatic page break + $x=$this->x; + $ws=$this->ws; + if($ws>0) + { + $this->ws=0; + $this->_out('0 Tw'); + } + $this->AddPage($this->CurOrientation); + $this->x=$x; + if($ws>0) + { + $this->ws=$ws; + $this->_out(sprintf('%.3f Tw',$ws*$k)); + } + } + if($w==0) + $w=$this->w-$this->rMargin-$this->x; + $s=''; + if($fill==1 or $border==1) + { + if($fill==1) + $op=($border==1) ? 'B' : 'f'; + else + $op='S'; + $s=sprintf('%.2f %.2f %.2f %.2f re %s ',$this->x*$k,($this->h-$this->y)*$k,$w*$k,-$h*$k,$op); + } + if(is_string($border)) + { + $x=$this->x; + $y=$this->y; + if(is_int(strpos($border,'L'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,$x*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'T'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-$y)*$k); + if(is_int(strpos($border,'R'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',($x+$w)*$k,($this->h-$y)*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + if(is_int(strpos($border,'B'))) + $s.=sprintf('%.2f %.2f m %.2f %.2f l S ',$x*$k,($this->h-($y+$h))*$k,($x+$w)*$k,($this->h-($y+$h))*$k); + } + if($txt!='') + { + $width = $this->GetStringWidth($txt); + if($align=='R') + $dx=$w-$this->cMargin-$width; + elseif($align=='C') + $dx=($w-$width)/2; + else + $dx=$this->cMargin; + if($this->ColorFlag) + $s.='q '.$this->TextColor.' '; + $txtstring=$this->_escapetext($txt); + $s.=sprintf('BT %.2f %.2f Td %s Tj ET',($this->x+$dx)*$k,($this->h-($this->y+.5*$h+.3*$this->FontSize))*$k,$txtstring); + if($this->underline) + $s.=' '.$this->_dounderline($this->x+$dx,$this->y+.5*$h+.3*$this->FontSize,$width,$txt); + if($this->ColorFlag) + $s.=' Q'; + if($link) + $this->Link($this->x+$dx,$this->y+.5*$h-.5*$this->FontSize,$width,$this->FontSize,$link); + } + if($s) + $this->_out($s); + $this->lasth=$h; + if($ln>0) + { + //Go to next line + $this->y+=$h; + if($ln==1) + $this->x=$this->lMargin; + } + else + $this->x+=$w; +} + +/******************************************************************************* +* * +* Protected methods * +* * +*******************************************************************************/ + +function _puttruetypeunicode($font) { + //Type0 Font + $this->_newobj(); + $this->_out('<_out('/Subtype /Type0'); + $this->_out('/BaseFont /'. $font['name'] .'-UCS'); + $this->_out('/Encoding /Identity-H'); + $this->_out('/DescendantFonts ['. ($this->n + 1) .' 0 R]'); + $this->_out('>>'); + $this->_out('endobj'); + + //CIDFont + $this->_newobj(); + $this->_out('<_out('/Subtype /CIDFontType2'); + $this->_out('/BaseFont /'. $font['name']); + $this->_out('/CIDSystemInfo <>'); + $this->_out('/FontDescriptor '. ($this->n + 1) .' 0 R'); + $c = 0; + $widths = ''; + foreach ($font['cw'] as $i => $w) { + $widths .= $i .' ['. $w.'] '; + } + $this->_out('/W ['. $widths .']'); + $this->_out('/CIDToGIDMap '. ($this->n + 2) .' 0 R'); + $this->_out('>>'); + $this->_out('endobj'); + + //Font descriptor + $this->_newobj(); + $this->_out('<_out('/FontName /'.$font['name']); + $s = ''; + foreach ($font['desc'] as $k => $v) { + $s .= ' /'. $k .' '. $v; + } + if ($font['file']) { + $s .= ' /FontFile2 '. $this->FontFiles[$font['file']]['n'] .' 0 R'; + } + $this->_out($s); + $this->_out('>>'); + $this->_out('endobj'); + + //Embed CIDToGIDMap + $this->_newobj(); + if(defined('FPDF_FONTPATH')) + $file=FPDF_FONTPATH.$font['ctg']; + else + $file=$font['ctg']; + $size=filesize($file); + if(!$size) + $this->Error('Font file not found'); + $this->_out('<_out('/Filter /FlateDecode'); + $this->_out('>>'); + $f = fopen($file,'rb'); + $this->_putstream(fread($f,$size)); + fclose($f); + $this->_out('endobj'); +} + +function _dounderline($x,$y,$width,$txt) +{ + //Underline text + $up=$this->CurrentFont['up']; + $ut=$this->CurrentFont['ut']; + $w=$width+$this->ws*substr_count($txt,' '); + return sprintf('%.2f %.2f %.2f %.2f re f',$x*$this->k,($this->h-($y-$up/1000*$this->FontSize))*$this->k,$w*$this->k,-$ut/1000*$this->FontSizePt); +} + +function _textstring($s) +{ + //Convert to UTF-16BE + $s = $this->utf8_to_utf16be($s); + //Escape necessary characters + return '('. strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\')) .')'; +} + +function _strreplace($what, $to, $where) { + $to = '' . $to; + return str_replace($this->utf8_to_utf16be($what, false), $this->utf8_to_utf16be($to, false), $where); +} + +function _escapetext($s) +{ + //Convert to UTF-16BE + $s = $this->utf8_to_utf16be($s, false); + //Escape necessary characters + return '('. strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\')) .')'; +} + +function _putinfo() +{ + $this->_out('/Producer '.$this->_textstring('UFPDF '. UFPDF_VERSION)); + if(!empty($this->title)) + $this->_out('/Title '.$this->_textstring($this->title)); + if(!empty($this->subject)) + $this->_out('/Subject '.$this->_textstring($this->subject)); + if(!empty($this->author)) + $this->_out('/Author '.$this->_textstring($this->author)); + if(!empty($this->keywords)) + $this->_out('/Keywords '.$this->_textstring($this->keywords)); + if(!empty($this->creator)) + $this->_out('/Creator '.$this->_textstring($this->creator)); + $this->_out('/CreationDate '.$this->_textstring('D:'.date('YmdHis'))); +} + +// UTF-8 to UTF-16BE conversion. +// Correctly handles all illegal UTF-8 sequences. +function utf8_to_utf16be(&$txt, $bom = true) { + $l = strlen($txt); + $out = $bom ? "\xFE\xFF" : ''; + for ($i = 0; $i < $l; ++$i) { + $c = ord($txt{$i}); + // ASCII + if ($c < 0x80) { + $out .= "\x00". $txt{$i}; + } + // Lost continuation byte + else if ($c < 0xC0) { + $out .= "\xFF\xFD"; + continue; + } + // Multibyte sequence leading byte + else { + if ($c < 0xE0) { + $s = 2; + } + else if ($c < 0xF0) { + $s = 3; + } + else if ($c < 0xF8) { + $s = 4; + } + // 5/6 byte sequences not possible for Unicode. + else { + $out .= "\xFF\xFD"; + while (ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; } + continue; + } + + $q = array($c); + // Fetch rest of sequence + $l = strlen($txt); + while ($i + 1 < $l && ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; $q[] = ord($txt{$i}); } + + // Check length + if (count($q) != $s) { + $out .= "\xFF\xFD"; + continue; + } + + switch ($s) { + case 2: + $cp = (($q[0] ^ 0xC0) << 6) | ($q[1] ^ 0x80); + // Overlong sequence + if ($cp < 0x80) { + $out .= "\xFF\xFD"; + } + else { + $out .= chr($cp >> 8); + $out .= chr($cp & 0xFF); + } + continue; + + case 3: + $cp = (($q[0] ^ 0xE0) << 12) | (($q[1] ^ 0x80) << 6) | ($q[2] ^ 0x80); + // Overlong sequence + if ($cp < 0x800) { + $out .= "\xFF\xFD"; + } + // Check for UTF-8 encoded surrogates (caused by a bad UTF-8 encoder) + else if ($c > 0xD800 && $c < 0xDFFF) { + $out .= "\xFF\xFD"; + } + else { + $out .= chr($cp >> 8); + $out .= chr($cp & 0xFF); + } + continue; + + case 4: + $cp = (($q[0] ^ 0xF0) << 18) | (($q[1] ^ 0x80) << 12) | (($q[2] ^ 0x80) << 6) | ($q[3] ^ 0x80); + // Overlong sequence + if ($cp < 0x10000) { + $out .= "\xFF\xFD"; + } + // Outside of the Unicode range + else if ($cp >= 0x10FFFF) { + $out .= "\xFF\xFD"; + } + else { + // Use surrogates + $cp -= 0x10000; + $s1 = 0xD800 | ($cp >> 10); + $s2 = 0xDC00 | ($cp & 0x3FF); + + $out .= chr($s1 >> 8); + $out .= chr($s1 & 0xFF); + $out .= chr($s2 >> 8); + $out .= chr($s2 & 0xFF); + } + continue; + } + } + } + return $out; +} + +// UTF-8 to codepoint array conversion. +// Correctly handles all illegal UTF-8 sequences. +function utf8_to_codepoints(&$txt) { + $l = strlen($txt); + $out = array(); + for ($i = 0; $i < $l; ++$i) { + $c = ord($txt{$i}); + // ASCII + if ($c < 0x80) { + $out[] = ord($txt{$i}); + } + // Lost continuation byte + else if ($c < 0xC0) { + $out[] = 0xFFFD; + continue; + } + // Multibyte sequence leading byte + else { + if ($c < 0xE0) { + $s = 2; + } + else if ($c < 0xF0) { + $s = 3; + } + else if ($c < 0xF8) { + $s = 4; + } + // 5/6 byte sequences not possible for Unicode. + else { + $out[] = 0xFFFD; + while (ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; } + continue; + } + + $q = array($c); + // Fetch rest of sequence + $l = strlen($txt); + while ($i + 1 < $l && ord($txt{$i + 1}) >= 0x80 && ord($txt{$i + 1}) < 0xC0) { ++$i; $q[] = ord($txt{$i}); } + + // Check length + if (count($q) != $s) { + $out[] = 0xFFFD; + continue; + } + + switch ($s) { + case 2: + $cp = (($q[0] ^ 0xC0) << 6) | ($q[1] ^ 0x80); + // Overlong sequence + if ($cp < 0x80) { + $out[] = 0xFFFD; + } + else { + $out[] = $cp; + } + continue; + + case 3: + $cp = (($q[0] ^ 0xE0) << 12) | (($q[1] ^ 0x80) << 6) | ($q[2] ^ 0x80); + // Overlong sequence + if ($cp < 0x800) { + $out[] = 0xFFFD; + } + // Check for UTF-8 encoded surrogates (caused by a bad UTF-8 encoder) + else if ($c > 0xD800 && $c < 0xDFFF) { + $out[] = 0xFFFD; + } + else { + $out[] = $cp; + } + continue; + + case 4: + $cp = (($q[0] ^ 0xF0) << 18) | (($q[1] ^ 0x80) << 12) | (($q[2] ^ 0x80) << 6) | ($q[3] ^ 0x80); + // Overlong sequence + if ($cp < 0x10000) { + $out[] = 0xFFFD; + } + // Outside of the Unicode range + else if ($cp >= 0x10FFFF) { + $out[] = 0xFFFD; + } + else { + $out[] = $cp; + } + continue; + } + } + } + return $out; +} + +//End of class +} + +} ?>