package rasterimage

import (
	
	
	
	
	
)

const (
	jpegMarkerPrefix = 0xff
	jpegMarkerSOI    = 0xd8
	jpegMarkerEOI    = 0xd9
	jpegMarkerSOS    = 0xda
	jpegMarkerAPP1   = 0xe1
	exifOrientation  = 0x0112
)

// jpegEXIFOrientation reads only marker and TIFF metadata preceding the first
// entropy-coded scan. Invalid or unsupported EXIF is ignored, matching image
// viewers that render the JPEG normally when its optional metadata is broken.
func jpegEXIFOrientation( context.Context,  []byte) (uint8, error) {
	if len() < 2 || [0] != jpegMarkerPrefix || [1] != jpegMarkerSOI {
		return 1, nil
	}
	for  := 2;  < len(); {
		if  := contextError();  != nil {
			return 1, 
		}
		if [] != jpegMarkerPrefix {
			return 1, nil
		}
		for  < len() && [] == jpegMarkerPrefix {
			++
		}
		if  >= len() {
			return 1, nil
		}
		 := []
		++
		switch {
		case  == jpegMarkerSOS ||  == jpegMarkerEOI:
			return 1, nil
		case  == jpegMarkerSOI ||  == 0x01 ||  >= 0xd0 &&  <= 0xd7:
			continue
		}
		if len()- < 2 {
			return 1, nil
		}
		 := int(binary.BigEndian.Uint16([ : +2]))
		if  < 2 ||  > len()- {
			return 1, nil
		}
		 := [+2 : +]
		if  == jpegMarkerAPP1 {
			if ,  := parseEXIFOrientation(, );  {
				return , nil
			}
			if  := contextError();  != nil {
				return 1, 
			}
		}
		 += 
	}
	return 1, nil
}

func parseEXIFOrientation( context.Context,  []byte) (uint8, bool) {
	if len() < 14 || !bytes.Equal([:6], []byte("Exif\x00\x00")) {
		return 0, false
	}
	 := [6:]
	var  binary.ByteOrder
	switch string([:2]) {
	case "II":
		 = binary.LittleEndian
	case "MM":
		 = binary.BigEndian
	default:
		return 0, false
	}
	if .Uint16([2:4]) != 42 {
		return 0, false
	}
	 := uint64(.Uint32([4:8]))
	if  > uint64(len()) || uint64(len())- < 2 {
		return 0, false
	}
	 := [int():]
	 := uint64(.Uint16([:2]))
	if  > (uint64(len())-2)/12 {
		return 0, false
	}
	for  := uint64(0);  < ; ++ {
		if &255 == 0 {
			if contextError() != nil {
				return 0, false
			}
		}
		 := [2+*12 : 2+(+1)*12]
		if .Uint16([:2]) != exifOrientation {
			continue
		}
		if .Uint16([2:4]) != 3 || .Uint32([4:8]) != 1 {
			return 0, false
		}
		 := .Uint16([8:10])
		if  < 1 ||  > 8 {
			return 0, false
		}
		return uint8(), true
	}
	return 0, false
}

func orientedConfig( image.Config,  uint8) image.Config {
	if  >= 5 &&  <= 8 {
		.Width, .Height = .Height, .Width
	}
	return 
}

func orientImage( image.Image,  uint8) image.Image {
	if  <= 1 ||  > 8 {
		return 
	}
	,  := .Bounds().Dx(), .Bounds().Dy()
	,  := , 
	if  >= 5 {
		,  = , 
	}
	return orientedImage{
		Image: , orientation: ,
		bounds: image.Rect(0, 0, , ),
	}
}

type orientedImage struct {
	image.Image
	orientation uint8
	bounds      image.Rectangle
}

func ( orientedImage) () image.Rectangle { return .bounds }

func ( orientedImage) (,  int) color.Color {
	 := image.Pt(, )
	if !.In(.bounds) {
		return color.NRGBA{}
	}
	 -= .bounds.Min.X
	 -= .bounds.Min.Y
	,  := .Image.Bounds().Dx(), .Image.Bounds().Dy()
	var ,  int
	switch .orientation {
	case 2:
		,  = -1-, 
	case 3:
		,  = -1-, -1-
	case 4:
		,  = , -1-
	case 5:
		,  = , 
	case 6:
		,  = , -1-
	case 7:
		,  = -1-, -1-
	case 8:
		,  = -1-, 
	default:
		,  = , 
	}
	 := .Image.Bounds().Min
	return .Image.At(.X+, .Y+)
}