Skip to content

Instantly share code, notes, and snippets.

@imjasonh
Last active December 15, 2015 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imjasonh/5297038 to your computer and use it in GitHub Desktop.
Save imjasonh/5297038 to your computer and use it in GitHub Desktop.
Go script to read a png image like those found at http://scrollboss.illmosis.net/sprites.php?g=xmen-konamiarc to figure out how to make one with Perler beads (WIP)
package main
import (
"flag"
"fmt"
"image"
"image/color"
"image/png"
"log"
"math"
"os"
"sort"
"strconv"
)
const (
pegboardH = 29
pegboardW = 29
perlerWidthInches = 0.181102362 // Inches width of a Perler bead
rgb8to16 = 0x101 // Multiply an 8-bit RGB value to 16-bit
newFilePrefix = "perlerized-"
)
var filename = flag.String("f", "", "Name of png file to perlerize")
func main() {
flag.Parse()
file, err := os.Open(*filename)
if err != nil {
log.Fatal(err)
}
defer file.Close()
img, err := png.Decode(file)
if err != nil {
log.Fatal(err)
}
bounds := img.Bounds()
size := bounds.Size()
w := size.X
h := size.Y
fmt.Printf("Image dimensions: %v x %v pixels\n", h, w)
str := func(x int) string {
return strconv.FormatFloat(float64(x)*perlerWidthInches, 'g', 3, 64)
}
realW := str(w)
realH := str(h)
fmt.Printf("Physical dimensions: %s\" x %s\" ", realH, realW)
boards := uint(math.Ceil(float64(w) / pegboardW) * math.Ceil(float64(h) / pegboardH))
fmt.Printf("(%d pegboards)\n", boards)
// Make a palette out of all the possible bead colors
var palette color.Palette
for k, _ := range paletteMap {
palette = append(palette, k)
}
paletted := palettedImage{img, palette}
newFilename := newFilePrefix + *filename
newFile, err := os.Create(newFilename)
if err != nil {
log.Fatal(err)
}
defer newFile.Close()
png.Encode(newFile, paletted)
fmt.Println("Created:", newFilename)
var total uint32
colors := make(map[string]uint32)
for i := bounds.Min.X; i < bounds.Max.X; i++ {
for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
c := paletted.At(i, j)
_, _, _, a := c.RGBA()
if a == 0 {
continue
}
colors[paletteMap[c]]++
total++
}
}
fmt.Printf("%d total beads\n=======\n", total)
pairs := sortMap(colors)
for p := 0; p < len(pairs); p++ {
fmt.Println(pairs[p].key, pairs[p].val)
}
}
type palettedImage struct {
orig image.Image
palette color.Palette
}
func (p palettedImage) ColorIndexAt(x, y int) uint8 {
return uint8(p.palette.Index(p.orig.At(x, y)))
}
func (p palettedImage) At(x, y int) color.Color {
return convert(p.palette, p.orig.At(x, y))
}
func (p palettedImage) Bounds() image.Rectangle {
return p.orig.Bounds()
}
func (p palettedImage) ColorModel() color.Model {
return color.ModelFunc(func(in color.Color) color.Color {
return convert(p.palette, in)
})
}
func convert(p color.Palette, c color.Color) color.Color {
_, _, _, a := c.RGBA()
if a == 0 {
return color.Transparent
}
return p.Convert(c)
}
type myColor struct {
r, g, b uint32
}
func (m myColor) RGBA() (r, g, b, a uint32) {
return m.r * rgb8to16,
m.g * rgb8to16,
m.b * rgb8to16,
255 * rgb8to16
}
func col(r, g, b uint32) color.Color {
return myColor{r, g, b}
}
// Map of available Perler bead colors to their name
// From https://sites.google.com/site/degenatrons/other-stuff/bead-pattern-generator
var paletteMap = map[color.Color]string{
// Perler bead colors
col(255, 255, 255): "P01-WHITE",
col(240, 230, 195): "P02-CREAM",
col(255, 235, 55): "P03-YELLOW",
col(255, 115, 80): "P04-ORANGE",
col(205, 70, 90): "P05-RED",
col(240, 130, 175): "P06-BUBBLE-GUM",
col(120, 95, 155): "P07-PURPLE",
col(35, 80, 145): "P08-DARK-BLUE",
col(45, 130, 200): "P09-LIGHT-BLUE",
col(40, 140, 100): "P10-DARK-GREEN",
col(75, 195, 180): "P11-LIGHT-GREEN",
col(110, 90, 85): "P12-BROWN",
col(150, 155, 160): "P17-GREY",
col(0, 0, 0): "P18-BLACK",
col(165, 90, 90): "P20-RUST",
col(160, 130, 95): "P21-LIGHT-BROWN",
col(250, 205, 195): "P33-PEACH",
col(205, 165, 135): "P35-TAN",
col(255, 60, 130): "P38-MAGENTA",
col(90, 160, 205): "P52-PASTEL-BLUE",
col(135, 210, 145): "P53-PASTEL-GREEN",
col(155, 135, 205): "P54-PASTEL-LAVENDER",
col(215, 155, 200): "P55-PASTEL-PINK",
col(245, 240, 155): "P56-PASTEL-YELLOW",
col(250, 200, 85): "P57-CHEDDAR",
col(160, 215, 225): "P58-TOOTHPASTE",
col(255, 90, 115): "P59-HOT-CORAL",
col(175, 90, 160): "P60-PLUM",
col(125, 210, 80): "P61-KIWI-LIME",
col(5, 150, 205): "P62-TURQUOISE",
col(255, 150, 160): "P63-BLUSH",
col(85, 125, 185): "P70-PERIWINKLE",
col(245, 200, 230): "P79-LIGHT-PINK",
col(115, 185, 115): "P80-BRIGHT-GREEN",
col(240, 95, 165): "P83-PINK",
col(190, 70, 115): "P88-RASPBERRY",
col(240, 150, 110): "P90-BUTTERSCOTCH",
col(0, 150, 165): "P91-PARROT-GREEN",
col(95, 100, 100): "P92-DARK-GREY",
// Hama bead colors
col(250, 240, 195): "H02-CREAM",
col(255, 215, 90): "H03-YELLOW",
col(240, 105, 95): "H04-ORANGE",
col(245, 155, 175): "H06-PINK",
col(35, 85, 160): "H08-BLUE",
col(120, 90, 145): "H07-PURPLE",
col(25, 105, 180): "H09-LIGHT-BLUE",
col(35, 125, 95): "H10-GREEN",
col(70, 195, 165): "H11-LIGHT-GREEN",
col(100, 75, 80): "H12-BROWN",
col(145, 150, 155): "H17-GREY",
col(170, 85, 80): "H20-BROWN",
col(190, 130, 100): "H21-LIGHT-BROWN",
col(175, 75, 85): "H22-DARK-RED",
col(240, 170, 165): "H26-FLESH",
col(225, 185, 150): "H27-BEIGE",
col(70, 85, 90): "H28-DARK-GREEN",
col(195, 80, 115): "H29-RASPBERRY",
col(115, 75, 85): "H30-BURGUNDY",
col(105, 160, 175): "H31-TURQUOISE",
col(255, 95, 200): "H32-FUCHSIA",
col(245, 240, 125): "H43-PASTEL-YELLOW",
col(255, 120, 140): "H44-PASTEL-CORAL",
col(165, 140, 205): "H45-PASTEL-PURPLE",
col(80, 170, 225): "H46-PASTEL-BLUE",
col(150, 230, 160): "H47-PASTEL-GREEN",
col(230, 135, 200): "H48-PASTEL-PINK",
col(240, 175, 95): "H60-TEDDY-BEAR",
// Nabbi bead colors
col(90, 85, 80): "N02-DARK-BROWN",
col(105, 75, 80): "N03-BROWN-MEDIUM",
col(150, 85, 100): "N04-WINE-RED",
col(190, 125, 85): "N05-BUTTERSCOTCH",
col(185, 160, 145): "N06-BEIGE",
col(240, 195, 150): "N07-SKIN",
col(160, 160, 155): "N08-ASH-GREY",
col(70, 100, 90): "N09-DARK-GREEN",
col(230, 225, 225): "N10-LIGHT-GREY",
col(115, 90, 155): "N11-PURPLE",
col(245, 225, 215): "N12-IVORY",
col(255, 210, 75): "N14-YELLOW",
col(50, 145, 100): "N16-GREEN",
col(0, 120, 210): "N17-BLUE",
col(245, 200, 190): "N18-LIGHT-PINK",
col(215, 65, 85): "N19-LIGHT-RED",
col(210, 155, 125): "N20-LIGHT-BROWN",
col(255, 245, 175): "N21-LIGHT-YELLOW",
col(55, 170, 100): "N22-PEARL-GREEN",
col(90, 170, 235): "N23-PASTEL-BLUE",
col(200, 185, 240): "N24-LILAC",
col(255, 120, 165): "N25-OLD-ROSE",
col(255, 185, 150): "N26-LIGHT-ORANGE",
col(145, 105, 100): "N27-BROWN",
col(160, 205, 245): "N28-LIGHT-BLUE",
col(225, 160, 85): "N29-PEARL-ORANGE",
col(200, 200, 120): "N30-OLIVE",
}
type pair struct {
key string
val uint32
}
type pairlist []pair
func (p pairlist) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p pairlist) Len() int { return len(p) }
func (p pairlist) Less(i, j int) bool { return p[i].val > p[j].val }
func sortMap(m map[string]uint32) pairlist {
p := make(pairlist, len(m))
i := 0
for k, v := range m {
p[i] = pair{k, v}
i++
}
sort.Sort(p)
return p
}
@timeslider
Copy link

Where did you find the rgb values of the colors?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment