Skip to content

Instantly share code, notes, and snippets.

@jarodium
Last active November 5, 2019 20:05
Show Gist options
  • Save jarodium/407b70ac41d7fd4c6837565e46474e90 to your computer and use it in GitHub Desktop.
Save jarodium/407b70ac41d7fd4c6837565e46474e90 to your computer and use it in GitHub Desktop.
Predominant color with VIPS
<?php
require '../vendor/autoload.php';
use Jcupitt\Vips;
Vips\Config::concurrencySet(2);
Vips\Config::CacheSetMax(0);
//header("Content-type: text/plain");
//var_dump($_REQUEST);
$mime = "jpeg";
$ext = ".jpg";
$desired_width = 800;
$f = filter_var($_REQUEST["uri"],FILTER_SANITIZE_STRING);
header("Content-type: image/".$mime);
//open our huge image and thumbnail it to a buffer
//$image = Vips\Image::newFromFile("produtos/capricorn-4315367.jpg");
$image = Vips\Image::thumbnail("produtos/capricorn-4315367.jpg", 100);
//calculate aspect ratio for guessing the height of final image
$aspectRatio = $image->height / $image->width;
/* Keep the width fix at $desired_width, but change the height according to the aspect ratio */
$desired_height = (int)($aspectRatio * $desired_width);
//quality 1 will pixelate as intended
$buffer = $image->writeToBuffer($ext,["Q" => 1]); //Karen Stadfelt reference here, Code Geass fans xD
//load image from buffer
$image2 = Vips\Image::newFromBuffer($buffer, '', ['sequential' => true]);
//i could get the average, but I want the dominant color
//https://stackoverflow.com/questions/3468500/detect-overall-average-color-of-the-picture
$block_size = 20;
$colors = [];
for($x=0; $x<$image2->width; $x += $block_size) {
for($y=0; $y<$image2->height; $y += $block_size) {
$rgb = $image2->getpoint($x, $y);
$red = round(round(($rgb[0] / 0x33)) * 0x33);
$green = round(round(($rgb[1] / 0x33)) * 0x33);
$blue = round(round(($rgb[2] / 0x33)) * 0x33);
$hexRGB = sprintf('%02X%02X%02X', $red, $green, $blue); //line is only usefull when dumping for HTML
$strRGB = $rgb[0].",".$rgb[1].",".$rgb[2];
if(array_key_exists($strRGB, $colors)) {
$colors[$strRGB]++;
}
else {
$colors[$strRGB] = 1;
}
}
}
arsort($colors);
//var_dump($colors);
$rgb = array_key_first($colors);
$rgb = explode(",",$rgb);
$colors = []; //free mem space?
//create a new image and then fill it with $rgb
//I find my lack of VIPS knowledge, disturbing
//var_dump($rgb);
$im = @imagecreatetruecolor($desired_width, $desired_height) or die("Cannot Initialize new GD image stream");
$bg = imagecolorallocate($im, (int)$rgb[0] , (int)$rgb[1], (int)$rgb[2]);
imagefill($im, 0, 0, $bg);
imagejpeg($im);
imagedestroy($im);
//echo $buffer;
exit;
<?php
$block_size = 25;
$colors = [];
/*
As instructed in https://github.com/libvips/php-vips/issues/92#issuecomment-549765148,
we make a fast thumbnail to 16 and then pixelate with resize
*/
$thumb = Vips\Image::thumbnail($f, 16);
$placeholder = $thumb->resize($desired_width / $thumb->width, [
'scale' => $desired_height / $thumb->height,
'kernel' => 'nearest'
]);
/* then we create an image from a buffer with sequential access to get pixel information with a block_size,
previously measured in Shop or Gimp
*/
$placeholder = Vips\Image::newFromBuffer($placeholder->writeToBuffer($ext), '', ['sequential' => true]);
for($x=0; $x<$placeholder->width; $x += $block_size) {
for($y=0; $y<$placeholder->height; $y += $block_size) {
$rgb = $placeholder->getpoint($x, $y);
$red = round(round(($rgb[0] / 0x33)) * 0x33);
$green = round(round(($rgb[1] / 0x33)) * 0x33);
$blue = round(round(($rgb[2] / 0x33)) * 0x33);
$hexRGB = "#".sprintf('%02X%02X%02X', $red, $green, $blue); //line is only usefull when dumping for HTML
//$strRGB = $rgb[0].",".$rgb[1].",".$rgb[2];
if(array_key_exists($hexRGB, $colors)) {
$colors[$hexRGB]++;
}
else {
$colors[$hexRGB] = 1;
}
}
}
arsort($colors);
$rgb = array_key_first($colors);
list($alpha, $red, $green, $blue) = parse($rgb); //parse function in https://gist.github.com/kleisauke/a8cdd74c63738eb3add7d9422458aed8
$thumb = null;
$placeholder = null;
$colors = [];
//this part is in https://gist.github.com/kleisauke/a8cdd74c63738eb3add7d9422458aed8
// Make a 1x1 pixel with the red channel and cast it to provided format.
$pixel = Vips\Image::black(1, 1)->add($red)->cast(Vips\BandFormat::UCHAR);
// Extend this 1x1 pixel to match the origin image dimensions.
$image = $pixel->embed(0, 0, $desired_width, $desired_height, ['extend' => Vips\Extend::COPY]);
// Ensure that the interpretation of the image is set.
$image = $image->copy(['interpretation' => Vips\Interpretation::SRGB]);
// Bandwise join the rest of the channels including the alpha channel.
$image = $image->bandjoin([
$green,
$blue,
$alpha
]);
$buffer = $image->writeToBuffer($ext);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment