Skip to content

Commit a2810be

Browse files
committed
Clean up code and add dependency for image loading
1 parent ec95530 commit a2810be

9 files changed

+325
-46
lines changed

composer.json

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
{
2-
"name": "marijnvdwerf/material-palette",
3-
"authors": [
4-
{
5-
"name": "Marijn van der Werf",
6-
"email": "[email protected]"
7-
}
8-
],
9-
"autoload": {
10-
"psr-4":{
11-
"marijnvdwerf\\palette\\": "src/"
12-
}
13-
},
14-
"require": {}
2+
"name": "marijnvdwerf/material-palette",
3+
"authors": [
4+
{
5+
"name": "Marijn van der Werf",
6+
"email": "[email protected]",
7+
"homepage": "http://marijnvdwerf.nl"
8+
}
9+
],
10+
"autoload": {
11+
"psr-4": {
12+
"marijnvdwerf\\palette\\": "src/"
13+
}
14+
},
15+
"require": {
16+
"php": ">=5.3.2",
17+
"intervention/image": "~2.2"
18+
},
19+
"suggest": {
20+
"ext-gd": "to use the GD implementation",
21+
"ext-imagick": "to use the Imagick implementation"
22+
}
1523
}

composer.lock

Lines changed: 76 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.php

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,58 @@
11
<?php
22

3-
use marijnvdwerf\palette\ImagickHistogramGenerator;
3+
use Intervention\Image\ImageManager;
44
use marijnvdwerf\palette\Palette;
55
use marijnvdwerf\palette\Swatch;
66

77
require 'vendor/autoload.php';
88

9-
$histogramGenerator = new ImagickHistogramGenerator();
10-
$colorQuantizer = new \marijnvdwerf\palette\ColorCutQuantizer();
9+
?>
10+
<style type="text/css">
11+
body {
12+
font-family: Roboto, sans-serif;
13+
}
1114

15+
* {
16+
margin: 0;
17+
padding: 0;
18+
box-sizing: border-box;
19+
}
1220

13-
$files = scandir('./specs/artwork');
14-
foreach ($files as $file) {
15-
if ($file[0] === '.') {
16-
continue;
17-
}
21+
.swatch {
22+
padding: 15px;
23+
list-style-type: none;
24+
}
25+
26+
.swatch__color {
27+
float: right;
28+
}
1829

19-
$image = new Imagick('./specs/artwork/' . $file);
30+
.album {
31+
width: 320px;
32+
}
33+
</style>
2034

21-
$image->sampleImage(100, 100);
35+
<?php
36+
$basePath = './specs/artwork';
37+
$files = scandir($basePath);
2238

23-
$image->setFormat('png');
39+
$manager = new ImageManager(array('driver' => 'imagick'));
40+
foreach ($files as $filename) {
41+
if ($filename[0] === '.') {
42+
continue;
43+
}
2444

25-
$swatches = $histogramGenerator->generate($image);
45+
$image = $manager->make($basePath . '/' . $filename);
2646

27-
$swatches = $colorQuantizer->quantize($swatches, 16);
47+
$palette = Palette::generate($image);
2848

29-
//$palette = Palette::generate($swatches);
3049

31-
echo '<h1>' . $file . '</h1>';
32-
echo "<img src='data:image/png;base64," . base64_encode($image->getImageBlob()) . "' />";
33-
printSwatches($swatches);
50+
echo '<div class="album">';
51+
echo "<img src='data:image/png;base64," . base64_encode($image->encode('png')) . "' />";
52+
echo '<h1>' . $filename . '</h1>';
53+
printPalette($palette);
54+
//printSwatches($swatches);
55+
echo '</div>';
3456
}
3557

3658

@@ -61,7 +83,7 @@ function printPalette(Palette $palette)
6183

6284
$swatchName = implode(' ', array_filter([$v2, $v1]));
6385
if ($swatch !== null) {
64-
echo sprintf('<li class="swatch" style="background-color: %s">%s</li>', $swatch->getColor(), $swatchName);
86+
echo sprintf('<li class="swatch" style="background-color: %1$s"><span class="swatch__name">%2$s</span> <span class="swatch__color">%1$s</span></li>', $swatch->getColor(), $swatchName);
6587
} else {
6688
echo sprintf('<li class="swatch swatch--empty">%s</li>', $swatchName);
6789
}
@@ -70,3 +92,4 @@ function printPalette(Palette $palette)
7092
}
7193
echo '</ul>';
7294
}
95+

src/ColorCutQuantizer.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function quantize($swatches, $maxColors)
2828
$vbox = $pq->extract();
2929

3030
if (!$vbox->canSplit()) {
31-
// No more boxes to split, so break;
31+
// No more boxes to split, so break;
3232
break;
3333
}
3434

@@ -234,5 +234,4 @@ function __toString()
234234
return sprintf('[VBox count:%d volume:%f]', count($this->swatches), $this->getVolume());
235235
}
236236

237-
238237
}

