/** * Extract data from a JPEG image * * @param string $data Image raw data * * @return array Image raw data array */ public function getData($data) { $data['filter'] = 'DCTDecode'; $data['data'] = $data['raw']; $byte = new Byte($data['raw']); // extract embedded ICC profile (if any) $icc = array(); $offset = 0; while (($pos = strpos($data['raw'], 'ICC_PROFILE' . "", $offset)) !== false) { // get ICC sequence length $length = $byte->getUShort($pos - 2) - 16; // marker sequence number $msn = max(1, ord($data['raw'][$pos + 12])); // number of markers (total of APP2 used) //$nom = max(1, ord($data['raw'][($pos + 13)])); // get sequence segment $icc[$msn - 1] = substr($data['raw'], $pos + 14, $length); // move forward to next sequence $offset = $pos + 14 + $length; } // order and compact ICC segments if (count($icc) > 0) { ksort($icc); $icc = implode('', $icc); if (substr($icc, 36, 4) == 'acsp') { // valid ICC profile $data['icc'] = $icc; } } return $data; }
/** * Get font widths */ protected function getWidths() { // create widths array $chw = array(); $this->offset = $this->fdt['table']['hmtx']['offset']; for ($i = 0; $i < $this->fdt['numHMetrics']; ++$i) { $chw[$i] = round($this->fbyte->getUFWord($this->offset) * $this->fdt['urk']); $this->offset += 4; // skip lsb } if ($this->fdt['numHMetrics'] < $this->fdt['numGlyphs']) { // fill missing widths with the last value $chw = array_pad($chw, $this->fdt['numGlyphs'], $chw[$this->fdt['numHMetrics'] - 1]); } $this->fdt['MissingWidth'] = $chw[0]; $this->fdt['cw'] = ''; $this->fdt['cbbox'] = ''; for ($cid = 0; $cid <= 65535; ++$cid) { if (isset($this->fdt['ctgdata'][$cid])) { if ($cid >= 0 && isset($chw[$this->fdt['ctgdata'][$cid]])) { $this->fdt['cw'] .= ',"' . $cid . '":' . $chw[$this->fdt['ctgdata'][$cid]]; } if (isset($this->fdt['indexToLoc'][$this->fdt['ctgdata'][$cid]])) { $this->offset = $this->fdt['table']['glyf']['offset'] + $this->fdt['indexToLoc'][$this->fdt['ctgdata'][$cid]]; $xMin = round($this->fbyte->getFWord($this->offset + 2) * $this->fdt['urk']); $yMin = round($this->fbyte->getFWord($this->offset + 4) * $this->fdt['urk']); $xMax = round($this->fbyte->getFWord($this->offset + 6) * $this->fdt['urk']); $yMax = round($this->fbyte->getFWord($this->offset + 8) * $this->fdt['urk']); $this->fdt['cbbox'] .= ',"' . $cid . '":[' . $xMin . ',' . $yMin . ',' . $xMax . ',' . $yMax . ']'; } } } }
/** * Add composite glyphs * * @param array $new_sga * @param int $key * * @return array */ protected function findCompositeGlyphs($new_sga, $key) { if (isset($this->fdt['indexToLoc'][$key])) { $this->offset = $this->fdt['table']['glyf']['offset'] + $this->fdt['indexToLoc'][$key]; $numberOfContours = $this->fbyte->getShort($this->offset); $this->offset += 2; if ($numberOfContours < 0) { // composite glyph $this->offset += 8; // skip xMin, yMin, xMax, yMax do { $flags = $this->fbyte->getUShort($this->offset); $this->offset += 2; $glyphIndex = $this->fbyte->getUShort($this->offset); $this->offset += 2; if (!isset($this->subglyphs[$glyphIndex])) { // add missing glyphs $new_sga[$glyphIndex] = true; } // skip some bytes by case if ($flags & 1) { $this->offset += 4; } else { $this->offset += 2; } if ($flags & 8) { $this->offset += 2; } elseif ($flags & 64) { $this->offset += 4; } elseif ($flags & 128) { $this->offset += 8; } } while ($flags & 32); } } return $new_sga; }
/** * Get the font type * * @param string $font_type Font type. Leave empty for autodetect mode. * * @return string */ protected function getFontType($font_type) { // autodetect font type if (empty($font_type)) { if (substr($this->font, 0, 16) == 'StartFontMetrics') { // AFM type - we use this type only for the 14 Core fonts return 'Core'; } if (substr($this->font, 0, 4) == 'OTTO') { throw new FontException('Unsupported font format: OpenType with CFF data'); } if ($this->fbyte->getULong(0) == 0x10000) { return 'TrueTypeUnicode'; } return 'Type1'; } if (strpos($font_type, 'CID0') === 0) { return 'cidfont0'; } if (in_array($font_type, array('Core', 'Type1', 'TrueType', 'TrueTypeUnicode'))) { return $font_type; } throw new FontException('unknown or unsupported font type: ' . $font_type); }
/** * Extract the iCCP chunk data * * @param Byte $byte Byte class object * @param string $data Image raw data * @param int $offset Current byte offset * @param int $len NUmber of bytes in this chunk * * @return array Image raw data array */ protected function getIccpChunk($byte, $data, &$offset, $len) { // skip profile name $pos = 0; while ($byte->getByte($offset++) != 0 && $pos < 80) { ++$pos; } // get compression method if ($byte->getByte($offset++) != 0) { // @codeCoverageIgnoreStart throw new ImageException('Unknown filter method'); // @codeCoverageIgnoreEnd } // read ICC Color Profile $len -= $pos + 2; $data['icc'] = gzuncompress(substr($data['raw'], $offset, $len)); $offset += $len; $offset += 4; return $data; }