From 613e69cdea7e3ef1c035cdc55ae44ae93bc04aa5 Mon Sep 17 00:00:00 2001
From: SamuelOPH <samueloph@gmail.com>
Date: Wed, 10 Feb 2016 09:59:51 -0500
Subject: [PATCH] More dynamic cover improvements - Expanded configuration
 documentation - Added more color-oriented configuration options - Some fixes
 to text sizing

---
 config/vufind/config.ini                     |  35 ++-
 module/VuFind/src/VuFind/Cover/Generator.php | 213 ++++++++++++-------
 2 files changed, 173 insertions(+), 75 deletions(-)

diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index 7d5efceaf33..fe191b8d162 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -669,18 +669,47 @@ authors         = Wikipedia
 [DynamicCovers]
 ; Font files specified here should exist in the css/font subdirectory of a theme.
 ; Some options are available by default inside the root theme.
+;
+; Covers are generated using title and author name, it will try to display everything
+; by doing the following: break the title into lines, and if the title is too long
+; it will display ellipses at the last line.
+; Author names will be resized to the minFontSize option if needed, and if that
+; don't make it fit, it will align left sided.
+;
+; Both author and title colors are independently customizable through these four
+; options:
+; authorFillColor,titleFillColor: the main color used, you can use any of the 16
+; named colors from HTML4.
+; authorBorderColor,titleBorderColor: the color used to make border, you can use
+; any of the 16 named colors from HTML4, or "none" if you don't want any border.
+;
+; maxLines: The maximum number of title lines to be displayed (excluding final ellipses)
+;
+; fontSize: Controls the maximum font size presented in the cover
+; minFontSize: The minimum font size author names can be, in order to display
+; as much as possible.
+;
+; bgColor: When using solid covers, you may also choose a background color, being
+; the default a pseudo-random generated color (the same for grid covers), the values
+; accepted are the same as the other color options.
+;
 ;authorFont = "Roboto-Light.ttf"
 ;titleFont = "RobotoCondensed-Bold.ttf"
 ;textAlign = center
 ;fontSize = 9
 ;minFontSize = 8
 ;maxLines = 4
-
 ;lightness = 220
 ;saturation = 80
 ;size = 128
 ;topPadding = 19
+;bottomPadding = 3
 ;wrapWidth = 110
+;titleFillColor = black
+;titleBorderColor = none
+;authorFillColor = white
+;authorBorderColor = black
+;bgColor = random
 
 ; This section is needed for Buchhandel.de cover loading. You need an authentication
 ; token. It may also be necessary to customize your templates in order to comply with
@@ -688,7 +717,7 @@ authors         = Wikipedia
 ; details before turning this on.
 [Buchhandel]
 url = "https://api.vlb.de/api/v1/cover/"
-; token = "XXXXXX-XXXX-XXXXX-XXXXXXXXXXXX" 
+; token = "XXXXXX-XXXX-XXXXX-XXXXXXXXXXXX"
 
 ; Possible HathiRights options = pd,ic,op,orph,und,umall,ic-world,nobody,pdus,cc-by,cc-by-nd,
 ; cc-by-nc-nd,cc-by-nc,cc-by-nc-sa,cc-by-sa,orphcand,cc-zero,und-world,icus
@@ -1060,7 +1089,7 @@ era             = true      ; allow browsing of era subdivisions
 ; <result_limit> most popular entries -- it only affects display order.
 ;alphabetical_order = true
 
-; This section controls the availability of export methods. 
+; This section controls the availability of export methods.
 ;
 ; Each entry may be a comma-separated list of contexts in which the export
 ; option will be presented. Valid options:
diff --git a/module/VuFind/src/VuFind/Cover/Generator.php b/module/VuFind/src/VuFind/Cover/Generator.php
index b0f6dd25a8b..19927689a61 100644
--- a/module/VuFind/src/VuFind/Cover/Generator.php
+++ b/module/VuFind/src/VuFind/Cover/Generator.php
@@ -26,7 +26,6 @@
  * @link     http://vufind.org/wiki/use_of_external_content Wiki
  */
 namespace VuFind\Cover;
-use VuFindCode\ISBN, Zend\Log\LoggerInterface, ZendService\Amazon\Amazon;
 
 /**
  * Dynamic Book Cover Generator
@@ -45,14 +44,41 @@ class Generator
      * @var array
      */
     protected $settings = [];
+
+    /**
+     * Title's fill color
+     *
+     * @var int
+     */
+    protected $titleFillColor;
+
+    /**
+     * Title's border color
+     *
+     * @var int
+     */
+    protected $titleBorderColor;
+
     /**
-     * Reserved color
+     * Author's fill color
+     *
+     * @var int
      */
-    protected $black;
+    protected $authorFillColor;
+
     /**
-     * Reserved color
+     * Author's border color
+     *
+     * @var int
      */
-    protected $white;
+    protected $authorBorderColor;
+
+    /**
+     * Base for image
+     *
+     * @var resource
+     */
+    protected $im;
 
     /**
      * Constructor
@@ -75,7 +101,12 @@ class Generator
             'textAlign'    => 'center',
             'titleFont'    => 'DroidSerif-Bold.ttf',
             'topPadding'   => 19,
+            'bottomPadding' => 3,
             'wrapWidth'    => 80,
+            'titleFillColor'  => 'black',
+            'titleBorderColor'  => 'none',
+            'authorFillColor' => 'white',
+            'authorBorderColor' => 'black'
         ];
         foreach ($settings as $i => $setting) {
             $default[$i] = $setting;
@@ -83,10 +114,70 @@ class Generator
         $default['authorFont'] = $this->fontPath($default['authorFont']);
         $default['titleFont']  = $this->fontPath($default['titleFont']);
         $this->settings = (object) $default;
+
+        // Create image
+        if (!($this->im = imagecreate($this->settings->size, $this->settings->size))
+        ) {
+            throw new \Exception("Cannot Initialize new GD image stream");
+        }
+        // Get all colors
+        $this->titleFillColor = $this->getColor($this->settings->titleFillColor);
+        $this->titleBorderColor = $this->getColor($this->settings->titleBorderColor);
+        $this->authorFillColor = $this->getColor($this->settings->authorFillColor);
+        $this->authorBorderColor = $this->getColor(
+            $this->settings->authorBorderColor
+        );
     }
 
     /**
-     * Generates a dynamic cover image from elements of the book
+     * Check and allocates color
+     *
+     * @param string $color Legal color name from HTML4
+     *
+     * @return allocated color
+     */
+    protected function getColor($color)
+    {
+        switch (strtolower($color)){
+        case 'black':
+            return imagecolorallocate($this->im, 0, 0, 0);
+        case 'silver':
+            return imagecolorallocate($this->im, 192, 192, 192);
+        case 'gray':
+            return imagecolorallocate($this->im, 128, 128, 128);
+        case 'white':
+            return imagecolorallocate($this->im, 255, 255, 255);
+        case 'maroon':
+            return imagecolorallocate($this->im, 128, 0, 0);
+        case 'red':
+            return imagecolorallocate($this->im, 255, 0, 0);
+        case 'purple':
+            return imagecolorallocate($this->im, 128, 0, 128);
+        case 'fuchsia':
+            return imagecolorallocate($this->im, 255, 0, 255);
+        case 'green':
+            return imagecolorallocate($this->im, 0, 128, 0);
+        case 'lime':
+            return imagecolorallocate($this->im, 0, 255, 0);
+        case 'olive':
+            return imagecolorallocate($this->im, 128, 128, 0);
+        case 'yellow':
+            return imagecolorallocate($this->im, 255, 255, 0);
+        case 'navy':
+            return imagecolorallocate($this->im, 0, 0, 128);
+        case 'blue':
+            return imagecolorallocate($this->im, 0, 0, 255);
+        case 'teal':
+            return imagecolorallocate($this->im, 0, 128, 128);
+        case 'aqua':
+            return imagecolorallocate($this->im, 0, 255, 255);
+        default:
+            return false;
+        }
+    }
+
+    /**
+     * Generates a dynamic cover image from elements of the item
      *
      * @param string $title      Title of the book
      * @param string $author     Author of the book
@@ -116,29 +207,20 @@ class Generator
      */
     protected function generateSolid($title, $author, $callnumber)
     {
-        $half = $this->settings->size / 2;
         $box  = $this->settings->size / 8;
-        // Create image
-        if (!($im = imagecreate($this->settings->size, $this->settings->size))) {
-            throw new \Exception("Cannot Initialize new GD image stream");
-        }
-        // this->white backdrop
-        $this->white = imagecolorallocate($im, 255, 255, 255);
-        // this->black
-        $this->black = imagecolorallocate($im, 0, 0, 0);
 
         // Generate seed from callnumber, title back up
         $seed = $this->createSeed($title, $callnumber);
         // Number to color, hsb to control saturation and lightness
         $color = $this->makeHSBColor(
-            $im,
+            $this->im,
             $seed % 256,
             $this->settings->saturation,
             $this->settings->lightness
         );
         // Fill solid color
         imagefilledrectangle(
-            $im,
+            $this->im,
             0,
             0,
             $this->settings->size,
@@ -146,17 +228,17 @@ class Generator
             $color
         );
 
-        $this->drawTitle($im, $title, $box);
-        $this->drawAuthor($im, $author);
+        $this->drawTitle($this->im, $title, $box);
+        $this->drawAuthor($this->im, $author);
 
         // Output png CHECK THE PARAM
         ob_start();
-        imagepng($im);
+        imagepng($this->im);
         $img = ob_get_contents();
         ob_end_clean();
 
         // Clear memory
-        imagedestroy($im);
+        imagedestroy($this->im);
         // GTFO
         return $img;
     }
@@ -176,15 +258,6 @@ class Generator
         $half = $this->settings->size / 2;
         $box  = $this->settings->size / 8;
 
-        // Create image
-        if (!($im = imagecreate($this->settings->size, $this->settings->size))) {
-            throw new \Exception("Cannot Initialize new GD image stream");
-        }
-        // this->white backdrop
-        $this->white = imagecolorallocate($im, 255, 255, 255);
-        // this->black
-        $this->black = imagecolorallocate($im, 0, 0, 0);
-
         // Generate seed from callnumber, title back up
         $seed = $this->createSeed($title, $callnumber);
         // Number to color, hsb to control saturation and lightness
@@ -294,7 +367,7 @@ class Generator
             $text = $words[$i];
             $line .= $text . ' ';
             $textWidth = $this->textWidth(
-                $line,
+                rtrim($line, ' '),
                 $this->settings->titleFont,
                 $this->settings->fontSize
             );
@@ -302,15 +375,14 @@ class Generator
                 // Print black with white border
                 $this->drawText(
                     $im,
-                    $pline,
-                    3,
+                    rtrim($pline, ' '),
                     $this->settings->topPadding + $lineHeight * $lineCount,
                     $this->settings->titleFont,
                     $this->settings->fontSize,
-                    $this->black,
-                    $this->white
+                    $this->titleFillColor,
+                    $this->titleBorderColor
                 );
-                $line = $text . " ";
+                $line = $text . ' ';
                 $lineCount++;
             }
             $i++;
@@ -318,26 +390,24 @@ class Generator
         // Print the last words
         $this->drawText(
             $im,
-            $line,
-            3,
+            rtrim($line, ' '),
             $this->settings->topPadding + $lineHeight * $lineCount,
             $this->settings->titleFont,
             $this->settings->fontSize,
-            $this->black,
-            $this->white
+            $this->titleFillColor,
+            $this->titleBorderColor
         );
         // Add ellipses if we've truncated
         if ($i < count($words) - 1) {
             $this->drawText(
                 $im,
                 '...',
-                5,
                 $this->settings->topPadding
                 + $this->settings->maxLines * $lineHeight,
                 $this->settings->titleFont,
                 $this->settings->fontSize + 1,
-                $this->black,
-                $this->white
+                $this->titleFillColor,
+                $this->titleBorderColor
             );
         }
     }
@@ -355,31 +425,33 @@ class Generator
         // Scale author to fit by incrementing fontsizes down
         $fontSize = $this->settings->fontSize;
         do {
-            $txtWidth = $this->textWidth(
+            $fontSize--;
+            $textWidth = $this->textWidth(
                 $author,
-                $this->settings->titleFont,
+                $this->settings->authorFont,
                 $fontSize
             );
-            $fontSize--;
-        } while ($txtWidth > $this->settings->wrapWidth);
-        // white text, black outline
-        $fontSize = ++$fontSize < $this->settings->minFontSize
-            ? $this->settings->fontSize
-            : $fontSize;
+        } while ($textWidth > $this->settings->wrapWidth &&
+              $fontSize > $this->minFontSize
+          );
         // Too small to read? Align left
-        $alignment = $fontSize < $this->settings->minFontSize
+        $textWidth = $this->textWidth(
+            $author,
+            $this->settings->authorFont,
+            $fontSize
+        );
+        $align = $textWidth > $this->settings->size
             ? 'left'
             : null;
         $this->drawText(
             $im,
             $author,
-            5,
-            $this->settings->size - 3,
+            $this->settings->size - $this->settings->bottomPadding,
             $this->settings->authorFont,
             $fontSize,
-            $this->white,
-            $this->black,
-            $alignment
+            $this->authorFillColor,
+            $this->authorBorderColor,
+            $align
         );
     }
 
@@ -410,7 +482,7 @@ class Generator
     protected function textWidth($text, $font, $size)
     {
         $p = imagettfbbox($size, 0, $font, $text);
-        return $p[2] - $p[0] - 4;
+        return $p[2] - $p[0];
     }
 
     /**
@@ -418,7 +490,6 @@ class Generator
      *
      * @param GCImage $im       Image object
      * @param string  $text     Text to render
-     * @param integer $x        Left position
      * @param integer $y        Top position
      * @param string  $font     Full path to font
      * @param integer $fontSize Size of the font
@@ -428,30 +499,28 @@ class Generator
      *
      * @return void
      */
-    protected function drawText($im, $text, $x, $y,
+    protected function drawText($im, $text, $y,
         $font, $fontSize, $mcolor, $scolor = false, $align = null
     ) {
-        $txtWidth = $this->textWidth(
+        $textWidth = $this->textWidth(
             $text,
-            $this->settings->titleFont,
-            $this->settings->fontSize
+            $font,
+            $fontSize
         );
-        if ($txtWidth > $this->settings->size) {
+        if ($textWidth > $this->settings->size) {
             $align = 'left';
-            $x = 0;
         }
         if (null == $align) {
             $align = $this->settings->textAlign;
         }
+        if ($align == 'left') {
+            $x = 0;
+        }
         if ($align == 'center') {
-            $p = imagettfbbox($fontSize, 0, $this->settings->titleFont, $text);
-            $txtWidth = $p[2] - $p[0] - 4;
-            $x = ($this->settings->size - $txtWidth) / 2;
+            $x = ($this->settings->size - $textWidth) / 2;
         }
         if ($align == 'right') {
-            $p = imagettfbbox($fontSize, 0, $this->settings->titleFont, $text);
-            $txtWidth = $p[2] - $p[0] - 4;
-            $x = $this->settings->size - $txtWidth - $x;
+            $x = $this->settings->size - $textWidth;
         }
 
         // Generate 5 lines of text, 4 offset in a border color
@@ -538,4 +607,4 @@ class Generator
             return imagecolorallocate($im, $v, $p, $q);
         }
     }
-}
\ No newline at end of file
+}
-- 
GitLab