/*
https://gist.github.com/sergiotapia/7882944
If you already have loaded an image with image.Decode(), you can also

b := img.Bounds()
imgWidth := b.Max.X
imgHeight := b.Max.Y
*/
194076
func ReadImageDimensions(imagePath string) (int, int, error) {
	file, err := os.Open(imagePath)
	if err != nil {
		return -1, -1, err
	}
	defer file.Close()

	img, _, err := image.DecodeConfig(file)
	if err != nil {
		return -1, -1, err
	}
	return img.Width, img.Height, nil
}
1319716
func RGBAToString(img *image.RGBA) string {
	var result string
	result += fmt.Sprintf("\nBounds: %v", img.Bounds())
	result += fmt.Sprintf("\nStride: %v", img.Stride)
	for y := 0; y < img.Bounds().Dy(); y++ {
		result += "\n"
		for x := 0; x < img.Bounds().Dx(); x++ {
			pos := y*img.Stride + x*4
			result += fmt.Sprintf("%#X, ", img.Pix[pos+0])
			result += fmt.Sprintf("%#X, ", img.Pix[pos+1])
			result += fmt.Sprintf("%#X, ", img.Pix[pos+2])
			result += fmt.Sprintf("%#X, ", img.Pix[pos+3])
		}
	}
	result += "\n"
	return result
}
23667
func Crop(img image.Image, rect image.Rectangle) *image.NRGBA {
	r := rect.Intersect(img.Bounds()).Sub(img.Bounds().Min)
	if r.Empty() {
		return &image.NRGBA{}
	}
	src := newScanner(img)
	dst := image.NewNRGBA(image.Rect(0, 0, r.Dx(), r.Dy()))
	rowSize := r.Dx() * 4
	parallel(r.Min.Y, r.Max.Y, func(ys <-chan int) {
		for y := range ys {
			i := (y - r.Min.Y) * dst.Stride
			src.scan(r.Min.X, y, r.Max.X, y+1, dst.Pix[i:i+rowSize])
		}
	})
	return dst
}
980277
func (matcher *EqualImageMatcher) Match(actual interface{}) (success bool, err error) {
	if actual == nil && matcher.Expected == nil {
		return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead.  This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
	}

	a, ok := actual.(image.Image)
	if !ok {
		return false, fmt.Errorf("actual must be of type image.Image")
	}

	e, ok := matcher.Expected.(image.Image)
	if !ok {
		return false, fmt.Errorf("expected must be of type image.Image")
	}

	if a.Bounds().Dx() != e.Bounds().Dx() {
		return false, fmt.Errorf("Different width values %d != %d", a.Bounds().Dx(), e.Bounds().Dx())
	}

	if a.Bounds().Dy() != e.Bounds().Dy() {
		return false, fmt.Errorf("Different height values %d != %d", a.Bounds().Dy(), e.Bounds().Dy())
	}

	for x := 0; x < a.Bounds().Dx(); x++ {
		for y := 0; y < a.Bounds().Dy(); y++ {
			if a.At(x, y) != e.At(x, y) {
				return false, fmt.Errorf("pixels don't match at %d %d. %d != %d", x, y, a.At(x, y), e.At(x, y))
			}
		}
	}

	return true, nil
}
1149994
func Histogram(img image.Image) [256]float64 {
	var mu sync.Mutex
	var histogram [256]float64
	var total float64

	src := newScanner(img)
	if src.w == 0 || src.h == 0 {
		return histogram
	}

	parallel(0, src.h, func(ys <-chan int) {
		var tmpHistogram [256]float64
		var tmpTotal float64
		scanLine := make([]uint8, src.w*4)
		for y := range ys {
			src.scan(0, y, src.w, y+1, scanLine)
			i := 0
			for x := 0; x < src.w; x++ {
				s := scanLine[i : i+3 : i+3]
				r := s[0]
				g := s[1]
				b := s[2]
				y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
				tmpHistogram[int(y+0.5)]++
				tmpTotal++
				i += 4
			}
		}
		mu.Lock()
		for i := 0; i < 256; i++ {
			histogram[i] += tmpHistogram[i]
		}
		total += tmpTotal
		mu.Unlock()
	})

	for i := 0; i < 256; i++ {
		histogram[i] = histogram[i] / total
	}
	return histogram
}
1285737
func (rb *Bitmap) Maximum() uint32 {
	lastindex := len(rb.highlowcontainer.containers) - 1
	return uint32(rb.highlowcontainer.containers[lastindex].maximum()) | (uint32(rb.highlowcontainer.keys[lastindex]) << 16)
}
803860
func Decode(r io.Reader, options *DecoderOptions) (dest image.Image, err error) {
	dinfo := newDecompress(r)
	if dinfo == nil {
		return nil, errors.New("allocation failed")
	}
	defer destroyDecompress(dinfo)

	// Recover panic
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(error); !ok {
				err = fmt.Errorf("JPEG error: %v", r)
			}
		}
	}()

	C.jpeg_read_header(dinfo, C.TRUE)
	setupDecoderOptions(dinfo, options)

	switch dinfo.num_components {
	case 1:
		if dinfo.jpeg_color_space != C.JCS_GRAYSCALE {
			return nil, errors.New("Image has unsupported colorspace")
		}
		dest, err = decodeGray(dinfo)
	case 3:
		switch dinfo.jpeg_color_space {
		case C.JCS_YCbCr:
			dest, err = decodeYCbCr(dinfo)
		case C.JCS_RGB:
			dest, err = decodeRGB(dinfo)
		default:
			return nil, errors.New("Image has unsupported colorspace")
		}
	}
	return
}
870066
func Fit(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
	maxW, maxH := width, height

	if maxW <= 0 || maxH <= 0 {
		return &image.NRGBA{}
	}

	srcBounds := img.Bounds()
	srcW := srcBounds.Dx()
	srcH := srcBounds.Dy()

	if srcW <= 0 || srcH <= 0 {
		return &image.NRGBA{}
	}

	if srcW <= maxW && srcH <= maxH {
		return Clone(img)
	}

	srcAspectRatio := float64(srcW) / float64(srcH)
	maxAspectRatio := float64(maxW) / float64(maxH)

	var newW, newH int
	if srcAspectRatio > maxAspectRatio {
		newW = maxW
		newH = int(float64(newW) / srcAspectRatio)
	} else {
		newH = maxH
		newW = int(float64(newH) * srcAspectRatio)
	}

	return Resize(img, newW, newH, filter)
}
1212615
func decodeRGB(dinfo *C.struct_jpeg_decompress_struct) (dest *rgb.Image, err error) {
	C.jpeg_calc_output_dimensions(dinfo)
	dest = rgb.NewImage(image.Rect(0, 0, int(dinfo.output_width), int(dinfo.output_height)))

	dinfo.out_color_space = C.JCS_RGB
	readScanLines(dinfo, dest.Pix, dest.Stride)
	return
}
451056
func (d *wktDecoder) decode(wkt string) (*Geometry, error) {
	cstr := C.CString(wkt)
	defer C.free(unsafe.Pointer(cstr))
	g := cGEOSWKTReader_read(d.r, cstr)
	if g == nil {
		return nil, Error()
	}
	return geomFromPtr(g), nil
}
1131480
func (b *Bound) Height() float64 {
	return b.ne.Y() - b.sw.Y()
}
968870
func encodedSize(src string, enc Encoding) int {
	if enc.Equals(EncodingUTF8) {
		return len(src)
	}

	toXEncoding := resolveXEncoding(nil, enc)
	encoded, _ := toXEncoding.Encoder().String(src)
	return len(encoded)
}
910231
func DecodeRGBAToSize(data []byte, width, height int) (m *image.RGBA, err error) {
	pix, err := webpDecodeRGBAToSize(data, width, height)
	if err != nil {
		return
	}
	m = &image.RGBA{
		Pix:    pix,
		Stride: 4 * width,
		Rect:   image.Rect(0, 0, width, height),
	}
	return
}
273343
func Alpha(dest *Image, alpha int) {
	r := dest.Bounds()

	var a, x, y, i int
	for x = r.Min.X; x < r.Max.X; x++ {
		for y = r.Min.Y; y < r.Max.Y; y++ {
			i = dest.PixOffset(x, y)
			a = int(dest.Pix[i+3])
			dest.Pix[i+3] = uint8((a * alpha) / 100)
		}
	}
}
8326
func Decode(src []byte, mode int) (inst Inst, err error) {
	return decode1(src, mode, false)
}
1080726
func NewBoundFromMapTile(x, y, z uint64) *Bound {
	maxIndex := uint64(1) << z
	if x < 0 || y < 0 || x >= maxIndex || y >= maxIndex {
		panic("tile index out of range")
	}

	shift := 31 - z
	if z > 31 {
		shift = 0
	}

	lng1, lat1 := scalarMercatorInverse(x<<shift, y<<shift, 31)
	lng2, lat2 := scalarMercatorInverse((x+1)<<shift, (y+1)<<shift, 31)

	return &Bound{
		sw: &Point{math.Min(lng1, lng2), math.Min(lat1, lat2)},
		ne: &Point{math.Max(lng1, lng2), math.Max(lat1, lat2)},
	}
}
1344367
func resizeNearest(img image.Image, width, height int) *image.NRGBA {
	dst := image.NewNRGBA(image.Rect(0, 0, width, height))
	dx := float64(img.Bounds().Dx()) / float64(width)
	dy := float64(img.Bounds().Dy()) / float64(height)

	if dx > 1 && dy > 1 {
		src := newScanner(img)
		parallel(0, height, func(ys <-chan int) {
			for y := range ys {
				srcY := int((float64(y) + 0.5) * dy)
				dstOff := y * dst.Stride
				for x := 0; x < width; x++ {
					srcX := int((float64(x) + 0.5) * dx)
					src.scan(srcX, srcY, srcX+1, srcY+1, dst.Pix[dstOff:dstOff+4])
					dstOff += 4
				}
			}
		})
	} else {
		src := toNRGBA(img)
		parallel(0, height, func(ys <-chan int) {
			for y := range ys {
				srcY := int((float64(y) + 0.5) * dy)
				srcOff0 := srcY * src.Stride
				dstOff := y * dst.Stride
				for x := 0; x < width; x++ {
					srcX := int((float64(x) + 0.5) * dx)
					srcOff := srcOff0 + srcX*4
					copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
					dstOff += 4
				}
			}
		})
	}

	return dst
}