crossword-8.x-1.x-dev/modules/crossword_image/src/Plugin/crossword/crossword_image/CrosswordThumbnailBase.php
modules/crossword_image/src/Plugin/crossword/crossword_image/CrosswordThumbnailBase.php
<?php namespace Drupal\crossword_image\Plugin\crossword\crossword_image; use Drupal\crossword_image\CrosswordImagePluginBase; use Drupal\file\FileInterface; /** * A base class for thumbnail images of crossword files. * * Simple extensions of this can set the image type, square size, * and line width. More advanced extensions can use the helper functions * provided on this class to add numerals and circles and fill. */ abstract class CrosswordThumbnailBase extends CrosswordImagePluginBase { /** * The width of a square in pixels. * * @var int */ protected $squareSize; /** * The width of a line in pixels. * * @var int */ protected $lineSize; /** * {@inheritdoc} */ public function createImageResource(FileInterface $file) { $data = $this->crosswordDataService->getData($file); $grid = $data['puzzle']['grid']; $image = $this->buildGrid($grid); $this->addEmbeddedImages($grid, $image); return $image; } /** * Make a black grid on white background. * * The result of this function can be used by other helper functions * to add things like fill and numerals. * * @param array $grid * The grid part of the crossword data array. * * @return resource * The most basic crossword thumbnail. */ public function buildGrid(array $grid) { $square_size = $this->squareSize; $line_size = $this->lineSize; $width = count($grid[0]) * $square_size + $line_size / 2; $height = count($grid) * $square_size + $line_size / 2; $image = @imagecreatetruecolor($width, $height); $white = imagecolorallocate($image, 255, 255, 255); foreach ($grid as $row_index => $row) { foreach ($row as $col_index => $square) { if ($square['fill'] !== NULL) { $color = $white; @imagefilledrectangle($image, $col_index * $square_size + $line_size / 2, $row_index * $square_size + $line_size / 2, ($col_index + 1) * $square_size - $line_size / 2, ($row_index + 1) * $square_size - $line_size / 2, $color); } } } return $image; } /** * Add circles to an existing image. * * @param array $grid * The grid part of the crossword data array. * @param resource $image * The crossword image we are adding to. * * @return resource * The image with added circles. */ public function addCircles(array $grid, $image) { $black = imagecolorallocate($image, 0, 0, 0); foreach ($grid as $row_index => $row) { foreach ($row as $col_index => $square) { if (!empty($square['circle'])) { $start = -180; $end = 180; $height = $width = $this->squareSize; $x = ($col_index + 0.5) * $this->squareSize; $y = ($row_index + 0.5) * $this->squareSize; // Draw two arcs to make the line thicker. @imagearc($image, $x, $y, $width, $height, $start, $end, $black); @imagearc($image, $x, $y, $width - 1, $height - 1, $start, $end, $black); } } } return $image; } /** * Add numerals to an existing image. * * @param array $grid * The grid part of the crossword data array. * @param resource $image * The crossword image we are adding to. * * @return resource * The image with added numerals. */ public function addNumerals(array $grid, $image) { $square_size = $this->squareSize; $line_size = $this->lineSize; $black = imagecolorallocate($image, 0, 0, 0); $font = $this->font ?? 3; foreach ($grid as $row_index => $row) { foreach ($row as $col_index => $square) { if (isset($square['numeral'])) { $color = $black; @imagestring($image, $font, $col_index * $square_size + $line_size / 2 + $line_size, $row_index * $square_size + $line_size / 2, $square['numeral'], $color); } } } return $image; } /** * Add fill to an existing image. * * @param array $grid * The grid part of the crossword data array. * @param resource $image * The crossword image we are adding to. * @param bool $only_hints * TRUE if you only want to add the fill for squares marked as hint. * * @return resource * The image with added fill. */ public function addFill(array $grid, $image, $only_hints = FALSE) { $square_size = $this->squareSize; $black = imagecolorallocate($image, 0, 0, 0); $font = $this->extensionList->getPath('crossword_image') . '/fonts/RobotoMono-Regular.ttf'; // The RobotoMono regular has approximately this aspect ratio. $font_aspect = 1.29; foreach ($grid as $row_index => $row) { foreach ($row as $col_index => $square) { if (isset($square['fill']) && (!$only_hints || isset($square['hint']))) { if (!empty($square['rebus'])) { $angle = -45; // Prescribe a total width for the rebus text. $text_width = $square_size / sqrt(2); $size = $text_width / strlen($square['fill']) * $font_aspect; // Bottom left of text. Kind of magic. $x = ($col_index + 0.15) * $square_size; $y = ($row_index + 0.41) * $square_size - sqrt($size) / 4; } else { $size = $this->squareSize / 2; $angle = 0; // Bottom left of text. $x = ($col_index + 0.5) * $square_size - $size / 2 / $font_aspect; $y = ($row_index + 1) * $square_size - $size / 2; } @imagettftext($image, $size, $angle, $x, $y, $black, $font, $square['fill']); } } } return $image; } /** * Add hints to an existing image. * * @param array $grid * The grid part of the crossword data array. * @param resource $image * The crossword image we are adding to. * * @return resource * The image with added hints. */ public function addHints(array $grid, $image) { return $this->addFill($grid, $image, TRUE); } /** * Embeds images into an existing image. * * @param array $grid * The grid part of the crossword data array. * @param resource $image * The crossword image we are adding to. * * @return resource * The image with added embedded images. */ public function addEmbeddedImages(array $grid, $image) { $square_size = $this->squareSize; $line_size = $this->lineSize; foreach ($grid as $row_index => $row) { foreach ($row as $col_index => $square) { if (isset($square['image'])) { $data = base64_decode($square['image']['data']); $embedded = imagecreatefromstring($data); if ($embedded === FALSE) { continue; } $width = $square['image']['width'] * $square_size - $line_size; $height = $square['image']['width'] * $square_size - $line_size; $embedded = @imagescale($embedded, $width, $height); @imagecopy( $image, $embedded, $col_index * $square_size + $line_size / 2, $row_index * $square_size + $line_size / 2, 0, 0, $width, $height ); imagedestroy($embedded); } } } return $image; } }