Skip to content

Instantly share code, notes, and snippets.

@maximvl
Created January 11, 2015 21:00
Show Gist options
  • Save maximvl/ac0a36380914fc9804cd to your computer and use it in GitHub Desktop.
Save maximvl/ac0a36380914fc9804cd to your computer and use it in GitHub Desktop.
# palettegen.rb
# Copyright 2008 Michael Yacavone, myacavone at gmail.com
# Released under the MIT license ("do whatever you want")
# http://www.opensource.org/licenses/mit-license.php
# Would love to receive improvement patches!
# Version 1.0
# February 18, 2007
# Version 1.1
# January 11, 2014
require 'RMagick'
include Magick
$just_print = false
if ARGV.length == 2
$just_print = true
aperture = Integer(ARGV[1])
elsif ARGV.length != 4
puts " Usage: ruby palettegen.rb InputImage OutputImage SwatchSize ApertureSize"
puts " Example: ruby palettegen.rb Ocean.jpg OceanPalette.jpg 50 100"
puts " Palettegen generates a 9x5 color palette from an input image."
puts " SwatchSize is the output color-swatch size."
puts " ApertureSize is the 'lens' size that picks up color from the image."
puts " ApertureSize is at the end because you may want to experiment to "
puts " find the optimal size."
exit
end
# Read the image file
img = Magick::Image::read(ARGV[0]).first
if not $just_print
# Set size of color swatches
$swatch = Integer(ARGV[2])
# Set the aperture of the target samples
aperture = Integer(ARGV[3])
# Create shades for blending
$black = Magick::Image.new($swatch, $swatch) { self.background_color = '#000000' }
$white = Magick::Image.new($swatch, $swatch) { self.background_color = '#ffffff' }
end
# Get the x/y coordinates of the five sample locations,
# based on the rule of thirds and the center. This awesome idea via
# Shelley Powers at http://burningbird.net/php/photographs.phps
topy = (img.rows / 3)
bottomy = ((img.rows / 3) * 2);
leftx = (img.columns / 3);
rightx = ((img.columns / 3) * 2);
centery = (img.rows / 2);
centerx = (img.columns / 2);
# Create an imagelist to hold the blends
blendedImages = Magick::ImageList.new
# Blend each of five samples with a black or white shade, in various percentages, to generate a palette.
# Process: at each x/y coordinate, crop out a rect based on the aperture size,
# quantize this rect down to a single color,
# set the background color to the quantized color,
# put each blended image into the imagelist.
def printColor(src)
color = src.pixel_color(1,1)
puts "#{color.red.to_s(16)}:#{color.green.to_s(16)}:#{color.blue.to_s(16)}"
end
def addImage(src, images)
src = Magick::Image.new($swatch, $swatch) { self.background_color = src.pixel_color(1, 1) }
images << $black.blend(src, 0.2)
images << $black.blend(src, 0.4)
images << $black.blend(src, 0.6)
images << $black.blend(src, 0.8)
images << src
images << $white.blend(src, 0.8)
images << $white.blend(src, 0.6)
images << $white.blend(src, 0.4)
images << $white.blend(src, 0.2)
end
def processImage(src, images)
if $just_print
printColor(src)
else
addImage(src, images)
end
end
# The following is total brute force; could use some block'd elegence....
src = img.crop(leftx, topy, aperture, aperture).quantize(1)
processImage(src, blendedImages)
src = img.crop(rightx, topy, aperture, aperture).quantize(1)
processImage(src, blendedImages)
src = img.crop(leftx, bottomy, aperture, aperture).quantize(1)
processImage(src, blendedImages)
src = img.crop(rightx, bottomy, aperture, aperture).quantize(1)
processImage(src, blendedImages)
src = img.crop(centerx, centery, aperture, aperture).quantize(1)
processImage(src, blendedImages)
# Positon blended images on a canvas.
# The tile is hard-coded to fit the nine swatches for each of the five samples.
# The geometry sets the gap between $swatches.
if blendedImages.size > 0
montage = blendedImages.montage {
self.tile = "9x5"
self.geometry = "+2+2"
self.background_color = "black"
}
# Write file to disk
montage.write(ARGV[1])
end
# To-do:
# Use blocks instead of the brute force swatch creation.
# Write text onto the image with original file name, aperture size, and maybe hex color values?
# Specify a global offset to the five target samples in case you want to move the sample targets around the image.
# Build a UI and make it a web app.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment