diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe5275..8bfd2b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ IMPORTANT NOTE: This version only works on CACTI 1.x++! --- develop --- +* feature#298: Fit or stretch background images within the map canvas + * issue#289: Load viewer helpers explicitly before rendering maps * issue#288: Preserve dynamic editor labels and cycle countdowns diff --git a/lib/WeatherMap.class.php b/lib/WeatherMap.class.php index daf2ea8..f2f677f 100644 --- a/lib/WeatherMap.class.php +++ b/lib/WeatherMap.class.php @@ -3911,6 +3911,11 @@ function DrawMap($filename = '', $thumbnailfile = '', $thumbnailmax = 250, $with wm_debug('Finished Post-Processing Plugins...'); + $background_sizing = $this->get_hint('background_sizing', 'image'); + if (!in_array($background_sizing, ['fit', 'stretch', 'image'], true)) { + $background_sizing = 'image'; + } + wm_debug('====================================='); wm_debug('Start of Map Drawing'); @@ -3936,8 +3941,10 @@ function DrawMap($filename = '', $thumbnailfile = '', $thumbnailmax = 250, $with if (!$bgimage) { wm_warn('Failed to open background image. One possible reason: Is your BACKGROUND really a PNG?'); } else { - $this->width = imagesx($bgimage); - $this->height = imagesy($bgimage); + if ($background_sizing === 'image') { + $this->width = imagesx($bgimage); + $this->height = imagesy($bgimage); + } } } else { wm_warn('Your background image file could not be read. Check the filename, and permissions, for ' . $this->background); @@ -3975,7 +3982,22 @@ function DrawMap($filename = '', $thumbnailfile = '', $thumbnailmax = 250, $with wimagefilledrectangle($image, 0, 0, $this->width, $this->height, $this->colours['DEFAULT']['BG']['gdref1']); if ($bgimage) { - imagecopy($image, $bgimage, 0, 0, 0, 0, $this->width, $this->height); + if ($background_sizing === 'image') { + imagecopy($image, $bgimage, 0, 0, 0, 0, $this->width, $this->height); + } else { + $source_width = imagesx($bgimage); + $source_height = imagesy($bgimage); + $dest_width = $this->width; + $dest_height = $this->height; + if ($background_sizing === 'fit') { + $ratio = min($dest_width / $source_width, $dest_height / $source_height); + $dest_width = max(1, (int) round($source_width * $ratio)); + $dest_height = max(1, (int) round($source_height * $ratio)); + } + $dest_x = (int) floor(($this->width - $dest_width) / 2); + $dest_y = (int) floor(($this->height - $dest_height) / 2); + imagecopyresampled($image, $bgimage, $dest_x, $dest_y, 0, 0, $dest_width, $dest_height, $source_width, $source_height); + } unset($bgimage); } diff --git a/lib/editor.actions.php b/lib/editor.actions.php index a7d6405..2fa38fd 100644 --- a/lib/editor.actions.php +++ b/lib/editor.actions.php @@ -472,6 +472,11 @@ function setMapProperties($mapfile) { $map->background = wm_editor_sanitize_file(stripslashes(get_nfilter_request_var('map_bgfile')), ['png', 'jpg', 'gif', 'jpeg']); } + $background_sizing = get_nfilter_request_var('map_background_sizing'); + if (is_string($background_sizing) && in_array($background_sizing, ['fit', 'stretch', 'image'], true)) { + $map->add_hint('background_sizing', $background_sizing); + } + db_execute_prepared('UPDATE weathermap_maps SET titlecache = ? WHERE configfile = ?', diff --git a/locales/po/cacti.pot b/locales/po/cacti.pot index 7ffedf7..3def007 100644 --- a/locales/po/cacti.pot +++ b/locales/po/cacti.pot @@ -1051,6 +1051,22 @@ msgstr "" msgid "Background Image Filename" msgstr "" +#: weathermap-cacti-plugin-editor.php +msgid "Background sizing" +msgstr "" + +#: weathermap-cacti-plugin-editor.php +msgid "Fit to map" +msgstr "" + +#: weathermap-cacti-plugin-editor.php +msgid "Stretch to map" +msgstr "" + +#: weathermap-cacti-plugin-editor.php +msgid "Use image size" +msgstr "" + #: weathermap-cacti-plugin-editor.php msgid "Timestamp Text" msgstr "" diff --git a/tests/Support/BackgroundSizingEngineRegression.php b/tests/Support/BackgroundSizingEngineRegression.php new file mode 100644 index 0000000..98ad1a2 --- /dev/null +++ b/tests/Support/BackgroundSizingEngineRegression.php @@ -0,0 +1,104 @@ +[120, 120], 'stretch'=>[120, 120], 'image'=>[200, 100], 'invalid'=>[200, 100]] as $mode=>$size) { + $map = new WeatherMap(); + $map->width = 120; + $map->height = 120; + $map->background = $directory . '/background.png'; + $map->add_hint('background_sizing', 'image'); + $map->WriteConfig($directory . '/' . $mode . '.conf'); + $GLOBALS['__test_nfilter_request'] = [ + 'map_title' => 'Background test', 'map_legend' => 'Traffic', 'map_stamp' => '', + 'map_htmlfile' => '', 'map_pngfile' => '', 'map_width' => '120', 'map_height' => '120', + 'map_bgfile' => $directory . '/background.png', 'map_background_sizing' => $mode, + 'map_linkdefaultwidth' => '7', 'map_linkdefaultbwin' => '100M', 'map_linkdefaultbwout' => '100M', + ]; + setMapProperties($directory . '/' . $mode . '.conf'); + $saved = new WeatherMap(); + $saved->ReadConfig($directory . '/' . $mode . '.conf'); + wm_engine_assert($saved->get_hint('background_sizing') === ($mode === 'invalid' ? 'image' : $mode), $mode . ' editor persistence'); + if ($mode === 'invalid') { + $saved->add_hint('background_sizing', 'invalid'); + } + $saved->DrawMap($directory . '/' . $mode . '.png'); + $image = imagecreatefrompng($directory . '/' . $mode . '.png'); + wm_engine_assert([imagesx($image), imagesy($image)] === $size,$mode . ' canvas'); + $pixel = imagecolorsforindex($image,imagecolorat($image,60,1)); + wm_engine_assert(($pixel['red'] === 255 && $pixel['green'] === 0) === ($mode !== 'fit'),$mode . ' fit proportions'); + imagedestroy($image); + } + + foreach (['fit' => [120, 120], 'stretch' => [120, 120], 'image' => [200, 100], 'invalid' => [200, 100]] as $mode => $size) { + $map = new WeatherMap(); + $map->width = 120; + $map->height = 120; + $map->background = $directory . '/background.png'; + $map->add_hint('background_sizing', 'stretch'); + $map->postprocessclasses = ['SizingOverride']; + $map->plugins['post']['SizingOverride'] = new class($mode) { + public function __construct(private string $mode) {} + public function run($map) { + $map->add_hint('background_sizing', $this->mode); + } + }; + $file = $directory . '/post-' . $mode . '.png'; + $map->DrawMap($file); + $image = imagecreatefrompng($file); + wm_engine_assert([imagesx($image), imagesy($image)] === $size, $mode . ' post-processor canvas'); + $pixel = imagecolorsforindex($image, imagecolorat($image, 60, 1)); + wm_engine_assert(($pixel['red'] === 255 && $pixel['green'] === 0) === ($mode !== 'fit'), $mode . ' post-processor proportions'); + imagedestroy($image); + } + + print "PASS\n"; +} finally { + foreach (glob($directory . '/*') as $file) { + unlink($file); + }rmdir($directory); +} diff --git a/tests/Unit/BackgroundSizingEngineTest.php b/tests/Unit/BackgroundSizingEngineTest.php new file mode 100644 index 0000000..4a022dd --- /dev/null +++ b/tests/Unit/BackgroundSizingEngineTest.php @@ -0,0 +1,43 @@ + +