Example #1
0
File: hxl.go Project: hawx/img
// Halves the width of the double-width image created by hxl to produce nice
// smooth edges.
func halveWidth(img image.Image) image.Image {
	b := img.Bounds()
	o := image.NewRGBA(image.Rect(0, 0, b.Dx()/2, b.Dy()))

	for y := 0; y < b.Dy(); y++ {
		for x := 0; x < b.Dx()/2; x++ {
			l := img.At(x*2, y)
			r := img.At(x*2+1, y)

			o.Set(x, y, utils.Average(l, r))
		}
	}

	return o
}
Example #2
0
File: pixelate.go Project: hawx/img
func paintAverage(img image.Image, bounds image.Rectangle, dest draw.Image,
	c chan int) {
	values := make([]color.Color, bounds.Dx()*bounds.Dy())
	count := 0

	utils.EachColorInRectangle(img, bounds, func(c color.Color) {
		values[count] = c
		count++
	})

	avg := utils.Average(values...)

	utils.MapColorInRectangle(img, bounds, dest, func(c color.Color) color.Color {
		return avg
	})

	c <- 1
}
Example #3
0
File: hxl.go Project: hawx/img
// Hxl pixelates the Image into equilateral triangles with the width
// given. These are arranged into hexagonal shapes.
func Hxl(img image.Image, width int) image.Image {
	b := img.Bounds()

	pixelHeight := width * 2
	pixelWidth := width

	cols := b.Dx() / pixelWidth
	rows := b.Dy() / pixelHeight

	o := image.NewRGBA(image.Rect(0, 0, pixelWidth*cols*2, pixelHeight*rows))

	// Note: "Top" doesn't mean above the x-axis, it means in the triangle
	// pointing towards the x-axis.
	inTop := func(x, y float64) bool {
		return (x >= 0 && y >= x) || (x <= 0 && y >= -x)
	}

	// Same for "Bottom" this is the triangle below and pointing towards the
	// x-axis.
	inBottom := func(x, y float64) bool {
		return (x >= 0 && y <= -x) || (x <= 0 && y <= x)
	}

	for col := 0; col < cols; col++ {
		for row := 0; row < rows; row++ {
			north := []color.Color{}
			south := []color.Color{}

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth; x++ {
					realY := row*pixelHeight + y
					realX := col*pixelWidth + x
					pixel := img.At(realX, realY)

					yOrigin := float64(y - pixelHeight/2)
					xOrigin := float64(x - pixelWidth/2)

					if inTop(xOrigin, yOrigin) {
						north = append(north, pixel)
					} else if inBottom(xOrigin, yOrigin) {
						south = append(south, pixel)
					}
				}
			}

			top := utils.Average(north...)
			bot := utils.Average(south...)

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth*2; x++ {
					realY := row*pixelHeight + y
					realX := col*pixelWidth*2 + x

					yOrigin := float64(y - pixelHeight/2)
					xOrigin := float64(x - pixelWidth*2/2)

					if inTop(xOrigin, yOrigin) {
						o.Set(realX, realY, top)
					} else if inBottom(xOrigin, yOrigin) {
						o.Set(realX, realY, bot)
					}
				}
			}
		}
	}

	// Now for the shifted version

	offsetY := pixelHeight / 2
	offsetX := pixelWidth / 2

	for col := -1; col < cols; col++ {
		for row := -1; row < rows; row++ {
			north := []color.Color{}
			south := []color.Color{}

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth; x++ {
					realY := row*pixelHeight + y + offsetY
					realX := col*pixelWidth + x + offsetX

					if realX >= 0 && realX < b.Dx() {
						pixel := img.At(realX, realY)

						yOrigin := float64(y - pixelHeight/2)
						xOrigin := float64(x - pixelWidth/2)

						if inTop(xOrigin, yOrigin) {
							north = append(north, pixel)
						} else if inBottom(xOrigin, yOrigin) {
							south = append(south, pixel)
						}
					}
				}
			}

			top := utils.Average(north...)
			bot := utils.Average(south...)

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth*2; x++ {
					realY := row*pixelHeight + y + offsetY
					realX := col*pixelWidth*2 + x + offsetX*2

					yOrigin := float64(y - pixelHeight/2)
					xOrigin := float64(x - pixelWidth*2/2)

					if inTop(xOrigin, yOrigin) {
						o.Set(realX, realY, top)
					} else if inBottom(xOrigin, yOrigin) {
						o.Set(realX, realY, bot)
					}
				}
			}
		}
	}

	return halveWidth(o)
}
Example #4
0
File: pxl.go Project: hawx/img
func pxlWorker(img image.Image, bounds image.Rectangle, dest draw.Image,
	size utils.Dimension, triangle Triangle, aliased bool, c chan int) {

	ratio := float64(size.H) / float64(size.W)

	inTop := func(x, y float64) bool {
		return (y > ratio*x) && (y > ratio*-x)
	}

	inRight := func(x, y float64) bool {
		return (y < ratio*x) && (y > ratio*-x)
	}

	inBottom := func(x, y float64) bool {
		return (y < ratio*x) && (y < ratio*-x)
	}

	inLeft := func(x, y float64) bool {
		return (y > ratio*x) && (y < ratio*-x)
	}

	to := []color.Color{}
	ri := []color.Color{}
	bo := []color.Color{}
	le := []color.Color{}

	for y := 0; y < bounds.Dy(); y++ {
		for x := 0; x < bounds.Dx(); x++ {

			realY := bounds.Min.Y + y
			realX := bounds.Min.X + x

			yOrigin := float64(y - size.H/2)
			xOrigin := float64(x - size.W/2)

			if inTop(xOrigin, yOrigin) {
				to = append(to, img.At(realX, realY))

			} else if inRight(xOrigin, yOrigin) {
				ri = append(ri, img.At(realX, realY))

			} else if inBottom(xOrigin, yOrigin) {
				bo = append(bo, img.At(realX, realY))

			} else if inLeft(xOrigin, yOrigin) {
				le = append(le, img.At(realX, realY))
			}
		}
	}

	ato := utils.Average(to...)
	ari := utils.Average(ri...)
	abo := utils.Average(bo...)
	ale := utils.Average(le...)

	if (triangle != LEFT) && (triangle == RIGHT ||
		utils.Closeness(ato, ari) > utils.Closeness(ato, ale)) {

		topRight := utils.Average(ato, ari)
		bottomLeft := utils.Average(abo, ale)
		middle := utils.Average(topRight, bottomLeft)

		for y := 0; y < bounds.Dy(); y++ {
			for x := 0; x < bounds.Dx(); x++ {

				realY := bounds.Min.Y + y
				realX := bounds.Min.X + x

				yOrigin := float64(y - size.H/2)
				xOrigin := float64(x - size.W/2)

				if yOrigin > ratio*xOrigin {
					dest.Set(realX, realY, topRight)
				} else if yOrigin == ratio*xOrigin && !aliased {
					dest.Set(realX, realY, middle)
				} else {
					dest.Set(realX, realY, bottomLeft)
				}
			}
		}

	} else {

		topLeft := utils.Average(ato, ale)
		bottomRight := utils.Average(abo, ari)
		middle := utils.Average(topLeft, bottomRight)

		for y := 0; y < bounds.Dy(); y++ {
			for x := 0; x < bounds.Dx(); x++ {

				realY := bounds.Min.Y + y
				realX := bounds.Min.X + x

				yOrigin := float64(y - size.H/2)
				xOrigin := float64(x - size.W/2)

				// Do this one opposite to above so that the diagonals line up when
				// aliased.
				if yOrigin < ratio*-xOrigin {
					dest.Set(realX, realY, bottomRight)
				} else if yOrigin == ratio*-xOrigin && !aliased {
					dest.Set(realX, realY, middle)
				} else {
					dest.Set(realX, realY, topLeft)
				}
			}
		}
	}

	c <- 1
}
Example #5
0
File: vxl.go Project: hawx/img
// Vxl pixelates the Image into isometric cubes. It averages the colours and
// naïvely darkens and lightens the colours to mimic highlight and shade.
func Vxl(img image.Image, height int, flip bool, top, left, right float64) image.Image {
	b := img.Bounds()

	pixelHeight := height
	pixelWidth := int(math.Sqrt(3.0) * float64(pixelHeight) / 2.0)

	cols := b.Dx() / pixelWidth
	rows := b.Dy() / pixelHeight

	// intersection of lines
	c := float64(pixelHeight) / 2
	// gradient of lines
	k := math.Sqrt(3.0) / 3.0
	o := image.NewRGBA(image.Rect(0, 0, pixelWidth*cols, pixelHeight*rows))

	// See: http://www.flickr.com/photos/hawx-/8466236036/
	inTopSquare := func(x, y float64) bool {
		if !flip {
			y *= -1
		}
		return y <= -k*x+c && y >= k*x && y >= -k*x && y <= k*x+c
	}

	inBottomRight := func(x, y float64) bool {
		if !flip {
			y *= -1
		}
		return x >= 0 && y <= k*x && y >= k*x-c
	}

	inBottomLeft := func(x, y float64) bool {
		if !flip {
			y *= -1
		}
		return x <= 0 && y <= -k*x && y >= -k*x-c
	}

	inHexagon := func(x, y float64) bool {
		return inTopSquare(x, y) || inBottomRight(x, y) || inBottomLeft(x, y)
	}

	topL := channel.AdjustC(utils.Multiplier(top), channel.Lightness)
	rightL := channel.AdjustC(utils.Multiplier(right), channel.Lightness)
	leftL := channel.AdjustC(utils.Multiplier(left), channel.Lightness)

	for col := 0; col < cols; col++ {
		for row := 0; row < rows; row++ {
			seen := []color.Color{}

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth; x++ {
					realY := row*(pixelHeight+int(c)) + y
					realX := col*pixelWidth + x
					pixel := img.At(realX, realY)

					yOrigin := float64(y - pixelHeight/2)
					xOrigin := float64(x - pixelWidth/2)

					if inHexagon(xOrigin, yOrigin) {
						seen = append(seen, pixel)
					}
				}
			}

			average := utils.Average(seen...)

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth; x++ {
					realY := row*(pixelHeight+int(c)) + y
					realX := col*pixelWidth + x

					yOrigin := float64(y - pixelHeight/2)
					xOrigin := float64(x - pixelWidth/2)

					// This stops white bits showing above the top squares. It does mean
					// the dimensions aren't perfect, but what did you expect with pixels
					// and trig. It is inefficient though, maybe fix that later?
					if (!flip && yOrigin < 0) || (flip && yOrigin > 0) {
						o.Set(realX, realY, topL(average))
					} else {
						if xOrigin > 0 {
							o.Set(realX, realY, rightL(average))
						} else {
							o.Set(realX, realY, leftL(average))
						}
					}

					if inTopSquare(xOrigin, yOrigin) {
						o.Set(realX, realY, topL(average))
					}
					if inBottomRight(xOrigin, yOrigin) {
						o.Set(realX, realY, rightL(average))
					}
					if inBottomLeft(xOrigin, yOrigin) {
						o.Set(realX, realY, leftL(average))
					}
				}
			}
		}
	}

	offsetY := (pixelHeight + int(c)) / 2.0
	offsetX := pixelWidth / 2

	for col := -1; col < cols; col++ {
		for row := -1; row < rows; row++ {
			seen := []color.Color{}

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth; x++ {
					realY := row*(pixelHeight+int(c)) + y + offsetY
					realX := col*pixelWidth + x + offsetX

					if image.Pt(realX, realY).In(b) {
						pixel := img.At(realX, realY)

						yOrigin := float64(y - pixelHeight/2)
						xOrigin := float64(x - pixelWidth/2)

						if inHexagon(xOrigin, yOrigin) {
							seen = append(seen, pixel)
						}
					}
				}
			}

			if len(seen) <= 0 {
				continue
			}
			average := utils.Average(seen...)

			for y := 0; y < pixelHeight; y++ {
				for x := 0; x < pixelWidth; x++ {
					realY := row*(pixelHeight+int(c)) + y + offsetY
					realX := col*pixelWidth + x + offsetX

					yOrigin := float64(y - pixelHeight/2)
					xOrigin := float64(x - pixelWidth/2)

					if inTopSquare(xOrigin, yOrigin) {
						o.Set(realX, realY, topL(average))
					}
					if inBottomRight(xOrigin, yOrigin) {
						o.Set(realX, realY, rightL(average))
					}
					if inBottomLeft(xOrigin, yOrigin) {
						o.Set(realX, realY, leftL(average))
					}
				}
			}
		}
	}

	return o
}