src/GDHistogramGenerator.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace marijnvdwerf\palette;
4+
5+
use Intervention\Image\Image;
6+
7+
class GDHistogramGenerator extends HistogramGenerator
8+
{
9+
10+
/**
11+
* @return Swatch
12+
*/
13+
private function getSwatch($color, $count)
14+
{
15+
// opacity ranges from 127 (transparent) to 0 (opaque). Should be from 0 to 1;
16+
$alpha = (127 - $color['alpha']) / 127;
17+
return new Swatch(new RGBColor($color['red'] / 255, $color['green'] / 255, $color['blue'] / 255, $alpha), $count);
18+
}
19+
20+
/**
21+
* @inheritdoc
22+
*/
23+
public function generate(Image $input)
24+
{
25+
$image = $input->getCore();
26+
27+
if (!(is_resource($image) && get_resource_type($image) === 'gd')) {
28+
throw new \Exception('This generator only support images using the GD driver');
29+
}
30+
31+
$srcImage = $image;
32+
if (imagesx($image) > 100 || imagesy($image) > 100) {
33+
// new canvas
34+
$image = imagecreatetruecolor(100, 100);
35+
36+
// fill with transparent color
37+
imagealphablending($image, false);
38+
$transparent = imagecolorallocatealpha($image, 255, 255, 255, 127);
39+
imagefilledrectangle($image, 0, 0, 100, 100, $transparent);
40+
imagecolortransparent($image, $transparent);
41+
imagealphablending($image, true);
42+
43+
// copy original
44+
imagecopyresized($image, $srcImage, 0, 0, 0, 0, 100, 100, imagesx($srcImage), imagesy($srcImage));
45+
}
46+
47+
$colorOccurences = [];
48+
for ($y = 0; $y < imagesy($image); $y++) {
49+
for ($x = 0; $x < imagesx($image); $x++) {
50+
$color = imagecolorat($image, $x, $y);
51+
if (!isset($colorOccurences[$color])) {
52+
$colorOccurences[$color] = 0;
53+
}
54+
55+
$colorOccurences[$color]++;
56+
}
57+
}
58+
59+
$palette = [];
60+
foreach ($colorOccurences as $colorIndex => $count) {
61+
$palette[] = $this->getSwatch(imagecolorsforindex($image, $colorIndex), $count);
62+
}
63+
64+
if ($srcImage !== $image) {
65+
// Destroy image if it was generated by this function
66+
imagedestroy($image);
67+
}
68+
69+
return $palette;
70+
}
71+
}

src/HistogramGenerator.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace marijnvdwerf\palette;
4+
5+
use Intervention\Image\Image;
6+
7+
abstract class HistogramGenerator
8+
{
9+
/**
10+
* @param $image Image
11+
* @return Swatch[];
12+
*/
13+
public abstract function generate(Image $image);
14+
}

src/ImagickHistogramGenerator.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
namespace marijnvdwerf\palette;
44

55

6-
class ImagickHistogramGenerator
6+
use Imagick;
7+
use Intervention\Image\Image;
8+
9+
class ImagickHistogramGenerator extends HistogramGenerator
710
{
811
/**
912
* @param \ImagickPixel $pixel
@@ -16,11 +19,29 @@ private function swatchForPixel(\ImagickPixel $pixel)
1619

1720

1821
/**
19-
* @return Swatch[]
22+
* @inheritdoc
2023
*/
21-
public function generate(\Imagick $image)
24+
public function generate(Image $input)
2225
{
23-
return array_map([$this, 'swatchForPixel'], $image->getImageHistogram());
26+
$srcImage = $input->getCore();
27+
if (!$srcImage instanceof Imagick) {
28+
throw new \Exception('This class only supports generating histograms for Imagick images');
29+
}
30+
31+
$image = $srcImage;
32+
33+
if ($image->getImageWidth() > 100 || $image->getImageHeight() > 100) {
34+
$image = clone $srcImage;
35+
$image->resizeImage(100, 100, Imagick::FILTER_POINT, 1);
36+
}
37+
38+
$histogram = array_map([$this, 'swatchForPixel'], $image->getImageHistogram());
39+
40+
if ($image !== $srcImage) {
41+
$image->destroy();
42+
}
43+
44+
return $histogram;
2445
}
2546

2647
}

src/Palette.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace marijnvdwerf\palette;
44

5+
use Intervention\Image\Image;
6+
57
class Palette
68
{
79
const TARGET_DARK_LUMA = 0.26;
@@ -49,22 +51,27 @@ class Palette
4951
private $darkMutedSwatch;
5052

5153
/**
52-
* @param $swatches Swatch[]
54+
* @param Image $image
5355
* @return Palette
5456
*/
55-
public static function generate($swatches)
57+
public static function generate(Image $image)
5658
{
57-
$palette = new Palette();
58-
$palette->swatches = $swatches;
59-
$palette->highestPopulation = $palette->findMaxPopulation();
59+
return PaletteGenerator::getInstance()->generate($image);
60+
}
6061

61-
$palette->generateVariationColors();
62+
/**
63+
* @param $swatches Swatch[]
64+
* @return Palette
65+
*/
66+
public function __construct($swatches)
67+
{
68+
$this->swatches = $swatches;
69+
$this->highestPopulation = $this->findMaxPopulation();
6270

71+
$this->generateVariationColors();
6372

6473
// Now try and generate any missing colors
65-
$palette->generateEmptySwatches();
66-
67-
return $palette;
74+
$this->generateEmptySwatches();
6875
}
6976

7077
private function findMaxPopulation()

0 commit comments

Comments
 (0)