Loading CHANGELOG.txt +1 −0 Changes for CHANGELOG.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ Image Field Repair 8.x-1.x (2018-04-??) -------------------- - [#2957577] by vaplas, fietserwin: Improve the performance of get image size. - [#2958147] by vaplas, fietserwin: More accentuated report. - Typo, missing @param, PhpStorm inspection. - [#2931750] by vaplas: TypeError: Argument 1 passed to Loading image_field_repair.inc +5 −3 Changes for image_field_repair.inc: 5 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; use Drupal\field\FieldStorageConfigInterface; use Drupal\image\Plugin\Field\FieldType\ImageItem; use Drupal\image_field_repair\ImageSizer; /** * Callback that processes a partial batch run to repair image fields. Loading Loading @@ -163,11 +164,11 @@ function image_field_repair_process_table_range(array $table_info, $rangeStart, // Get actual image dimensions and compare with stored image dimensions. // Do NOT use the image toolkit: we don't need it and we don't want to // depend on it or its current list of supported image types here. $image_size = @getimagesize($row['uri']); $image_size = ImageSizer::getSize($row['uri']); if (is_array($image_size)) { if ($row[$table_info['width_field']] != $image_size[0] || $row[$table_info['height_field']] != $image_size[1]) { // Not equal: repair current record (identified by its primary key // values). // Dimensions are not equal: repair current record (identified by its // primary key values). $update_query = $database->update($table_name) ->fields(array( $table_info['width_field'] => $image_size[0], Loading Loading @@ -262,6 +263,7 @@ function image_field_repair_get_field_table_infos(FieldStorageConfigInterface $f ]; } /** @noinspection PhpDocMissingThrowsInspection */ /** * Returns the table info for 1 field table. * Loading src/FastImage.php 0 → 100644 +209 −0 Changes for src/FastImage.php: 209 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\image_field_repair; /** * FastImage - Because sometimes you just want the size! * Based on the Ruby Implementation by Steven Sykes (https://github.com/sdsykes/fastimage) * * Copyright (c) 2012 Tom Moor, http://tommoor.com */ class FastImage { private $strpos = 0; private $str; private $type; private $handle; public function __construct($uri = NULL) { if ($uri) { $this->load($uri); } } public function load($uri) { if ($this->handle) { $this->close(); } $this->handle = fopen($uri, 'r'); } public function close() { if ($this->handle) { fclose($this->handle); $this->handle = NULL; $this->type = NULL; $this->str = NULL; } } /** * @return array|bool */ public function getSize() { $this->strpos = 0; if ($this->getType()) { return array_values($this->parseSize()); } return FALSE; } public function getType() { $this->strpos = 0; if (!$this->type) { switch ($this->getChars(2)) { case "BM": return $this->type = 'bmp'; case "GI": return $this->type = 'gif'; case chr(0xFF) . chr(0xd8): return $this->type = 'jpeg'; case chr(0x89) . 'P': return $this->type = 'png'; default: return FALSE; } } return $this->type; } private function parseSize() { $this->strpos = 0; switch ($this->type) { case 'png': return $this->parseSizeForPNG(); case 'gif': return $this->parseSizeForGIF(); case 'bmp': return $this->parseSizeForBMP(); case 'jpeg': return $this->parseSizeForJPEG(); } return NULL; } private function parseSizeForPNG() { $chars = $this->getChars(25); return unpack("N*", substr($chars, 16, 8)); } private function parseSizeForGIF() { $chars = $this->getChars(11); return unpack("S*", substr($chars, 6, 4)); } private function parseSizeForBMP() { $chars = $this->getChars(29); $chars = substr($chars, 14, 14); $type = unpack('C', $chars); return (reset($type) == 40) ? unpack('L*', substr($chars, 4)) : unpack('L*', substr($chars, 4, 8)); } private function parseSizeForJPEG() { $state = NULL; while (TRUE) { switch ($state) { default: $this->getChars(2); $state = 'started'; break; case 'started': $b = $this->getByte(); if ($b === FALSE) { return FALSE; } $state = $b == 0xFF ? 'sof' : 'started'; break; case 'sof': $b = $this->getByte(); if (in_array($b, range(0xe0, 0xef))) { $state = 'skipframe'; } elseif (in_array($b, array_merge(range(0xC0, 0xC3), range(0xC5, 0xC7), range(0xC9, 0xCB), range(0xCD, 0xCF)))) { $state = 'readsize'; } elseif ($b == 0xFF) { $state = 'sof'; } else { $state = 'skipframe'; } break; case 'skipframe': $skip = $this->readInt($this->getChars(2)) - 2; $state = 'doskip'; break; case 'doskip': /** @noinspection PhpUndefinedVariableInspection */ $this->getChars($skip); $state = 'started'; break; case 'readsize': $c = $this->getChars(7); return array( $this->readInt(substr($c, 5, 2)), $this->readInt(substr($c, 3, 2)) ); } } } private function getChars($n) { $response = NULL; // do we need more data? if ($this->strpos + $n - 1 >= strlen($this->str)) { $end = ($this->strpos + $n); while (strlen($this->str) < $end && $response !== FALSE) { // read more from the file handle $need = $end - ftell($this->handle); if ($response = fread($this->handle, $need)) { $this->str .= $response; } else { return FALSE; } } } $result = substr($this->str, $this->strpos, $n); $this->strpos += $n; return $result; } private function getByte() { $c = $this->getChars(1); $b = unpack("C", $c); return reset($b); } private function readInt($str) { $size = unpack("C*", $str); return ($size[1] << 8) + $size[2]; } public function __destruct() { $this->close(); } } src/ImageSizer.php 0 → 100644 +45 −0 Changes for src/ImageSizer.php: 45 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\image_field_repair; /** * Helper for get image size. */ class ImageSizer { /** * FastImage instance. * * @var \Drupal\image_field_repair\FastImage */ private static $fastImage; /** * Returns size of image. * * @param string $uri * Uri of image. * * @return array|bool * Array with info about image size: [0] => width, [1] => height. * FALSE if image not found or unsupported format. */ public static function getSize($uri) { if (!static::$fastImage) { static::$fastImage = new FastImage(); } if ($uri[0] === '/' && $uri[1] === '/') { $uri = 'http:' . $uri; } @static::$fastImage->load($uri); $size = @static::$fastImage->getSize(); if (!$size) { $size = @getimagesize($uri); } return $size; } } tests/src/Kernel/ImageSizerTest.php 0 → 100644 +56 −0 Changes for tests/src/Kernel/ImageSizerTest.php: 56 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\image_field_repair\Kernel; use Drupal\image_field_repair\ImageSizer; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\TestFileCreationTrait; /** * Tests get image size. * * @group image_field_repair */ class ImageSizerTest extends KernelTestBase { use TestFileCreationTrait; /** * {@inheritdoc} */ public static $modules = ['file', 'system', 'image_field_repair', 'simpletest']; /** * Tests get image size. */ public function testImageSizer() { $this->getTestFiles('image'); $this->getTestFiles('text'); $data = [ 'public://image-test.png' => [40, 20], 'public://image-test-transparent-indexed.gif' => [20, 17], 'public://image-test.gif' => [40, 20], 'public://image-test-transparent-out-of-range.gif' => [40, 20], 'public://image-test-no-transparency.gif' => [40, 20], 'public://image-2.jpg' => [80, 60], 'public://image-test.jpg' => [40, 20], 'public://image-1.png' => [360, 240], 'https://www.drupal.org/files/cta_multiple/featured_image/highlights_drupal.jpg' => [600, 410], '//www.drupal.org/files/cta_multiple/featured_image/highlights_drupal.jpg' => [600, 410], 'public://text-0.txt' => FALSE, 'public://not-found.jpg' => FALSE, ]; foreach ($data as $uri => $expected_size) { $actual_size = ImageSizer::getSize($uri); if (is_array($expected_size)) { $this->assertSame($expected_size[0], $actual_size[0]); $this->assertSame($expected_size[1], $actual_size[1]); } else { $this->assertSame($expected_size, $actual_size); } } } } Loading
CHANGELOG.txt +1 −0 Changes for CHANGELOG.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ Image Field Repair 8.x-1.x (2018-04-??) -------------------- - [#2957577] by vaplas, fietserwin: Improve the performance of get image size. - [#2958147] by vaplas, fietserwin: More accentuated report. - Typo, missing @param, PhpStorm inspection. - [#2931750] by vaplas: TypeError: Argument 1 passed to Loading
image_field_repair.inc +5 −3 Changes for image_field_repair.inc: 5 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; use Drupal\field\FieldStorageConfigInterface; use Drupal\image\Plugin\Field\FieldType\ImageItem; use Drupal\image_field_repair\ImageSizer; /** * Callback that processes a partial batch run to repair image fields. Loading Loading @@ -163,11 +164,11 @@ function image_field_repair_process_table_range(array $table_info, $rangeStart, // Get actual image dimensions and compare with stored image dimensions. // Do NOT use the image toolkit: we don't need it and we don't want to // depend on it or its current list of supported image types here. $image_size = @getimagesize($row['uri']); $image_size = ImageSizer::getSize($row['uri']); if (is_array($image_size)) { if ($row[$table_info['width_field']] != $image_size[0] || $row[$table_info['height_field']] != $image_size[1]) { // Not equal: repair current record (identified by its primary key // values). // Dimensions are not equal: repair current record (identified by its // primary key values). $update_query = $database->update($table_name) ->fields(array( $table_info['width_field'] => $image_size[0], Loading Loading @@ -262,6 +263,7 @@ function image_field_repair_get_field_table_infos(FieldStorageConfigInterface $f ]; } /** @noinspection PhpDocMissingThrowsInspection */ /** * Returns the table info for 1 field table. * Loading
src/FastImage.php 0 → 100644 +209 −0 Changes for src/FastImage.php: 209 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\image_field_repair; /** * FastImage - Because sometimes you just want the size! * Based on the Ruby Implementation by Steven Sykes (https://github.com/sdsykes/fastimage) * * Copyright (c) 2012 Tom Moor, http://tommoor.com */ class FastImage { private $strpos = 0; private $str; private $type; private $handle; public function __construct($uri = NULL) { if ($uri) { $this->load($uri); } } public function load($uri) { if ($this->handle) { $this->close(); } $this->handle = fopen($uri, 'r'); } public function close() { if ($this->handle) { fclose($this->handle); $this->handle = NULL; $this->type = NULL; $this->str = NULL; } } /** * @return array|bool */ public function getSize() { $this->strpos = 0; if ($this->getType()) { return array_values($this->parseSize()); } return FALSE; } public function getType() { $this->strpos = 0; if (!$this->type) { switch ($this->getChars(2)) { case "BM": return $this->type = 'bmp'; case "GI": return $this->type = 'gif'; case chr(0xFF) . chr(0xd8): return $this->type = 'jpeg'; case chr(0x89) . 'P': return $this->type = 'png'; default: return FALSE; } } return $this->type; } private function parseSize() { $this->strpos = 0; switch ($this->type) { case 'png': return $this->parseSizeForPNG(); case 'gif': return $this->parseSizeForGIF(); case 'bmp': return $this->parseSizeForBMP(); case 'jpeg': return $this->parseSizeForJPEG(); } return NULL; } private function parseSizeForPNG() { $chars = $this->getChars(25); return unpack("N*", substr($chars, 16, 8)); } private function parseSizeForGIF() { $chars = $this->getChars(11); return unpack("S*", substr($chars, 6, 4)); } private function parseSizeForBMP() { $chars = $this->getChars(29); $chars = substr($chars, 14, 14); $type = unpack('C', $chars); return (reset($type) == 40) ? unpack('L*', substr($chars, 4)) : unpack('L*', substr($chars, 4, 8)); } private function parseSizeForJPEG() { $state = NULL; while (TRUE) { switch ($state) { default: $this->getChars(2); $state = 'started'; break; case 'started': $b = $this->getByte(); if ($b === FALSE) { return FALSE; } $state = $b == 0xFF ? 'sof' : 'started'; break; case 'sof': $b = $this->getByte(); if (in_array($b, range(0xe0, 0xef))) { $state = 'skipframe'; } elseif (in_array($b, array_merge(range(0xC0, 0xC3), range(0xC5, 0xC7), range(0xC9, 0xCB), range(0xCD, 0xCF)))) { $state = 'readsize'; } elseif ($b == 0xFF) { $state = 'sof'; } else { $state = 'skipframe'; } break; case 'skipframe': $skip = $this->readInt($this->getChars(2)) - 2; $state = 'doskip'; break; case 'doskip': /** @noinspection PhpUndefinedVariableInspection */ $this->getChars($skip); $state = 'started'; break; case 'readsize': $c = $this->getChars(7); return array( $this->readInt(substr($c, 5, 2)), $this->readInt(substr($c, 3, 2)) ); } } } private function getChars($n) { $response = NULL; // do we need more data? if ($this->strpos + $n - 1 >= strlen($this->str)) { $end = ($this->strpos + $n); while (strlen($this->str) < $end && $response !== FALSE) { // read more from the file handle $need = $end - ftell($this->handle); if ($response = fread($this->handle, $need)) { $this->str .= $response; } else { return FALSE; } } } $result = substr($this->str, $this->strpos, $n); $this->strpos += $n; return $result; } private function getByte() { $c = $this->getChars(1); $b = unpack("C", $c); return reset($b); } private function readInt($str) { $size = unpack("C*", $str); return ($size[1] << 8) + $size[2]; } public function __destruct() { $this->close(); } }
src/ImageSizer.php 0 → 100644 +45 −0 Changes for src/ImageSizer.php: 45 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\image_field_repair; /** * Helper for get image size. */ class ImageSizer { /** * FastImage instance. * * @var \Drupal\image_field_repair\FastImage */ private static $fastImage; /** * Returns size of image. * * @param string $uri * Uri of image. * * @return array|bool * Array with info about image size: [0] => width, [1] => height. * FALSE if image not found or unsupported format. */ public static function getSize($uri) { if (!static::$fastImage) { static::$fastImage = new FastImage(); } if ($uri[0] === '/' && $uri[1] === '/') { $uri = 'http:' . $uri; } @static::$fastImage->load($uri); $size = @static::$fastImage->getSize(); if (!$size) { $size = @getimagesize($uri); } return $size; } }
tests/src/Kernel/ImageSizerTest.php 0 → 100644 +56 −0 Changes for tests/src/Kernel/ImageSizerTest.php: 56 added lines, 0 removed lines. Original line number Diff line number Diff line <?php namespace Drupal\Tests\image_field_repair\Kernel; use Drupal\image_field_repair\ImageSizer; use Drupal\KernelTests\KernelTestBase; use Drupal\Tests\TestFileCreationTrait; /** * Tests get image size. * * @group image_field_repair */ class ImageSizerTest extends KernelTestBase { use TestFileCreationTrait; /** * {@inheritdoc} */ public static $modules = ['file', 'system', 'image_field_repair', 'simpletest']; /** * Tests get image size. */ public function testImageSizer() { $this->getTestFiles('image'); $this->getTestFiles('text'); $data = [ 'public://image-test.png' => [40, 20], 'public://image-test-transparent-indexed.gif' => [20, 17], 'public://image-test.gif' => [40, 20], 'public://image-test-transparent-out-of-range.gif' => [40, 20], 'public://image-test-no-transparency.gif' => [40, 20], 'public://image-2.jpg' => [80, 60], 'public://image-test.jpg' => [40, 20], 'public://image-1.png' => [360, 240], 'https://www.drupal.org/files/cta_multiple/featured_image/highlights_drupal.jpg' => [600, 410], '//www.drupal.org/files/cta_multiple/featured_image/highlights_drupal.jpg' => [600, 410], 'public://text-0.txt' => FALSE, 'public://not-found.jpg' => FALSE, ]; foreach ($data as $uri => $expected_size) { $actual_size = ImageSizer::getSize($uri); if (is_array($expected_size)) { $this->assertSame($expected_size[0], $actual_size[0]); $this->assertSame($expected_size[1], $actual_size[1]); } else { $this->assertSame($expected_size, $actual_size); } } } }