upgrade code for new simulator version
* add new rotation axis * resize image if necessary * add debug logs
This commit is contained in:
		@@ -58,7 +58,7 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var cameraFov, cameraImgW, cameraImgH, cameraImgD int
 | 
						var cameraFov, cameraImgW, cameraImgH, cameraImgD int
 | 
				
			||||||
	var cameraFishEyeX, cameraFishEyeY float64
 | 
						var cameraFishEyeX, cameraFishEyeY float64
 | 
				
			||||||
	var cameraOffsetX, cameraOffsetY, cameraOffsetZ, cameraRotX float64
 | 
						var cameraOffsetX, cameraOffsetY, cameraOffsetZ, cameraRotX, cameraRotY, cameraRotZ float64
 | 
				
			||||||
	var cameraImgEnc string
 | 
						var cameraImgEnc string
 | 
				
			||||||
	flag.IntVar(&cameraFov, "camera-fov", 90, "")
 | 
						flag.IntVar(&cameraFov, "camera-fov", 90, "")
 | 
				
			||||||
	flag.Float64Var(&cameraFishEyeX, "camera-fish-eye-x", 0.4, "")
 | 
						flag.Float64Var(&cameraFishEyeX, "camera-fish-eye-x", 0.4, "")
 | 
				
			||||||
@@ -70,7 +70,9 @@ func main() {
 | 
				
			|||||||
	flag.Float64Var(&cameraOffsetX, "camera-offset-x", 0, "moves camera left/right")
 | 
						flag.Float64Var(&cameraOffsetX, "camera-offset-x", 0, "moves camera left/right")
 | 
				
			||||||
	flag.Float64Var(&cameraOffsetY, "camera-offset-y", 1.120395, "moves camera up/down")
 | 
						flag.Float64Var(&cameraOffsetY, "camera-offset-y", 1.120395, "moves camera up/down")
 | 
				
			||||||
	flag.Float64Var(&cameraOffsetZ, "camera-offset-z", 0.5528488, "moves camera forward/back")
 | 
						flag.Float64Var(&cameraOffsetZ, "camera-offset-z", 0.5528488, "moves camera forward/back")
 | 
				
			||||||
	flag.Float64Var(&cameraRotX, "camera-rot-x", 15.0, "rotate the camera")
 | 
						flag.Float64Var(&cameraRotX, "camera-rot-x", 15.0, "rotate the camera around x-axis")
 | 
				
			||||||
 | 
						flag.Float64Var(&cameraRotY, "camera-rot-y", 0.0, "rotate the camera around y-axis")
 | 
				
			||||||
 | 
						flag.Float64Var(&cameraRotZ, "camera-rot-z", 0.0, "rotate the camera around z-axis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flag.Parse()
 | 
						flag.Parse()
 | 
				
			||||||
	if len(os.Args) <= 1 {
 | 
						if len(os.Args) <= 1 {
 | 
				
			||||||
@@ -132,8 +134,13 @@ func main() {
 | 
				
			|||||||
		OffsetY: fmt.Sprintf("%.2f", cameraOffsetY),
 | 
							OffsetY: fmt.Sprintf("%.2f", cameraOffsetY),
 | 
				
			||||||
		OffsetZ: fmt.Sprintf("%.2f", cameraOffsetZ),
 | 
							OffsetZ: fmt.Sprintf("%.2f", cameraOffsetZ),
 | 
				
			||||||
		RotX:    fmt.Sprintf("%.2f", cameraRotX),
 | 
							RotX:    fmt.Sprintf("%.2f", cameraRotX),
 | 
				
			||||||
 | 
							RotY:    fmt.Sprintf("%.2f", cameraRotY),
 | 
				
			||||||
 | 
							RotZ:    fmt.Sprintf("%.2f", cameraRotZ),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						gtw, err := gateway.New(address, &carConfig, &racer, &camera)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							zap.S().Fatalf("unable to init gateway: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	gtw := gateway.New(address, &carConfig, &racer, &camera)
 | 
					 | 
				
			||||||
	defer gtw.Stop()
 | 
						defer gtw.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgPub := events.NewMsgPublisher(
 | 
						msgPub := events.NewMsgPublisher(
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@@ -6,6 +6,7 @@ require (
 | 
				
			|||||||
	github.com/avast/retry-go v3.0.0+incompatible
 | 
						github.com/avast/retry-go v3.0.0+incompatible
 | 
				
			||||||
	github.com/cyrilix/robocar-base v0.1.5
 | 
						github.com/cyrilix/robocar-base v0.1.5
 | 
				
			||||||
	github.com/cyrilix/robocar-protobuf/go v1.0.3
 | 
						github.com/cyrilix/robocar-protobuf/go v1.0.3
 | 
				
			||||||
 | 
						github.com/disintegration/imaging v1.6.2
 | 
				
			||||||
	github.com/eclipse/paho.mqtt.golang v1.3.5
 | 
						github.com/eclipse/paho.mqtt.golang v1.3.5
 | 
				
			||||||
	github.com/golang/protobuf v1.5.2
 | 
						github.com/golang/protobuf v1.5.2
 | 
				
			||||||
	go.uber.org/zap v1.19.1
 | 
						go.uber.org/zap v1.19.1
 | 
				
			||||||
@@ -15,6 +16,7 @@ require (
 | 
				
			|||||||
	github.com/gorilla/websocket v1.4.2 // indirect
 | 
						github.com/gorilla/websocket v1.4.2 // indirect
 | 
				
			||||||
	go.uber.org/atomic v1.7.0 // indirect
 | 
						go.uber.org/atomic v1.7.0 // indirect
 | 
				
			||||||
	go.uber.org/multierr v1.6.0 // indirect
 | 
						go.uber.org/multierr v1.6.0 // indirect
 | 
				
			||||||
 | 
						golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
 | 
				
			||||||
	golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
 | 
						golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
 | 
				
			||||||
	google.golang.org/protobuf v1.26.0 // indirect
 | 
						google.golang.org/protobuf v1.26.0 // indirect
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@@ -17,6 +17,8 @@ github.com/cyrilix/robocar-protobuf/go v1.0.3/go.mod h1:xb95cK07lYXnKcHZKnGafmAg
 | 
				
			|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
					github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
				
			||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
					github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
				
			||||||
 | 
					github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
 | 
				
			||||||
 | 
					github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
 | 
				
			||||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
					github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
				
			||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
					github.com/docker/docker v17.12.0-ce-rc1.0.20200916142827-bd33bbf0497b+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
				
			||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 | 
					github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 | 
				
			||||||
@@ -99,6 +101,8 @@ go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
 | 
				
			|||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
					golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
					golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
 | 
					golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
 | 
				
			||||||
 | 
					golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 | 
				
			||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
					golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 | 
				
			||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 | 
					golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 | 
				
			||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
					golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,9 @@ import (
 | 
				
			|||||||
	"github.com/cyrilix/robocar-simulator/pkg/gateway"
 | 
						"github.com/cyrilix/robocar-simulator/pkg/gateway"
 | 
				
			||||||
	mqtt "github.com/eclipse/paho.mqtt.golang"
 | 
						mqtt "github.com/eclipse/paho.mqtt.golang"
 | 
				
			||||||
	"github.com/golang/protobuf/proto"
 | 
						"github.com/golang/protobuf/proto"
 | 
				
			||||||
 | 
						"go.uber.org/zap"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
	"go.uber.org/zap"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewMsgPublisher(srcEvents gateway.SimulatorSource, p Publisher, topicFrame, topicSteering, topicThrottle string) *MsgPublisher {
 | 
					func NewMsgPublisher(srcEvents gateway.SimulatorSource, p Publisher, topicFrame, topicSteering, topicThrottle string) *MsgPublisher {
 | 
				
			||||||
@@ -113,6 +113,7 @@ func (m *MsgPublisher) listenFrame() {
 | 
				
			|||||||
		msg := <-msgChan
 | 
							msg := <-msgChan
 | 
				
			||||||
		if msg == nil {
 | 
							if msg == nil {
 | 
				
			||||||
			// channel closed
 | 
								// channel closed
 | 
				
			||||||
 | 
								logr.Info("received empty message, channel closed")
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		logr.Debugf("new frame %v", msg.Id)
 | 
							logr.Debugf("new frame %v", msg.Id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,7 @@ func TestGateway_Start(t *testing.T) {
 | 
				
			|||||||
		OffsetZ:  "0",
 | 
							OffsetZ:  "0",
 | 
				
			||||||
		RotX:     "0",
 | 
							RotX:     "0",
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	gw := New(simulatorMock.Addr(),
 | 
						gw, err := New(simulatorMock.Addr(),
 | 
				
			||||||
		&carConfig,
 | 
							&carConfig,
 | 
				
			||||||
		&simulator.RacerBioMsg{},
 | 
							&simulator.RacerBioMsg{},
 | 
				
			||||||
		&camConfig,
 | 
							&camConfig,
 | 
				
			||||||
@@ -130,10 +130,13 @@ func TestGateway_WriteSteering(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gw := New(simulatorMock.Addr(),
 | 
						gw, err := New(simulatorMock.Addr(),
 | 
				
			||||||
		&simulator.CarConfigMsg{MsgType: simulator.MsgTypeCarConfig},
 | 
							&simulator.CarConfigMsg{MsgType: simulator.MsgTypeCarConfig},
 | 
				
			||||||
		&simulator.RacerBioMsg{},
 | 
							&simulator.RacerBioMsg{},
 | 
				
			||||||
		&simulator.CamConfigMsg{})
 | 
							&simulator.CamConfigMsg{
 | 
				
			||||||
 | 
							ImgH: "128",
 | 
				
			||||||
 | 
							ImgW: "160",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("unable to init simulator gateway: %v", err)
 | 
							t.Fatalf("unable to init simulator gateway: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -254,10 +257,16 @@ func TestGateway_WriteThrottle(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gw := New(simulatorMock.Addr(), &simulator.CarConfigMsg{MsgType: simulator.MsgTypeCarConfig},
 | 
						gw, err := New(simulatorMock.Addr(), &simulator.CarConfigMsg{MsgType: simulator.MsgTypeCarConfig},
 | 
				
			||||||
		&simulator.RacerBioMsg{},
 | 
							&simulator.RacerBioMsg{},
 | 
				
			||||||
		&simulator.CamConfigMsg{})
 | 
							&simulator.CamConfigMsg{
 | 
				
			||||||
 | 
								ImgH: "128",
 | 
				
			||||||
 | 
								ImgW: "160",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("unable to init simulator gateway: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	//go gw.Start()
 | 
						//go gw.Start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//<- simulatorMock.NotifyCar()
 | 
						//<- simulatorMock.NotifyCar()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,15 +2,20 @@ package gateway
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"github.com/avast/retry-go"
 | 
						"github.com/avast/retry-go"
 | 
				
			||||||
	"github.com/cyrilix/robocar-protobuf/go/events"
 | 
						"github.com/cyrilix/robocar-protobuf/go/events"
 | 
				
			||||||
	"github.com/cyrilix/robocar-simulator/pkg/simulator"
 | 
						"github.com/cyrilix/robocar-simulator/pkg/simulator"
 | 
				
			||||||
 | 
						"github.com/disintegration/imaging"
 | 
				
			||||||
	"github.com/golang/protobuf/ptypes/timestamp"
 | 
						"github.com/golang/protobuf/ptypes/timestamp"
 | 
				
			||||||
	"go.uber.org/zap"
 | 
						"go.uber.org/zap"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/jpeg"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -31,10 +36,19 @@ type ThrottleSource interface {
 | 
				
			|||||||
	SubscribeThrottle() <-chan *events.ThrottleMessage
 | 
						SubscribeThrottle() <-chan *events.ThrottleMessage
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func New(addressSimulator string, car *simulator.CarConfigMsg, racer *simulator.RacerBioMsg, camera *simulator.CamConfigMsg) *Gateway {
 | 
					func New(addressSimulator string, car *simulator.CarConfigMsg, racer *simulator.RacerBioMsg, camera *simulator.CamConfigMsg) (*Gateway, error) {
 | 
				
			||||||
	l := zap.S().With("simulator", addressSimulator)
 | 
						l := zap.S().With("simulator", addressSimulator)
 | 
				
			||||||
	l.Info("run gateway from simulator")
 | 
						l.Info("run gateway from simulator")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imgHeight, err := strconv.Atoi(camera.ImgH)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("invalid camera configuration, height should be a number: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						imgWidth, err := strconv.Atoi(camera.ImgW)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("invalid camera configuration, width should be a number: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &Gateway{
 | 
						return &Gateway{
 | 
				
			||||||
		address:              addressSimulator,
 | 
							address:              addressSimulator,
 | 
				
			||||||
		log:                  l,
 | 
							log:                  l,
 | 
				
			||||||
@@ -46,9 +60,11 @@ func New(addressSimulator string, car *simulator.CarConfigMsg, racer *simulator.
 | 
				
			|||||||
		racerSubscribers:     make(map[chan *simulator.Msg]interface{}),
 | 
							racerSubscribers:     make(map[chan *simulator.Msg]interface{}),
 | 
				
			||||||
		cameraSubscribers:    make(map[chan *simulator.Msg]interface{}),
 | 
							cameraSubscribers:    make(map[chan *simulator.Msg]interface{}),
 | 
				
			||||||
		carConfig:            car,
 | 
							carConfig:            car,
 | 
				
			||||||
 | 
							imgWidth:             imgWidth,
 | 
				
			||||||
 | 
							imgHeight:            imgHeight,
 | 
				
			||||||
		racer:                racer,
 | 
							racer:                racer,
 | 
				
			||||||
		cameraConfig:         camera,
 | 
							cameraConfig:         camera,
 | 
				
			||||||
	}
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Gateway is Simulator interface to events gateway frames into events topicFrame
 | 
					// Gateway is Simulator interface to events gateway frames into events topicFrame
 | 
				
			||||||
@@ -76,34 +92,46 @@ type Gateway struct {
 | 
				
			|||||||
	cameraSubscribers    map[chan *simulator.Msg]interface{}
 | 
						cameraSubscribers    map[chan *simulator.Msg]interface{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	carConfig    *simulator.CarConfigMsg
 | 
						carConfig    *simulator.CarConfigMsg
 | 
				
			||||||
 | 
						imgHeight    int
 | 
				
			||||||
 | 
						imgWidth     int
 | 
				
			||||||
	racer        *simulator.RacerBioMsg
 | 
						racer        *simulator.RacerBioMsg
 | 
				
			||||||
	cameraConfig *simulator.CamConfigMsg
 | 
						cameraConfig *simulator.CamConfigMsg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *Gateway) Start() error {
 | 
					func (g *Gateway) Start() error {
 | 
				
			||||||
	g.log.Info("connect to simulator")
 | 
						g.log.Info("connect to simulator")
 | 
				
			||||||
	g.cancel = make(chan interface{})
 | 
						g.cancel = make(chan interface{})
 | 
				
			||||||
	msgChan := g.subscribeTelemetryEvents()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go g.run()
 | 
						go g.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := g.writeRacerConfig()
 | 
						err := g.writeRacerConfig()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("unable to configure racer to server: %v", err)
 | 
							return fmt.Errorf("unable to configure racer to server: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = g.writeCarConfig()
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("unable to configure car to server: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = g.writeCameraConfig()
 | 
						err = g.writeCameraConfig()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("unable to configure camera to server: %v", err)
 | 
							return fmt.Errorf("unable to configure camera to server: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = g.writeCarConfig()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("unable to configure car to server: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgChan := g.subscribeTelemetryEvents()
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case msg := <-msgChan:
 | 
							case msg := <-msgChan:
 | 
				
			||||||
			fr := g.publishFrame(msg)
 | 
								g.log.Debug("try to publish frame")
 | 
				
			||||||
 | 
								fr, err := g.publishFrame(msg)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									zap.S().Errorf("unable to publish frame, ignore event %v: %v", msg, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								g.log.Debugf("frame published: %v", fr)
 | 
				
			||||||
			go g.publishInputSteering(msg, fr)
 | 
								go g.publishInputSteering(msg, fr)
 | 
				
			||||||
			go g.publishInputThrottle(msg, fr)
 | 
								go g.publishInputThrottle(msg, fr)
 | 
				
			||||||
		case <-g.cancel:
 | 
							case <-g.cancel:
 | 
				
			||||||
@@ -195,12 +223,20 @@ func (g *Gateway) listen() error {
 | 
				
			|||||||
		err = json.Unmarshal(rawLine, &msg)
 | 
							err = json.Unmarshal(rawLine, &msg)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			g.log.Errorf("unable to unmarshal simulator msg '%v': %v", string(rawLine), err)
 | 
								g.log.Errorf("unable to unmarshal simulator msg '%v': %v", string(rawLine), err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							g.log.Debugf("new message of type %v", string(msg.MsgType))
 | 
				
			||||||
		switch msg.MsgType {
 | 
							switch msg.MsgType {
 | 
				
			||||||
 | 
							case "":
 | 
				
			||||||
 | 
								g.log.Debug("ping")
 | 
				
			||||||
		case simulator.MsgTypeTelemetry:
 | 
							case simulator.MsgTypeTelemetry:
 | 
				
			||||||
			g.broadcastTelemetryMsg(rawLine)
 | 
								g.broadcastTelemetryMsg(rawLine)
 | 
				
			||||||
		case simulator.MsgTypeCarLoaded:
 | 
							case simulator.MsgTypeCarLoaded:
 | 
				
			||||||
 | 
								g.log.Debugf("car loaded: %v",string(rawLine))
 | 
				
			||||||
 | 
								if err := g.writeCarConfig(); err != nil{
 | 
				
			||||||
 | 
									zap.S().Errorf("unable to send car config: %v", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			g.broadcastCarMsg(rawLine)
 | 
								g.broadcastCarMsg(rawLine)
 | 
				
			||||||
		case simulator.MsgTypeRacerInfo:
 | 
							case simulator.MsgTypeRacerInfo:
 | 
				
			||||||
			g.broadcastRacerMsg(rawLine)
 | 
								g.broadcastRacerMsg(rawLine)
 | 
				
			||||||
@@ -211,50 +247,55 @@ func (g *Gateway) listen() error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *Gateway) broadcastTelemetryMsg(rawLine []byte) {
 | 
					func (g *Gateway) broadcastTelemetryMsg(rawLine []byte) {
 | 
				
			||||||
	for c := range g.telemetrySubscribers {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var tMsg simulator.TelemetryMsg
 | 
						var tMsg simulator.TelemetryMsg
 | 
				
			||||||
	err := json.Unmarshal(rawLine, &tMsg)
 | 
						err := json.Unmarshal(rawLine, &tMsg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		g.log.Errorf("unable to unmarshal telemetry simulator msg '%v': %v", string(rawLine), err)
 | 
							g.log.Errorf("unable to unmarshal telemetry simulator msg '%v': %v", string(rawLine), err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						g.log.Debugf("broadcast %d telemetry'", len(g.telemetrySubscribers))
 | 
				
			||||||
 | 
						for c := range g.telemetrySubscribers {
 | 
				
			||||||
 | 
							g.log.Debugf("broadcast telemetry ")
 | 
				
			||||||
		c <- &tMsg
 | 
							c <- &tMsg
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *Gateway) broadcastCarMsg(rawLine []byte) {
 | 
					func (g *Gateway) broadcastCarMsg(rawLine []byte) {
 | 
				
			||||||
	for c := range g.carSubscribers {
 | 
					 | 
				
			||||||
	var tMsg simulator.Msg
 | 
						var tMsg simulator.Msg
 | 
				
			||||||
	err := json.Unmarshal(rawLine, &tMsg)
 | 
						err := json.Unmarshal(rawLine, &tMsg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		g.log.Errorf("unable to unmarshal car simulator msg '%v': %v", string(rawLine), err)
 | 
							g.log.Errorf("unable to unmarshal car simulator msg '%v': %v", string(rawLine), err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						for c := range g.carSubscribers {
 | 
				
			||||||
		c <- &tMsg
 | 
							c <- &tMsg
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *Gateway) broadcastRacerMsg(rawLine []byte) {
 | 
					func (g *Gateway) broadcastRacerMsg(rawLine []byte) {
 | 
				
			||||||
	for c := range g.racerSubscribers {
 | 
					 | 
				
			||||||
	var tMsg simulator.Msg
 | 
						var tMsg simulator.Msg
 | 
				
			||||||
	err := json.Unmarshal(rawLine, &tMsg)
 | 
						err := json.Unmarshal(rawLine, &tMsg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		g.log.Errorf("unable to unmarshal racer simulator msg '%v': %v", string(rawLine), err)
 | 
							g.log.Errorf("unable to unmarshal racer simulator msg '%v': %v", string(rawLine), err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						for c := range g.racerSubscribers {
 | 
				
			||||||
		c <- &tMsg
 | 
							c <- &tMsg
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (g *Gateway) broadcastCameraMsg(rawLine []byte) {
 | 
					func (g *Gateway) broadcastCameraMsg(rawLine []byte) {
 | 
				
			||||||
	for c := range g.cameraSubscribers {
 | 
					 | 
				
			||||||
	var tMsg simulator.Msg
 | 
						var tMsg simulator.Msg
 | 
				
			||||||
	err := json.Unmarshal(rawLine, &tMsg)
 | 
						err := json.Unmarshal(rawLine, &tMsg)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		g.log.Errorf("unable to unmarshal camera simulator msg '%v': %v", string(rawLine), err)
 | 
							g.log.Errorf("unable to unmarshal camera simulator msg '%v': %v", string(rawLine), err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						for c := range g.cameraSubscribers {
 | 
				
			||||||
		c <- &tMsg
 | 
							c <- &tMsg
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *Gateway) publishFrame(msgSim *simulator.TelemetryMsg) *events.FrameRef {
 | 
					func (g *Gateway) publishFrame(msgSim *simulator.TelemetryMsg) (*events.FrameRef, error) {
 | 
				
			||||||
	now := time.Now()
 | 
						now := time.Now()
 | 
				
			||||||
	frameRef := &events.FrameRef{
 | 
						frameRef := &events.FrameRef{
 | 
				
			||||||
		Name: "gateway",
 | 
							Name: "gateway",
 | 
				
			||||||
@@ -264,17 +305,32 @@ func (g *Gateway) publishFrame(msgSim *simulator.TelemetryMsg) *events.FrameRef
 | 
				
			|||||||
			Nanos:   int32(now.Nanosecond()),
 | 
								Nanos:   int32(now.Nanosecond()),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg := &events.FrameMessage{
 | 
						msg := &events.FrameMessage{
 | 
				
			||||||
		Id:    frameRef,
 | 
							Id:    frameRef,
 | 
				
			||||||
		Frame: msgSim.Image,
 | 
							Frame: msgSim.Image,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g.log.Debugf("events frame '%v/%v'", msg.Id.Name, msg.Id.Id)
 | 
						img, _, err := image.Decode(bytes.NewReader(msgSim.Image))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("bad image, skip simulator event: %w", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if img.Bounds().Dy() != g.imgHeight || img.Bounds().Dx() != g.imgWidth {
 | 
				
			||||||
 | 
							zap.S().Debugf("resize simulator image from (%vx%v) -> (%dx%d)", img.Bounds().Dx(), img.Bounds().Dy(), g.imgWidth, g.imgHeight)
 | 
				
			||||||
 | 
							img = imaging.Resize(img, g.imgWidth, g.imgHeight, imaging.NearestNeighbor)
 | 
				
			||||||
 | 
							var imgBuf bytes.Buffer
 | 
				
			||||||
 | 
							err = jpeg.Encode(&imgBuf, img, nil)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("unable to encode to peg resized image: %w", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							msg.Frame = imgBuf.Bytes()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						g.log.Debugf("events frame '%v/%v'", msg.Id.Name, msg.Id.Id)
 | 
				
			||||||
	for fs := range g.frameSubscribers {
 | 
						for fs := range g.frameSubscribers {
 | 
				
			||||||
		fs <- msg
 | 
							fs <- msg
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return frameRef
 | 
						return frameRef, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (g *Gateway) publishInputSteering(msgSim *simulator.TelemetryMsg, frameRef *events.FrameRef) {
 | 
					func (g *Gateway) publishInputSteering(msgSim *simulator.TelemetryMsg, frameRef *events.FrameRef) {
 | 
				
			||||||
@@ -374,6 +430,7 @@ func (g *Gateway) WriteSteering(message *events.SteeringMessage) {
 | 
				
			|||||||
	g.initLastControlMsg()
 | 
						g.initLastControlMsg()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g.lastControl.Steering = fmt.Sprintf("%.2f", message.Steering)
 | 
						g.lastControl.Steering = fmt.Sprintf("%.2f", message.Steering)
 | 
				
			||||||
 | 
						zap.S().Debugf("steering updated: %v", g.lastControl.Steering)
 | 
				
			||||||
	g.writeControlCommandToSimulator()
 | 
						g.writeControlCommandToSimulator()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -401,7 +458,7 @@ func (g *Gateway) writeCommand(content []byte) error {
 | 
				
			|||||||
	g.log.Debugf("write command to simulator: %v", string(content))
 | 
						g.log.Debugf("write command to simulator: %v", string(content))
 | 
				
			||||||
	w := bufio.NewWriter(g.conn)
 | 
						w := bufio.NewWriter(g.conn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := w.Write(append(content, '\n'))
 | 
						_, err := w.Write(content)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("unable to write control msg \"%#v\" to simulator: %v", g.lastControl, err)
 | 
							return fmt.Errorf("unable to write control msg \"%#v\" to simulator: %v", g.lastControl, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -425,6 +482,7 @@ func (g *Gateway) WriteThrottle(message *events.ThrottleMessage) {
 | 
				
			|||||||
		g.lastControl.Brake = fmt.Sprintf("%.2f", -1*message.Throttle)
 | 
							g.lastControl.Brake = fmt.Sprintf("%.2f", -1*message.Throttle)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						zap.S().Debugf("throttle updated: %v, brake: %v", g.lastControl.Throttle, g.lastControl.Brake)
 | 
				
			||||||
	g.writeControlCommandToSimulator()
 | 
						g.writeControlCommandToSimulator()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -456,9 +514,13 @@ func (g *Gateway) writeCarConfig() error {
 | 
				
			|||||||
		return fmt.Errorf("unable to send car config to simulator: %v", err)
 | 
							return fmt.Errorf("unable to send car config to simulator: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg := <-carChan
 | 
						select {
 | 
				
			||||||
 | 
						case msg := <-carChan:
 | 
				
			||||||
		g.log.Infof("Car loaded: %v", msg)
 | 
							g.log.Infof("Car loaded: %v", msg)
 | 
				
			||||||
	time.Sleep(250 * time.Millisecond)
 | 
						case <-time.Tick(250 * time.Millisecond):
 | 
				
			||||||
 | 
							g.log.Info("no response after car loading")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -482,6 +544,7 @@ func (g *Gateway) writeRacerConfig() error {
 | 
				
			|||||||
	case msg := <-racerChan:
 | 
						case msg := <-racerChan:
 | 
				
			||||||
		g.log.Infof("Racer loaded: %v", msg)
 | 
							g.log.Infof("Racer loaded: %v", msg)
 | 
				
			||||||
	case <-time.Tick(250 * time.Millisecond):
 | 
						case <-time.Tick(250 * time.Millisecond):
 | 
				
			||||||
 | 
							g.log.Info("no response after racer loading")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -506,6 +569,7 @@ func (g *Gateway) writeCameraConfig() error {
 | 
				
			|||||||
	case msg := <-cameraChan:
 | 
						case msg := <-cameraChan:
 | 
				
			||||||
		g.log.Infof("Camera configured: %v", msg)
 | 
							g.log.Infof("Camera configured: %v", msg)
 | 
				
			||||||
	case <-time.Tick(250 * time.Millisecond):
 | 
						case <-time.Tick(250 * time.Millisecond):
 | 
				
			||||||
 | 
							g.log.Info("no response after camera loading")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,11 +25,14 @@ func TestGateway_ListenEvents(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gw := New(simulatorMock.Addr(),
 | 
						gw, err := New(simulatorMock.Addr(),
 | 
				
			||||||
		&simulator.CarConfigMsg{MsgType: simulator.MsgTypeCarConfig},
 | 
							&simulator.CarConfigMsg{MsgType: simulator.MsgTypeCarConfig},
 | 
				
			||||||
		&simulator.RacerBioMsg{},
 | 
							&simulator.RacerBioMsg{},
 | 
				
			||||||
		&simulator.CamConfigMsg{},
 | 
							&simulator.CamConfigMsg{},
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("unable to init test: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		err := gw.Start()
 | 
							err := gw.Start()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,4 +113,6 @@ type CamConfigMsg struct {
 | 
				
			|||||||
	OffsetY  string         `json:"offset_y"`
 | 
						OffsetY  string         `json:"offset_y"`
 | 
				
			||||||
	OffsetZ  string         `json:"offset_z"`
 | 
						OffsetZ  string         `json:"offset_z"`
 | 
				
			||||||
	RotX     string         `json:"rot_x"`
 | 
						RotX     string         `json:"rot_x"`
 | 
				
			||||||
 | 
						RotY     string         `json:"rot_y"`
 | 
				
			||||||
 | 
						RotZ     string         `json:"rot_z"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								vendor/github.com/disintegration/imaging/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/disintegration/imaging/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					language: go
 | 
				
			||||||
 | 
					go:
 | 
				
			||||||
 | 
					  - "1.10.x"
 | 
				
			||||||
 | 
					  - "1.11.x"
 | 
				
			||||||
 | 
					  - "1.12.x"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					before_install:
 | 
				
			||||||
 | 
					  - go get github.com/mattn/goveralls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					script:
 | 
				
			||||||
 | 
					  - go test -v -race -cover
 | 
				
			||||||
 | 
					  - $GOPATH/bin/goveralls -service=travis-ci
 | 
				
			||||||
							
								
								
									
										21
									
								
								vendor/github.com/disintegration/imaging/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/disintegration/imaging/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2012 Grigory Dryapak
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
							
								
								
									
										226
									
								
								vendor/github.com/disintegration/imaging/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								vendor/github.com/disintegration/imaging/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,226 @@
 | 
				
			|||||||
 | 
					# Imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[](https://godoc.org/github.com/disintegration/imaging)
 | 
				
			||||||
 | 
					[](https://travis-ci.org/disintegration/imaging)
 | 
				
			||||||
 | 
					[](https://coveralls.io/github/disintegration/imaging?branch=master)
 | 
				
			||||||
 | 
					[](https://goreportcard.com/report/github.com/disintegration/imaging)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All the image processing functions provided by the package accept any image type that implements `image.Image` interface
 | 
				
			||||||
 | 
					as an input, and return a new image of `*image.NRGBA` type (32bit RGBA colors, non-premultiplied alpha).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Installation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    go get -u github.com/disintegration/imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					http://godoc.org/github.com/disintegration/imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Usage examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A few usage examples can be found below. See the documentation for the full list of supported functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Image resizing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					// Resize srcImage to size = 128x128px using the Lanczos filter.
 | 
				
			||||||
 | 
					dstImage128 := imaging.Resize(srcImage, 128, 128, imaging.Lanczos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resize srcImage to width = 800px preserving the aspect ratio.
 | 
				
			||||||
 | 
					dstImage800 := imaging.Resize(srcImage, 800, 0, imaging.Lanczos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Scale down srcImage to fit the 800x600px bounding box.
 | 
				
			||||||
 | 
					dstImageFit := imaging.Fit(srcImage, 800, 600, imaging.Lanczos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resize and crop the srcImage to fill the 100x100px area.
 | 
				
			||||||
 | 
					dstImageFill := imaging.Fill(srcImage, 100, 100, imaging.Center, imaging.Lanczos)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Imaging supports image resizing using various resampling filters. The most notable ones:
 | 
				
			||||||
 | 
					- `Lanczos` - A high-quality resampling filter for photographic images yielding sharp results.
 | 
				
			||||||
 | 
					- `CatmullRom` - A sharp cubic filter that is faster than Lanczos filter while providing similar results.
 | 
				
			||||||
 | 
					- `MitchellNetravali` - A cubic filter that produces smoother results with less ringing artifacts than CatmullRom.
 | 
				
			||||||
 | 
					- `Linear` - Bilinear resampling filter, produces smooth output. Faster than cubic filters.
 | 
				
			||||||
 | 
					- `Box` - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor.
 | 
				
			||||||
 | 
					- `NearestNeighbor` - Fastest resampling filter, no antialiasing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The full list of supported filters:  NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. Custom filters can be created using ResampleFilter struct.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Resampling filters comparison**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The same image resized from 600x400px to 150x100px using different resampling filters.
 | 
				
			||||||
 | 
					From faster (lower quality) to slower (higher quality):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Filter                    | Resize result
 | 
				
			||||||
 | 
					--------------------------|---------------------------------------------
 | 
				
			||||||
 | 
					`imaging.NearestNeighbor` | 
 | 
				
			||||||
 | 
					`imaging.Linear`          | 
 | 
				
			||||||
 | 
					`imaging.CatmullRom`      | 
 | 
				
			||||||
 | 
					`imaging.Lanczos`         | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Gaussian Blur
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					dstImage := imaging.Blur(srcImage, 0.5)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sigma parameter allows to control the strength of the blurring effect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image                     | Sigma = 0.5                            | Sigma = 1.5
 | 
				
			||||||
 | 
					-----------------------------------|----------------------------------------|---------------------------------------
 | 
				
			||||||
 | 
					 |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Sharpening
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					dstImage := imaging.Sharpen(srcImage, 0.5)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`Sharpen` uses gaussian function internally. Sigma parameter allows to control the strength of the sharpening effect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image                     | Sigma = 0.5                               | Sigma = 1.5
 | 
				
			||||||
 | 
					-----------------------------------|-------------------------------------------|------------------------------------------
 | 
				
			||||||
 | 
					 |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Gamma correction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					dstImage := imaging.AdjustGamma(srcImage, 0.75)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image                     | Gamma = 0.75                             | Gamma = 1.25
 | 
				
			||||||
 | 
					-----------------------------------|------------------------------------------|-----------------------------------------
 | 
				
			||||||
 | 
					 |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Contrast adjustment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					dstImage := imaging.AdjustContrast(srcImage, 20)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image                     | Contrast = 15                              | Contrast = -15
 | 
				
			||||||
 | 
					-----------------------------------|--------------------------------------------|-------------------------------------------
 | 
				
			||||||
 | 
					 |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Brightness adjustment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					dstImage := imaging.AdjustBrightness(srcImage, 20)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image                     | Brightness = 10                              | Brightness = -10
 | 
				
			||||||
 | 
					-----------------------------------|----------------------------------------------|---------------------------------------------
 | 
				
			||||||
 | 
					 |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Saturation adjustment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					dstImage := imaging.AdjustSaturation(srcImage, 20)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Original image                     | Saturation = 30                              | Saturation = -30
 | 
				
			||||||
 | 
					-----------------------------------|----------------------------------------------|---------------------------------------------
 | 
				
			||||||
 | 
					 |  | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## FAQ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Incorrect image orientation after processing (e.g. an image appears rotated after resizing)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Most probably, the given image contains the EXIF orientation tag.
 | 
				
			||||||
 | 
					The stadard `image/*` packages do not support loading and saving
 | 
				
			||||||
 | 
					this kind of information. To fix the issue, try opening images with
 | 
				
			||||||
 | 
					the `AutoOrientation` decode option. If this option is set to `true`,
 | 
				
			||||||
 | 
					the image orientation is changed after decoding, according to the
 | 
				
			||||||
 | 
					orientation tag (if present). Here's the example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### What's the difference between `imaging` and `gift` packages?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[imaging](https://github.com/disintegration/imaging)
 | 
				
			||||||
 | 
					is designed to be a lightweight and simple image manipulation package.
 | 
				
			||||||
 | 
					It provides basic image processing functions and a few helper functions
 | 
				
			||||||
 | 
					such as `Open` and `Save`. It consistently returns *image.NRGBA image 
 | 
				
			||||||
 | 
					type (8 bits per channel, RGBA).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[gift](https://github.com/disintegration/gift)
 | 
				
			||||||
 | 
					supports more advanced image processing, for example, sRGB/Linear color
 | 
				
			||||||
 | 
					space conversions. It also supports different output image types
 | 
				
			||||||
 | 
					(e.g. 16 bits per channel) and provides easy-to-use API for chaining
 | 
				
			||||||
 | 
					multiple processing steps together.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Example code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```go
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/disintegration/imaging"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						// Open a test image.
 | 
				
			||||||
 | 
						src, err := imaging.Open("testdata/flowers.png")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("failed to open image: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Crop the original image to 300x300px size using the center anchor.
 | 
				
			||||||
 | 
						src = imaging.CropAnchor(src, 300, 300, imaging.Center)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Resize the cropped image to width = 200px preserving the aspect ratio.
 | 
				
			||||||
 | 
						src = imaging.Resize(src, 200, 0, imaging.Lanczos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create a blurred version of the image.
 | 
				
			||||||
 | 
						img1 := imaging.Blur(src, 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create a grayscale version of the image with higher contrast and sharpness.
 | 
				
			||||||
 | 
						img2 := imaging.Grayscale(src)
 | 
				
			||||||
 | 
						img2 = imaging.AdjustContrast(img2, 20)
 | 
				
			||||||
 | 
						img2 = imaging.Sharpen(img2, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create an inverted version of the image.
 | 
				
			||||||
 | 
						img3 := imaging.Invert(src)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create an embossed version of the image using a convolution filter.
 | 
				
			||||||
 | 
						img4 := imaging.Convolve3x3(
 | 
				
			||||||
 | 
							src,
 | 
				
			||||||
 | 
							[9]float64{
 | 
				
			||||||
 | 
								-1, -1, 0,
 | 
				
			||||||
 | 
								-1, 1, 1,
 | 
				
			||||||
 | 
								0, 1, 1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							nil,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create a new image and paste the four produced images into it.
 | 
				
			||||||
 | 
						dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0})
 | 
				
			||||||
 | 
						dst = imaging.Paste(dst, img1, image.Pt(0, 0))
 | 
				
			||||||
 | 
						dst = imaging.Paste(dst, img2, image.Pt(0, 200))
 | 
				
			||||||
 | 
						dst = imaging.Paste(dst, img3, image.Pt(200, 0))
 | 
				
			||||||
 | 
						dst = imaging.Paste(dst, img4, image.Pt(200, 200))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Save the resulting image as JPEG.
 | 
				
			||||||
 | 
						err = imaging.Save(dst, "testdata/out_example.jpg")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("failed to save image: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Output:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										253
									
								
								vendor/github.com/disintegration/imaging/adjust.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								vendor/github.com/disintegration/imaging/adjust.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,253 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Grayscale produces a grayscale version of the image.
 | 
				
			||||||
 | 
					func Grayscale(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								i := y * dst.Stride
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 | 
				
			||||||
 | 
								for x := 0; x < src.w; x++ {
 | 
				
			||||||
 | 
									d := dst.Pix[i : i+3 : i+3]
 | 
				
			||||||
 | 
									r := d[0]
 | 
				
			||||||
 | 
									g := d[1]
 | 
				
			||||||
 | 
									b := d[2]
 | 
				
			||||||
 | 
									f := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)
 | 
				
			||||||
 | 
									y := uint8(f + 0.5)
 | 
				
			||||||
 | 
									d[0] = y
 | 
				
			||||||
 | 
									d[1] = y
 | 
				
			||||||
 | 
									d[2] = y
 | 
				
			||||||
 | 
									i += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Invert produces an inverted (negated) version of the image.
 | 
				
			||||||
 | 
					func Invert(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								i := y * dst.Stride
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 | 
				
			||||||
 | 
								for x := 0; x < src.w; x++ {
 | 
				
			||||||
 | 
									d := dst.Pix[i : i+3 : i+3]
 | 
				
			||||||
 | 
									d[0] = 255 - d[0]
 | 
				
			||||||
 | 
									d[1] = 255 - d[1]
 | 
				
			||||||
 | 
									d[2] = 255 - d[2]
 | 
				
			||||||
 | 
									i += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AdjustSaturation changes the saturation of the image using the percentage parameter and returns the adjusted image.
 | 
				
			||||||
 | 
					// The percentage must be in the range (-100, 100).
 | 
				
			||||||
 | 
					// The percentage = 0 gives the original image.
 | 
				
			||||||
 | 
					// The percentage = 100 gives the image with the saturation value doubled for each pixel.
 | 
				
			||||||
 | 
					// The percentage = -100 gives the image with the saturation value zeroed for each pixel (grayscale).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//  dstImage = imaging.AdjustSaturation(srcImage, 25) // Increase image saturation by 25%.
 | 
				
			||||||
 | 
					//  dstImage = imaging.AdjustSaturation(srcImage, -10) // Decrease image saturation by 10%.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func AdjustSaturation(img image.Image, percentage float64) *image.NRGBA {
 | 
				
			||||||
 | 
						percentage = math.Min(math.Max(percentage, -100), 100)
 | 
				
			||||||
 | 
						multiplier := 1 + percentage/100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return AdjustFunc(img, func(c color.NRGBA) color.NRGBA {
 | 
				
			||||||
 | 
							h, s, l := rgbToHSL(c.R, c.G, c.B)
 | 
				
			||||||
 | 
							s *= multiplier
 | 
				
			||||||
 | 
							if s > 1 {
 | 
				
			||||||
 | 
								s = 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							r, g, b := hslToRGB(h, s, l)
 | 
				
			||||||
 | 
							return color.NRGBA{r, g, b, c.A}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image.
 | 
				
			||||||
 | 
					// The percentage must be in range (-100, 100). The percentage = 0 gives the original image.
 | 
				
			||||||
 | 
					// The percentage = -100 gives solid gray image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustContrast(srcImage, -10) // Decrease image contrast by 10%.
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustContrast(srcImage, 20) // Increase image contrast by 20%.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func AdjustContrast(img image.Image, percentage float64) *image.NRGBA {
 | 
				
			||||||
 | 
						percentage = math.Min(math.Max(percentage, -100.0), 100.0)
 | 
				
			||||||
 | 
						lut := make([]uint8, 256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						v := (100.0 + percentage) / 100.0
 | 
				
			||||||
 | 
						for i := 0; i < 256; i++ {
 | 
				
			||||||
 | 
							switch {
 | 
				
			||||||
 | 
							case 0 <= v && v <= 1:
 | 
				
			||||||
 | 
								lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0)
 | 
				
			||||||
 | 
							case 1 < v && v < 2:
 | 
				
			||||||
 | 
								lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0)
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								lut[i] = uint8(float64(i)/255.0+0.5) * 255
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adjustLUT(img, lut)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AdjustBrightness changes the brightness of the image using the percentage parameter and returns the adjusted image.
 | 
				
			||||||
 | 
					// The percentage must be in range (-100, 100). The percentage = 0 gives the original image.
 | 
				
			||||||
 | 
					// The percentage = -100 gives solid black image. The percentage = 100 gives solid white image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustBrightness(srcImage, -15) // Decrease image brightness by 15%.
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustBrightness(srcImage, 10) // Increase image brightness by 10%.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA {
 | 
				
			||||||
 | 
						percentage = math.Min(math.Max(percentage, -100.0), 100.0)
 | 
				
			||||||
 | 
						lut := make([]uint8, 256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						shift := 255.0 * percentage / 100.0
 | 
				
			||||||
 | 
						for i := 0; i < 256; i++ {
 | 
				
			||||||
 | 
							lut[i] = clamp(float64(i) + shift)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adjustLUT(img, lut)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AdjustGamma performs a gamma correction on the image and returns the adjusted image.
 | 
				
			||||||
 | 
					// Gamma parameter must be positive. Gamma = 1.0 gives the original image.
 | 
				
			||||||
 | 
					// Gamma less than 1.0 darkens the image and gamma greater than 1.0 lightens it.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustGamma(srcImage, 0.7)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func AdjustGamma(img image.Image, gamma float64) *image.NRGBA {
 | 
				
			||||||
 | 
						e := 1.0 / math.Max(gamma, 0.0001)
 | 
				
			||||||
 | 
						lut := make([]uint8, 256)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < 256; i++ {
 | 
				
			||||||
 | 
							lut[i] = clamp(math.Pow(float64(i)/255.0, e) * 255.0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adjustLUT(img, lut)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AdjustSigmoid changes the contrast of the image using a sigmoidal function and returns the adjusted image.
 | 
				
			||||||
 | 
					// It's a non-linear contrast change useful for photo adjustments as it preserves highlight and shadow detail.
 | 
				
			||||||
 | 
					// The midpoint parameter is the midpoint of contrast that must be between 0 and 1, typically 0.5.
 | 
				
			||||||
 | 
					// The factor parameter indicates how much to increase or decrease the contrast, typically in range (-10, 10).
 | 
				
			||||||
 | 
					// If the factor parameter is positive the image contrast is increased otherwise the contrast is decreased.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustSigmoid(srcImage, 0.5, 3.0) // Increase the contrast.
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustSigmoid(srcImage, 0.5, -3.0) // Decrease the contrast.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func AdjustSigmoid(img image.Image, midpoint, factor float64) *image.NRGBA {
 | 
				
			||||||
 | 
						if factor == 0 {
 | 
				
			||||||
 | 
							return Clone(img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lut := make([]uint8, 256)
 | 
				
			||||||
 | 
						a := math.Min(math.Max(midpoint, 0.0), 1.0)
 | 
				
			||||||
 | 
						b := math.Abs(factor)
 | 
				
			||||||
 | 
						sig0 := sigmoid(a, b, 0)
 | 
				
			||||||
 | 
						sig1 := sigmoid(a, b, 1)
 | 
				
			||||||
 | 
						e := 1.0e-6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if factor > 0 {
 | 
				
			||||||
 | 
							for i := 0; i < 256; i++ {
 | 
				
			||||||
 | 
								x := float64(i) / 255.0
 | 
				
			||||||
 | 
								sigX := sigmoid(a, b, x)
 | 
				
			||||||
 | 
								f := (sigX - sig0) / (sig1 - sig0)
 | 
				
			||||||
 | 
								lut[i] = clamp(f * 255.0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for i := 0; i < 256; i++ {
 | 
				
			||||||
 | 
								x := float64(i) / 255.0
 | 
				
			||||||
 | 
								arg := math.Min(math.Max((sig1-sig0)*x+sig0, e), 1.0-e)
 | 
				
			||||||
 | 
								f := a - math.Log(1.0/arg-1.0)/b
 | 
				
			||||||
 | 
								lut[i] = clamp(f * 255.0)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return adjustLUT(img, lut)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sigmoid(a, b, x float64) float64 {
 | 
				
			||||||
 | 
						return 1 / (1 + math.Exp(b*(a-x)))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// adjustLUT applies the given lookup table to the colors of the image.
 | 
				
			||||||
 | 
					func adjustLUT(img image.Image, lut []uint8) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						lut = lut[0:256]
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								i := y * dst.Stride
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 | 
				
			||||||
 | 
								for x := 0; x < src.w; x++ {
 | 
				
			||||||
 | 
									d := dst.Pix[i : i+3 : i+3]
 | 
				
			||||||
 | 
									d[0] = lut[d[0]]
 | 
				
			||||||
 | 
									d[1] = lut[d[1]]
 | 
				
			||||||
 | 
									d[2] = lut[d[2]]
 | 
				
			||||||
 | 
									i += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AdjustFunc applies the fn function to each pixel of the img image and returns the adjusted image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage = imaging.AdjustFunc(
 | 
				
			||||||
 | 
					//		srcImage,
 | 
				
			||||||
 | 
					//		func(c color.NRGBA) color.NRGBA {
 | 
				
			||||||
 | 
					//			// Shift the red channel by 16.
 | 
				
			||||||
 | 
					//			r := int(c.R) + 16
 | 
				
			||||||
 | 
					//			if r > 255 {
 | 
				
			||||||
 | 
					//				r = 255
 | 
				
			||||||
 | 
					//			}
 | 
				
			||||||
 | 
					//			return color.NRGBA{uint8(r), c.G, c.B, c.A}
 | 
				
			||||||
 | 
					//		}
 | 
				
			||||||
 | 
					//	)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func AdjustFunc(img image.Image, fn func(c color.NRGBA) color.NRGBA) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								i := y * dst.Stride
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4])
 | 
				
			||||||
 | 
								for x := 0; x < src.w; x++ {
 | 
				
			||||||
 | 
									d := dst.Pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
									r := d[0]
 | 
				
			||||||
 | 
									g := d[1]
 | 
				
			||||||
 | 
									b := d[2]
 | 
				
			||||||
 | 
									a := d[3]
 | 
				
			||||||
 | 
									c := fn(color.NRGBA{r, g, b, a})
 | 
				
			||||||
 | 
									d[0] = c.R
 | 
				
			||||||
 | 
									d[1] = c.G
 | 
				
			||||||
 | 
									d[2] = c.B
 | 
				
			||||||
 | 
									d[3] = c.A
 | 
				
			||||||
 | 
									i += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										148
									
								
								vendor/github.com/disintegration/imaging/convolution.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								vendor/github.com/disintegration/imaging/convolution.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ConvolveOptions are convolution parameters.
 | 
				
			||||||
 | 
					type ConvolveOptions struct {
 | 
				
			||||||
 | 
						// If Normalize is true the kernel is normalized before convolution.
 | 
				
			||||||
 | 
						Normalize bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If Abs is true the absolute value of each color channel is taken after convolution.
 | 
				
			||||||
 | 
						Abs bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Bias is added to each color channel value after convolution.
 | 
				
			||||||
 | 
						Bias int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convolve3x3 convolves the image with the specified 3x3 convolution kernel.
 | 
				
			||||||
 | 
					// Default parameters are used if a nil *ConvolveOptions is passed.
 | 
				
			||||||
 | 
					func Convolve3x3(img image.Image, kernel [9]float64, options *ConvolveOptions) *image.NRGBA {
 | 
				
			||||||
 | 
						return convolve(img, kernel[:], options)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convolve5x5 convolves the image with the specified 5x5 convolution kernel.
 | 
				
			||||||
 | 
					// Default parameters are used if a nil *ConvolveOptions is passed.
 | 
				
			||||||
 | 
					func Convolve5x5(img image.Image, kernel [25]float64, options *ConvolveOptions) *image.NRGBA {
 | 
				
			||||||
 | 
						return convolve(img, kernel[:], options)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *image.NRGBA {
 | 
				
			||||||
 | 
						src := toNRGBA(img)
 | 
				
			||||||
 | 
						w := src.Bounds().Max.X
 | 
				
			||||||
 | 
						h := src.Bounds().Max.Y
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, w, h))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if w < 1 || h < 1 {
 | 
				
			||||||
 | 
							return dst
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if options == nil {
 | 
				
			||||||
 | 
							options = &ConvolveOptions{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if options.Normalize {
 | 
				
			||||||
 | 
							normalizeKernel(kernel)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						type coef struct {
 | 
				
			||||||
 | 
							x, y int
 | 
				
			||||||
 | 
							k    float64
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var coefs []coef
 | 
				
			||||||
 | 
						var m int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch len(kernel) {
 | 
				
			||||||
 | 
						case 9:
 | 
				
			||||||
 | 
							m = 1
 | 
				
			||||||
 | 
						case 25:
 | 
				
			||||||
 | 
							m = 2
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i := 0
 | 
				
			||||||
 | 
						for y := -m; y <= m; y++ {
 | 
				
			||||||
 | 
							for x := -m; x <= m; x++ {
 | 
				
			||||||
 | 
								if kernel[i] != 0 {
 | 
				
			||||||
 | 
									coefs = append(coefs, coef{x: x, y: y, k: kernel[i]})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								i++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parallel(0, h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								for x := 0; x < w; x++ {
 | 
				
			||||||
 | 
									var r, g, b float64
 | 
				
			||||||
 | 
									for _, c := range coefs {
 | 
				
			||||||
 | 
										ix := x + c.x
 | 
				
			||||||
 | 
										if ix < 0 {
 | 
				
			||||||
 | 
											ix = 0
 | 
				
			||||||
 | 
										} else if ix >= w {
 | 
				
			||||||
 | 
											ix = w - 1
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										iy := y + c.y
 | 
				
			||||||
 | 
										if iy < 0 {
 | 
				
			||||||
 | 
											iy = 0
 | 
				
			||||||
 | 
										} else if iy >= h {
 | 
				
			||||||
 | 
											iy = h - 1
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										off := iy*src.Stride + ix*4
 | 
				
			||||||
 | 
										s := src.Pix[off : off+3 : off+3]
 | 
				
			||||||
 | 
										r += float64(s[0]) * c.k
 | 
				
			||||||
 | 
										g += float64(s[1]) * c.k
 | 
				
			||||||
 | 
										b += float64(s[2]) * c.k
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if options.Abs {
 | 
				
			||||||
 | 
										if r < 0 {
 | 
				
			||||||
 | 
											r = -r
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if g < 0 {
 | 
				
			||||||
 | 
											g = -g
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if b < 0 {
 | 
				
			||||||
 | 
											b = -b
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if options.Bias != 0 {
 | 
				
			||||||
 | 
										r += float64(options.Bias)
 | 
				
			||||||
 | 
										g += float64(options.Bias)
 | 
				
			||||||
 | 
										b += float64(options.Bias)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									srcOff := y*src.Stride + x*4
 | 
				
			||||||
 | 
									dstOff := y*dst.Stride + x*4
 | 
				
			||||||
 | 
									d := dst.Pix[dstOff : dstOff+4 : dstOff+4]
 | 
				
			||||||
 | 
									d[0] = clamp(r)
 | 
				
			||||||
 | 
									d[1] = clamp(g)
 | 
				
			||||||
 | 
									d[2] = clamp(b)
 | 
				
			||||||
 | 
									d[3] = src.Pix[srcOff+3]
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func normalizeKernel(kernel []float64) {
 | 
				
			||||||
 | 
						var sum, sumpos float64
 | 
				
			||||||
 | 
						for i := range kernel {
 | 
				
			||||||
 | 
							sum += kernel[i]
 | 
				
			||||||
 | 
							if kernel[i] > 0 {
 | 
				
			||||||
 | 
								sumpos += kernel[i]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if sum != 0 {
 | 
				
			||||||
 | 
							for i := range kernel {
 | 
				
			||||||
 | 
								kernel[i] /= sum
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if sumpos != 0 {
 | 
				
			||||||
 | 
							for i := range kernel {
 | 
				
			||||||
 | 
								kernel[i] /= sumpos
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								vendor/github.com/disintegration/imaging/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/disintegration/imaging/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All the image processing functions provided by the package accept any image type that implements image.Image interface
 | 
				
			||||||
 | 
					as an input, and return a new image of *image.NRGBA type (32bit RGBA colors, non-premultiplied alpha).
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					package imaging
 | 
				
			||||||
							
								
								
									
										169
									
								
								vendor/github.com/disintegration/imaging/effects.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/github.com/disintegration/imaging/effects.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func gaussianBlurKernel(x, sigma float64) float64 {
 | 
				
			||||||
 | 
						return math.Exp(-(x*x)/(2*sigma*sigma)) / (sigma * math.Sqrt(2*math.Pi))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Blur produces a blurred version of the image using a Gaussian function.
 | 
				
			||||||
 | 
					// Sigma parameter must be positive and indicates how much the image will be blurred.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage := imaging.Blur(srcImage, 3.5)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Blur(img image.Image, sigma float64) *image.NRGBA {
 | 
				
			||||||
 | 
						if sigma <= 0 {
 | 
				
			||||||
 | 
							return Clone(img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						radius := int(math.Ceil(sigma * 3.0))
 | 
				
			||||||
 | 
						kernel := make([]float64, radius+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i <= radius; i++ {
 | 
				
			||||||
 | 
							kernel[i] = gaussianBlurKernel(float64(i), sigma)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return blurVertical(blurHorizontal(img, kernel), kernel)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						radius := len(kernel) - 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							scanLine := make([]uint8, src.w*4)
 | 
				
			||||||
 | 
							scanLineF := make([]float64, len(scanLine))
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, scanLine)
 | 
				
			||||||
 | 
								for i, v := range scanLine {
 | 
				
			||||||
 | 
									scanLineF[i] = float64(v)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for x := 0; x < src.w; x++ {
 | 
				
			||||||
 | 
									min := x - radius
 | 
				
			||||||
 | 
									if min < 0 {
 | 
				
			||||||
 | 
										min = 0
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									max := x + radius
 | 
				
			||||||
 | 
									if max > src.w-1 {
 | 
				
			||||||
 | 
										max = src.w - 1
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var r, g, b, a, wsum float64
 | 
				
			||||||
 | 
									for ix := min; ix <= max; ix++ {
 | 
				
			||||||
 | 
										i := ix * 4
 | 
				
			||||||
 | 
										weight := kernel[absint(x-ix)]
 | 
				
			||||||
 | 
										wsum += weight
 | 
				
			||||||
 | 
										s := scanLineF[i : i+4 : i+4]
 | 
				
			||||||
 | 
										wa := s[3] * weight
 | 
				
			||||||
 | 
										r += s[0] * wa
 | 
				
			||||||
 | 
										g += s[1] * wa
 | 
				
			||||||
 | 
										b += s[2] * wa
 | 
				
			||||||
 | 
										a += wa
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if a != 0 {
 | 
				
			||||||
 | 
										aInv := 1 / a
 | 
				
			||||||
 | 
										j := y*dst.Stride + x*4
 | 
				
			||||||
 | 
										d := dst.Pix[j : j+4 : j+4]
 | 
				
			||||||
 | 
										d[0] = clamp(r * aInv)
 | 
				
			||||||
 | 
										d[1] = clamp(g * aInv)
 | 
				
			||||||
 | 
										d[2] = clamp(b * aInv)
 | 
				
			||||||
 | 
										d[3] = clamp(a / wsum)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						radius := len(kernel) - 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parallel(0, src.w, func(xs <-chan int) {
 | 
				
			||||||
 | 
							scanLine := make([]uint8, src.h*4)
 | 
				
			||||||
 | 
							scanLineF := make([]float64, len(scanLine))
 | 
				
			||||||
 | 
							for x := range xs {
 | 
				
			||||||
 | 
								src.scan(x, 0, x+1, src.h, scanLine)
 | 
				
			||||||
 | 
								for i, v := range scanLine {
 | 
				
			||||||
 | 
									scanLineF[i] = float64(v)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for y := 0; y < src.h; y++ {
 | 
				
			||||||
 | 
									min := y - radius
 | 
				
			||||||
 | 
									if min < 0 {
 | 
				
			||||||
 | 
										min = 0
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									max := y + radius
 | 
				
			||||||
 | 
									if max > src.h-1 {
 | 
				
			||||||
 | 
										max = src.h - 1
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var r, g, b, a, wsum float64
 | 
				
			||||||
 | 
									for iy := min; iy <= max; iy++ {
 | 
				
			||||||
 | 
										i := iy * 4
 | 
				
			||||||
 | 
										weight := kernel[absint(y-iy)]
 | 
				
			||||||
 | 
										wsum += weight
 | 
				
			||||||
 | 
										s := scanLineF[i : i+4 : i+4]
 | 
				
			||||||
 | 
										wa := s[3] * weight
 | 
				
			||||||
 | 
										r += s[0] * wa
 | 
				
			||||||
 | 
										g += s[1] * wa
 | 
				
			||||||
 | 
										b += s[2] * wa
 | 
				
			||||||
 | 
										a += wa
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if a != 0 {
 | 
				
			||||||
 | 
										aInv := 1 / a
 | 
				
			||||||
 | 
										j := y*dst.Stride + x*4
 | 
				
			||||||
 | 
										d := dst.Pix[j : j+4 : j+4]
 | 
				
			||||||
 | 
										d[0] = clamp(r * aInv)
 | 
				
			||||||
 | 
										d[1] = clamp(g * aInv)
 | 
				
			||||||
 | 
										d[2] = clamp(b * aInv)
 | 
				
			||||||
 | 
										d[3] = clamp(a / wsum)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sharpen produces a sharpened version of the image.
 | 
				
			||||||
 | 
					// Sigma parameter must be positive and indicates how much the image will be sharpened.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage := imaging.Sharpen(srcImage, 3.5)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Sharpen(img image.Image, sigma float64) *image.NRGBA {
 | 
				
			||||||
 | 
						if sigma <= 0 {
 | 
				
			||||||
 | 
							return Clone(img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						blurred := Blur(img, sigma)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							scanLine := make([]uint8, src.w*4)
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, scanLine)
 | 
				
			||||||
 | 
								j := y * dst.Stride
 | 
				
			||||||
 | 
								for i := 0; i < src.w*4; i++ {
 | 
				
			||||||
 | 
									val := int(scanLine[i])<<1 - int(blurred.Pix[j])
 | 
				
			||||||
 | 
									if val < 0 {
 | 
				
			||||||
 | 
										val = 0
 | 
				
			||||||
 | 
									} else if val > 0xff {
 | 
				
			||||||
 | 
										val = 0xff
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dst.Pix[j] = uint8(val)
 | 
				
			||||||
 | 
									j++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								vendor/github.com/disintegration/imaging/histogram.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/disintegration/imaging/histogram.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Histogram returns a normalized histogram of an image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Resulting histogram is represented as an array of 256 floats, where
 | 
				
			||||||
 | 
					// histogram[i] is a probability of a pixel being of a particular luminance i.
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										444
									
								
								vendor/github.com/disintegration/imaging/io.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								vendor/github.com/disintegration/imaging/io.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,444 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/draw"
 | 
				
			||||||
 | 
						"image/gif"
 | 
				
			||||||
 | 
						"image/jpeg"
 | 
				
			||||||
 | 
						"image/png"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/image/bmp"
 | 
				
			||||||
 | 
						"golang.org/x/image/tiff"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type fileSystem interface {
 | 
				
			||||||
 | 
						Create(string) (io.WriteCloser, error)
 | 
				
			||||||
 | 
						Open(string) (io.ReadCloser, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type localFS struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) }
 | 
				
			||||||
 | 
					func (localFS) Open(name string) (io.ReadCloser, error)    { return os.Open(name) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var fs fileSystem = localFS{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type decodeConfig struct {
 | 
				
			||||||
 | 
						autoOrientation bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var defaultDecodeConfig = decodeConfig{
 | 
				
			||||||
 | 
						autoOrientation: false,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeOption sets an optional parameter for the Decode and Open functions.
 | 
				
			||||||
 | 
					type DecodeOption func(*decodeConfig)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AutoOrientation returns a DecodeOption that sets the auto-orientation mode.
 | 
				
			||||||
 | 
					// If auto-orientation is enabled, the image will be transformed after decoding
 | 
				
			||||||
 | 
					// according to the EXIF orientation tag (if present). By default it's disabled.
 | 
				
			||||||
 | 
					func AutoOrientation(enabled bool) DecodeOption {
 | 
				
			||||||
 | 
						return func(c *decodeConfig) {
 | 
				
			||||||
 | 
							c.autoOrientation = enabled
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decode reads an image from r.
 | 
				
			||||||
 | 
					func Decode(r io.Reader, opts ...DecodeOption) (image.Image, error) {
 | 
				
			||||||
 | 
						cfg := defaultDecodeConfig
 | 
				
			||||||
 | 
						for _, option := range opts {
 | 
				
			||||||
 | 
							option(&cfg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !cfg.autoOrientation {
 | 
				
			||||||
 | 
							img, _, err := image.Decode(r)
 | 
				
			||||||
 | 
							return img, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var orient orientation
 | 
				
			||||||
 | 
						pr, pw := io.Pipe()
 | 
				
			||||||
 | 
						r = io.TeeReader(r, pw)
 | 
				
			||||||
 | 
						done := make(chan struct{})
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer close(done)
 | 
				
			||||||
 | 
							orient = readOrientation(pr)
 | 
				
			||||||
 | 
							io.Copy(ioutil.Discard, pr)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						img, _, err := image.Decode(r)
 | 
				
			||||||
 | 
						pw.Close()
 | 
				
			||||||
 | 
						<-done
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fixOrientation(img, orient), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Open loads an image from file.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// Load an image from file.
 | 
				
			||||||
 | 
					//	img, err := imaging.Open("test.jpg")
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// Load an image and transform it depending on the EXIF orientation tag (if present).
 | 
				
			||||||
 | 
					//	img, err := imaging.Open("test.jpg", imaging.AutoOrientation(true))
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Open(filename string, opts ...DecodeOption) (image.Image, error) {
 | 
				
			||||||
 | 
						file, err := fs.Open(filename)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer file.Close()
 | 
				
			||||||
 | 
						return Decode(file, opts...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Format is an image file format.
 | 
				
			||||||
 | 
					type Format int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Image file formats.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						JPEG Format = iota
 | 
				
			||||||
 | 
						PNG
 | 
				
			||||||
 | 
						GIF
 | 
				
			||||||
 | 
						TIFF
 | 
				
			||||||
 | 
						BMP
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var formatExts = map[string]Format{
 | 
				
			||||||
 | 
						"jpg":  JPEG,
 | 
				
			||||||
 | 
						"jpeg": JPEG,
 | 
				
			||||||
 | 
						"png":  PNG,
 | 
				
			||||||
 | 
						"gif":  GIF,
 | 
				
			||||||
 | 
						"tif":  TIFF,
 | 
				
			||||||
 | 
						"tiff": TIFF,
 | 
				
			||||||
 | 
						"bmp":  BMP,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var formatNames = map[Format]string{
 | 
				
			||||||
 | 
						JPEG: "JPEG",
 | 
				
			||||||
 | 
						PNG:  "PNG",
 | 
				
			||||||
 | 
						GIF:  "GIF",
 | 
				
			||||||
 | 
						TIFF: "TIFF",
 | 
				
			||||||
 | 
						BMP:  "BMP",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (f Format) String() string {
 | 
				
			||||||
 | 
						return formatNames[f]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrUnsupportedFormat means the given image format is not supported.
 | 
				
			||||||
 | 
					var ErrUnsupportedFormat = errors.New("imaging: unsupported image format")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FormatFromExtension parses image format from filename extension:
 | 
				
			||||||
 | 
					// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
 | 
				
			||||||
 | 
					func FormatFromExtension(ext string) (Format, error) {
 | 
				
			||||||
 | 
						if f, ok := formatExts[strings.ToLower(strings.TrimPrefix(ext, "."))]; ok {
 | 
				
			||||||
 | 
							return f, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -1, ErrUnsupportedFormat
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FormatFromFilename parses image format from filename:
 | 
				
			||||||
 | 
					// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
 | 
				
			||||||
 | 
					func FormatFromFilename(filename string) (Format, error) {
 | 
				
			||||||
 | 
						ext := filepath.Ext(filename)
 | 
				
			||||||
 | 
						return FormatFromExtension(ext)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type encodeConfig struct {
 | 
				
			||||||
 | 
						jpegQuality         int
 | 
				
			||||||
 | 
						gifNumColors        int
 | 
				
			||||||
 | 
						gifQuantizer        draw.Quantizer
 | 
				
			||||||
 | 
						gifDrawer           draw.Drawer
 | 
				
			||||||
 | 
						pngCompressionLevel png.CompressionLevel
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var defaultEncodeConfig = encodeConfig{
 | 
				
			||||||
 | 
						jpegQuality:         95,
 | 
				
			||||||
 | 
						gifNumColors:        256,
 | 
				
			||||||
 | 
						gifQuantizer:        nil,
 | 
				
			||||||
 | 
						gifDrawer:           nil,
 | 
				
			||||||
 | 
						pngCompressionLevel: png.DefaultCompression,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// EncodeOption sets an optional parameter for the Encode and Save functions.
 | 
				
			||||||
 | 
					type EncodeOption func(*encodeConfig)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// JPEGQuality returns an EncodeOption that sets the output JPEG quality.
 | 
				
			||||||
 | 
					// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95.
 | 
				
			||||||
 | 
					func JPEGQuality(quality int) EncodeOption {
 | 
				
			||||||
 | 
						return func(c *encodeConfig) {
 | 
				
			||||||
 | 
							c.jpegQuality = quality
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GIFNumColors returns an EncodeOption that sets the maximum number of colors
 | 
				
			||||||
 | 
					// used in the GIF-encoded image. It ranges from 1 to 256.  Default is 256.
 | 
				
			||||||
 | 
					func GIFNumColors(numColors int) EncodeOption {
 | 
				
			||||||
 | 
						return func(c *encodeConfig) {
 | 
				
			||||||
 | 
							c.gifNumColors = numColors
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
 | 
				
			||||||
 | 
					// a palette of the GIF-encoded image.
 | 
				
			||||||
 | 
					func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
 | 
				
			||||||
 | 
						return func(c *encodeConfig) {
 | 
				
			||||||
 | 
							c.gifQuantizer = quantizer
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
 | 
				
			||||||
 | 
					// the source image to the desired palette of the GIF-encoded image.
 | 
				
			||||||
 | 
					func GIFDrawer(drawer draw.Drawer) EncodeOption {
 | 
				
			||||||
 | 
						return func(c *encodeConfig) {
 | 
				
			||||||
 | 
							c.gifDrawer = drawer
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PNGCompressionLevel returns an EncodeOption that sets the compression level
 | 
				
			||||||
 | 
					// of the PNG-encoded image. Default is png.DefaultCompression.
 | 
				
			||||||
 | 
					func PNGCompressionLevel(level png.CompressionLevel) EncodeOption {
 | 
				
			||||||
 | 
						return func(c *encodeConfig) {
 | 
				
			||||||
 | 
							c.pngCompressionLevel = level
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
 | 
				
			||||||
 | 
					func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
 | 
				
			||||||
 | 
						cfg := defaultEncodeConfig
 | 
				
			||||||
 | 
						for _, option := range opts {
 | 
				
			||||||
 | 
							option(&cfg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch format {
 | 
				
			||||||
 | 
						case JPEG:
 | 
				
			||||||
 | 
							if nrgba, ok := img.(*image.NRGBA); ok && nrgba.Opaque() {
 | 
				
			||||||
 | 
								rgba := &image.RGBA{
 | 
				
			||||||
 | 
									Pix:    nrgba.Pix,
 | 
				
			||||||
 | 
									Stride: nrgba.Stride,
 | 
				
			||||||
 | 
									Rect:   nrgba.Rect,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case PNG:
 | 
				
			||||||
 | 
							encoder := png.Encoder{CompressionLevel: cfg.pngCompressionLevel}
 | 
				
			||||||
 | 
							return encoder.Encode(w, img)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case GIF:
 | 
				
			||||||
 | 
							return gif.Encode(w, img, &gif.Options{
 | 
				
			||||||
 | 
								NumColors: cfg.gifNumColors,
 | 
				
			||||||
 | 
								Quantizer: cfg.gifQuantizer,
 | 
				
			||||||
 | 
								Drawer:    cfg.gifDrawer,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case TIFF:
 | 
				
			||||||
 | 
							return tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case BMP:
 | 
				
			||||||
 | 
							return bmp.Encode(w, img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ErrUnsupportedFormat
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Save saves the image to file with the specified filename.
 | 
				
			||||||
 | 
					// The format is determined from the filename extension:
 | 
				
			||||||
 | 
					// "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// Save the image as PNG.
 | 
				
			||||||
 | 
					//	err := imaging.Save(img, "out.png")
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// Save the image as JPEG with optional quality parameter set to 80.
 | 
				
			||||||
 | 
					//	err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80))
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Save(img image.Image, filename string, opts ...EncodeOption) (err error) {
 | 
				
			||||||
 | 
						f, err := FormatFromFilename(filename)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						file, err := fs.Create(filename)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = Encode(file, img, f, opts...)
 | 
				
			||||||
 | 
						errc := file.Close()
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							err = errc
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// orientation is an EXIF flag that specifies the transformation
 | 
				
			||||||
 | 
					// that should be applied to image to display it correctly.
 | 
				
			||||||
 | 
					type orientation int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						orientationUnspecified = 0
 | 
				
			||||||
 | 
						orientationNormal      = 1
 | 
				
			||||||
 | 
						orientationFlipH       = 2
 | 
				
			||||||
 | 
						orientationRotate180   = 3
 | 
				
			||||||
 | 
						orientationFlipV       = 4
 | 
				
			||||||
 | 
						orientationTranspose   = 5
 | 
				
			||||||
 | 
						orientationRotate270   = 6
 | 
				
			||||||
 | 
						orientationTransverse  = 7
 | 
				
			||||||
 | 
						orientationRotate90    = 8
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// readOrientation tries to read the orientation EXIF flag from image data in r.
 | 
				
			||||||
 | 
					// If the EXIF data block is not found or the orientation flag is not found
 | 
				
			||||||
 | 
					// or any other error occures while reading the data, it returns the
 | 
				
			||||||
 | 
					// orientationUnspecified (0) value.
 | 
				
			||||||
 | 
					func readOrientation(r io.Reader) orientation {
 | 
				
			||||||
 | 
						const (
 | 
				
			||||||
 | 
							markerSOI      = 0xffd8
 | 
				
			||||||
 | 
							markerAPP1     = 0xffe1
 | 
				
			||||||
 | 
							exifHeader     = 0x45786966
 | 
				
			||||||
 | 
							byteOrderBE    = 0x4d4d
 | 
				
			||||||
 | 
							byteOrderLE    = 0x4949
 | 
				
			||||||
 | 
							orientationTag = 0x0112
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check if JPEG SOI marker is present.
 | 
				
			||||||
 | 
						var soi uint16
 | 
				
			||||||
 | 
						if err := binary.Read(r, binary.BigEndian, &soi); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if soi != markerSOI {
 | 
				
			||||||
 | 
							return orientationUnspecified // Missing JPEG SOI marker.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Find JPEG APP1 marker.
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							var marker, size uint16
 | 
				
			||||||
 | 
							if err := binary.Read(r, binary.BigEndian, &marker); err != nil {
 | 
				
			||||||
 | 
								return orientationUnspecified
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err := binary.Read(r, binary.BigEndian, &size); err != nil {
 | 
				
			||||||
 | 
								return orientationUnspecified
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if marker>>8 != 0xff {
 | 
				
			||||||
 | 
								return orientationUnspecified // Invalid JPEG marker.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if marker == markerAPP1 {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if size < 2 {
 | 
				
			||||||
 | 
								return orientationUnspecified // Invalid block size.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := io.CopyN(ioutil.Discard, r, int64(size-2)); err != nil {
 | 
				
			||||||
 | 
								return orientationUnspecified
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check if EXIF header is present.
 | 
				
			||||||
 | 
						var header uint32
 | 
				
			||||||
 | 
						if err := binary.Read(r, binary.BigEndian, &header); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if header != exifHeader {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Read byte order information.
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							byteOrderTag uint16
 | 
				
			||||||
 | 
							byteOrder    binary.ByteOrder
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if err := binary.Read(r, binary.BigEndian, &byteOrderTag); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch byteOrderTag {
 | 
				
			||||||
 | 
						case byteOrderBE:
 | 
				
			||||||
 | 
							byteOrder = binary.BigEndian
 | 
				
			||||||
 | 
						case byteOrderLE:
 | 
				
			||||||
 | 
							byteOrder = binary.LittleEndian
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return orientationUnspecified // Invalid byte order flag.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := io.CopyN(ioutil.Discard, r, 2); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Skip the EXIF offset.
 | 
				
			||||||
 | 
						var offset uint32
 | 
				
			||||||
 | 
						if err := binary.Read(r, byteOrder, &offset); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if offset < 8 {
 | 
				
			||||||
 | 
							return orientationUnspecified // Invalid offset value.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := io.CopyN(ioutil.Discard, r, int64(offset-8)); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Read the number of tags.
 | 
				
			||||||
 | 
						var numTags uint16
 | 
				
			||||||
 | 
						if err := binary.Read(r, byteOrder, &numTags); err != nil {
 | 
				
			||||||
 | 
							return orientationUnspecified
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Find the orientation tag.
 | 
				
			||||||
 | 
						for i := 0; i < int(numTags); i++ {
 | 
				
			||||||
 | 
							var tag uint16
 | 
				
			||||||
 | 
							if err := binary.Read(r, byteOrder, &tag); err != nil {
 | 
				
			||||||
 | 
								return orientationUnspecified
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if tag != orientationTag {
 | 
				
			||||||
 | 
								if _, err := io.CopyN(ioutil.Discard, r, 10); err != nil {
 | 
				
			||||||
 | 
									return orientationUnspecified
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := io.CopyN(ioutil.Discard, r, 6); err != nil {
 | 
				
			||||||
 | 
								return orientationUnspecified
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var val uint16
 | 
				
			||||||
 | 
							if err := binary.Read(r, byteOrder, &val); err != nil {
 | 
				
			||||||
 | 
								return orientationUnspecified
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if val < 1 || val > 8 {
 | 
				
			||||||
 | 
								return orientationUnspecified // Invalid tag value.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return orientation(val)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return orientationUnspecified // Missing orientation tag.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// fixOrientation applies a transform to img corresponding to the given orientation flag.
 | 
				
			||||||
 | 
					func fixOrientation(img image.Image, o orientation) image.Image {
 | 
				
			||||||
 | 
						switch o {
 | 
				
			||||||
 | 
						case orientationNormal:
 | 
				
			||||||
 | 
						case orientationFlipH:
 | 
				
			||||||
 | 
							img = FlipH(img)
 | 
				
			||||||
 | 
						case orientationFlipV:
 | 
				
			||||||
 | 
							img = FlipV(img)
 | 
				
			||||||
 | 
						case orientationRotate90:
 | 
				
			||||||
 | 
							img = Rotate90(img)
 | 
				
			||||||
 | 
						case orientationRotate180:
 | 
				
			||||||
 | 
							img = Rotate180(img)
 | 
				
			||||||
 | 
						case orientationRotate270:
 | 
				
			||||||
 | 
							img = Rotate270(img)
 | 
				
			||||||
 | 
						case orientationTranspose:
 | 
				
			||||||
 | 
							img = Transpose(img)
 | 
				
			||||||
 | 
						case orientationTransverse:
 | 
				
			||||||
 | 
							img = Transverse(img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return img
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										595
									
								
								vendor/github.com/disintegration/imaging/resize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										595
									
								
								vendor/github.com/disintegration/imaging/resize.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,595 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type indexWeight struct {
 | 
				
			||||||
 | 
						index  int
 | 
				
			||||||
 | 
						weight float64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWeight {
 | 
				
			||||||
 | 
						du := float64(srcSize) / float64(dstSize)
 | 
				
			||||||
 | 
						scale := du
 | 
				
			||||||
 | 
						if scale < 1.0 {
 | 
				
			||||||
 | 
							scale = 1.0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ru := math.Ceil(scale * filter.Support)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out := make([][]indexWeight, dstSize)
 | 
				
			||||||
 | 
						tmp := make([]indexWeight, 0, dstSize*int(ru+2)*2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for v := 0; v < dstSize; v++ {
 | 
				
			||||||
 | 
							fu := (float64(v)+0.5)*du - 0.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							begin := int(math.Ceil(fu - ru))
 | 
				
			||||||
 | 
							if begin < 0 {
 | 
				
			||||||
 | 
								begin = 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							end := int(math.Floor(fu + ru))
 | 
				
			||||||
 | 
							if end > srcSize-1 {
 | 
				
			||||||
 | 
								end = srcSize - 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var sum float64
 | 
				
			||||||
 | 
							for u := begin; u <= end; u++ {
 | 
				
			||||||
 | 
								w := filter.Kernel((float64(u) - fu) / scale)
 | 
				
			||||||
 | 
								if w != 0 {
 | 
				
			||||||
 | 
									sum += w
 | 
				
			||||||
 | 
									tmp = append(tmp, indexWeight{index: u, weight: w})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if sum != 0 {
 | 
				
			||||||
 | 
								for i := range tmp {
 | 
				
			||||||
 | 
									tmp[i].weight /= sum
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							out[v] = tmp
 | 
				
			||||||
 | 
							tmp = tmp[len(tmp):]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return out
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resize resizes the image to the specified width and height using the specified resampling
 | 
				
			||||||
 | 
					// filter and returns the transformed image. If one of width or height is 0, the image aspect
 | 
				
			||||||
 | 
					// ratio is preserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage := imaging.Resize(srcImage, 800, 600, imaging.Lanczos)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						dstW, dstH := width, height
 | 
				
			||||||
 | 
						if dstW < 0 || dstH < 0 {
 | 
				
			||||||
 | 
							return &image.NRGBA{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if dstW == 0 && dstH == 0 {
 | 
				
			||||||
 | 
							return &image.NRGBA{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srcW := img.Bounds().Dx()
 | 
				
			||||||
 | 
						srcH := img.Bounds().Dy()
 | 
				
			||||||
 | 
						if srcW <= 0 || srcH <= 0 {
 | 
				
			||||||
 | 
							return &image.NRGBA{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If new width or height is 0 then preserve aspect ratio, minimum 1px.
 | 
				
			||||||
 | 
						if dstW == 0 {
 | 
				
			||||||
 | 
							tmpW := float64(dstH) * float64(srcW) / float64(srcH)
 | 
				
			||||||
 | 
							dstW = int(math.Max(1.0, math.Floor(tmpW+0.5)))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if dstH == 0 {
 | 
				
			||||||
 | 
							tmpH := float64(dstW) * float64(srcH) / float64(srcW)
 | 
				
			||||||
 | 
							dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if filter.Support <= 0 {
 | 
				
			||||||
 | 
							// Nearest-neighbor special case.
 | 
				
			||||||
 | 
							return resizeNearest(img, dstW, dstH)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if srcW != dstW && srcH != dstH {
 | 
				
			||||||
 | 
							return resizeVertical(resizeHorizontal(img, dstW, filter), dstH, filter)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srcW != dstW {
 | 
				
			||||||
 | 
							return resizeHorizontal(img, dstW, filter)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if srcH != dstH {
 | 
				
			||||||
 | 
							return resizeVertical(img, dstH, filter)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Clone(img)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, width, src.h))
 | 
				
			||||||
 | 
						weights := precomputeWeights(width, src.w, filter)
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							scanLine := make([]uint8, src.w*4)
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, scanLine)
 | 
				
			||||||
 | 
								j0 := y * dst.Stride
 | 
				
			||||||
 | 
								for x := range weights {
 | 
				
			||||||
 | 
									var r, g, b, a float64
 | 
				
			||||||
 | 
									for _, w := range weights[x] {
 | 
				
			||||||
 | 
										i := w.index * 4
 | 
				
			||||||
 | 
										s := scanLine[i : i+4 : i+4]
 | 
				
			||||||
 | 
										aw := float64(s[3]) * w.weight
 | 
				
			||||||
 | 
										r += float64(s[0]) * aw
 | 
				
			||||||
 | 
										g += float64(s[1]) * aw
 | 
				
			||||||
 | 
										b += float64(s[2]) * aw
 | 
				
			||||||
 | 
										a += aw
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if a != 0 {
 | 
				
			||||||
 | 
										aInv := 1 / a
 | 
				
			||||||
 | 
										j := j0 + x*4
 | 
				
			||||||
 | 
										d := dst.Pix[j : j+4 : j+4]
 | 
				
			||||||
 | 
										d[0] = clamp(r * aInv)
 | 
				
			||||||
 | 
										d[1] = clamp(g * aInv)
 | 
				
			||||||
 | 
										d[2] = clamp(b * aInv)
 | 
				
			||||||
 | 
										d[3] = clamp(a)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func resizeVertical(img image.Image, height int, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, height))
 | 
				
			||||||
 | 
						weights := precomputeWeights(height, src.h, filter)
 | 
				
			||||||
 | 
						parallel(0, src.w, func(xs <-chan int) {
 | 
				
			||||||
 | 
							scanLine := make([]uint8, src.h*4)
 | 
				
			||||||
 | 
							for x := range xs {
 | 
				
			||||||
 | 
								src.scan(x, 0, x+1, src.h, scanLine)
 | 
				
			||||||
 | 
								for y := range weights {
 | 
				
			||||||
 | 
									var r, g, b, a float64
 | 
				
			||||||
 | 
									for _, w := range weights[y] {
 | 
				
			||||||
 | 
										i := w.index * 4
 | 
				
			||||||
 | 
										s := scanLine[i : i+4 : i+4]
 | 
				
			||||||
 | 
										aw := float64(s[3]) * w.weight
 | 
				
			||||||
 | 
										r += float64(s[0]) * aw
 | 
				
			||||||
 | 
										g += float64(s[1]) * aw
 | 
				
			||||||
 | 
										b += float64(s[2]) * aw
 | 
				
			||||||
 | 
										a += aw
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if a != 0 {
 | 
				
			||||||
 | 
										aInv := 1 / a
 | 
				
			||||||
 | 
										j := y*dst.Stride + x*4
 | 
				
			||||||
 | 
										d := dst.Pix[j : j+4 : j+4]
 | 
				
			||||||
 | 
										d[0] = clamp(r * aInv)
 | 
				
			||||||
 | 
										d[1] = clamp(g * aInv)
 | 
				
			||||||
 | 
										d[2] = clamp(b * aInv)
 | 
				
			||||||
 | 
										d[3] = clamp(a)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// resizeNearest is a fast nearest-neighbor resize, no filtering.
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fit scales down the image using the specified resample filter to fit the specified
 | 
				
			||||||
 | 
					// maximum width and height and returns the transformed image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage := imaging.Fit(srcImage, 800, 600, imaging.Lanczos)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Fill creates an image with the specified dimensions and fills it with the scaled source image.
 | 
				
			||||||
 | 
					// To achieve the correct aspect ratio without stretching, the source image will be cropped.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage := imaging.Fill(srcImage, 800, 600, imaging.Center, imaging.Lanczos)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Fill(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						dstW, dstH := width, height
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if dstW <= 0 || dstH <= 0 {
 | 
				
			||||||
 | 
							return &image.NRGBA{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srcBounds := img.Bounds()
 | 
				
			||||||
 | 
						srcW := srcBounds.Dx()
 | 
				
			||||||
 | 
						srcH := srcBounds.Dy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if srcW <= 0 || srcH <= 0 {
 | 
				
			||||||
 | 
							return &image.NRGBA{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if srcW == dstW && srcH == dstH {
 | 
				
			||||||
 | 
							return Clone(img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if srcW >= 100 && srcH >= 100 {
 | 
				
			||||||
 | 
							return cropAndResize(img, dstW, dstH, anchor, filter)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return resizeAndCrop(img, dstW, dstH, anchor, filter)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// cropAndResize crops the image to the smallest possible size that has the required aspect ratio using
 | 
				
			||||||
 | 
					// the given anchor point, then scales it to the specified dimensions and returns the transformed image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This is generally faster than resizing first, but may result in inaccuracies when used on small source images.
 | 
				
			||||||
 | 
					func cropAndResize(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						dstW, dstH := width, height
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srcBounds := img.Bounds()
 | 
				
			||||||
 | 
						srcW := srcBounds.Dx()
 | 
				
			||||||
 | 
						srcH := srcBounds.Dy()
 | 
				
			||||||
 | 
						srcAspectRatio := float64(srcW) / float64(srcH)
 | 
				
			||||||
 | 
						dstAspectRatio := float64(dstW) / float64(dstH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tmp *image.NRGBA
 | 
				
			||||||
 | 
						if srcAspectRatio < dstAspectRatio {
 | 
				
			||||||
 | 
							cropH := float64(srcW) * float64(dstH) / float64(dstW)
 | 
				
			||||||
 | 
							tmp = CropAnchor(img, srcW, int(math.Max(1, cropH)+0.5), anchor)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cropW := float64(srcH) * float64(dstW) / float64(dstH)
 | 
				
			||||||
 | 
							tmp = CropAnchor(img, int(math.Max(1, cropW)+0.5), srcH, anchor)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return Resize(tmp, dstW, dstH, filter)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// resizeAndCrop resizes the image to the smallest possible size that will cover the specified dimensions,
 | 
				
			||||||
 | 
					// crops the resized image to the specified dimensions using the given anchor point and returns
 | 
				
			||||||
 | 
					// the transformed image.
 | 
				
			||||||
 | 
					func resizeAndCrop(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						dstW, dstH := width, height
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srcBounds := img.Bounds()
 | 
				
			||||||
 | 
						srcW := srcBounds.Dx()
 | 
				
			||||||
 | 
						srcH := srcBounds.Dy()
 | 
				
			||||||
 | 
						srcAspectRatio := float64(srcW) / float64(srcH)
 | 
				
			||||||
 | 
						dstAspectRatio := float64(dstW) / float64(dstH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tmp *image.NRGBA
 | 
				
			||||||
 | 
						if srcAspectRatio < dstAspectRatio {
 | 
				
			||||||
 | 
							tmp = Resize(img, dstW, 0, filter)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							tmp = Resize(img, 0, dstH, filter)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CropAnchor(tmp, dstW, dstH, anchor)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Thumbnail scales the image up or down using the specified resample filter, crops it
 | 
				
			||||||
 | 
					// to the specified width and hight and returns the transformed image.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Example:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	dstImage := imaging.Thumbnail(srcImage, 100, 100, imaging.Lanczos)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Thumbnail(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
 | 
				
			||||||
 | 
						return Fill(img, width, height, Center, filter)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ResampleFilter specifies a resampling filter to be used for image resizing.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	General filter recommendations:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	- Lanczos
 | 
				
			||||||
 | 
					//		A high-quality resampling filter for photographic images yielding sharp results.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	- CatmullRom
 | 
				
			||||||
 | 
					//		A sharp cubic filter that is faster than Lanczos filter while providing similar results.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	- MitchellNetravali
 | 
				
			||||||
 | 
					//		A cubic filter that produces smoother results with less ringing artifacts than CatmullRom.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	- Linear
 | 
				
			||||||
 | 
					//		Bilinear resampling filter, produces a smooth output. Faster than cubic filters.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	- Box
 | 
				
			||||||
 | 
					//		Simple and fast averaging filter appropriate for downscaling.
 | 
				
			||||||
 | 
					//		When upscaling it's similar to NearestNeighbor.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	- NearestNeighbor
 | 
				
			||||||
 | 
					//		Fastest resampling filter, no antialiasing.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					type ResampleFilter struct {
 | 
				
			||||||
 | 
						Support float64
 | 
				
			||||||
 | 
						Kernel  func(float64) float64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NearestNeighbor is a nearest-neighbor filter (no anti-aliasing).
 | 
				
			||||||
 | 
					var NearestNeighbor ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Box filter (averaging pixels).
 | 
				
			||||||
 | 
					var Box ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Linear filter.
 | 
				
			||||||
 | 
					var Linear ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hermite cubic spline filter (BC-spline; B=0; C=0).
 | 
				
			||||||
 | 
					var Hermite ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// MitchellNetravali is Mitchell-Netravali cubic filter (BC-spline; B=1/3; C=1/3).
 | 
				
			||||||
 | 
					var MitchellNetravali ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CatmullRom is a Catmull-Rom - sharp cubic filter (BC-spline; B=0; C=0.5).
 | 
				
			||||||
 | 
					var CatmullRom ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BSpline is a smooth cubic filter (BC-spline; B=1; C=0).
 | 
				
			||||||
 | 
					var BSpline ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Gaussian is a Gaussian blurring filter.
 | 
				
			||||||
 | 
					var Gaussian ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Bartlett is a Bartlett-windowed sinc filter (3 lobes).
 | 
				
			||||||
 | 
					var Bartlett ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Lanczos filter (3 lobes).
 | 
				
			||||||
 | 
					var Lanczos ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hann is a Hann-windowed sinc filter (3 lobes).
 | 
				
			||||||
 | 
					var Hann ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hamming is a Hamming-windowed sinc filter (3 lobes).
 | 
				
			||||||
 | 
					var Hamming ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Blackman is a Blackman-windowed sinc filter (3 lobes).
 | 
				
			||||||
 | 
					var Blackman ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Welch is a Welch-windowed sinc filter (parabolic window, 3 lobes).
 | 
				
			||||||
 | 
					var Welch ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Cosine is a Cosine-windowed sinc filter (3 lobes).
 | 
				
			||||||
 | 
					var Cosine ResampleFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func bcspline(x, b, c float64) float64 {
 | 
				
			||||||
 | 
						var y float64
 | 
				
			||||||
 | 
						x = math.Abs(x)
 | 
				
			||||||
 | 
						if x < 1.0 {
 | 
				
			||||||
 | 
							y = ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6
 | 
				
			||||||
 | 
						} else if x < 2.0 {
 | 
				
			||||||
 | 
							y = ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return y
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sinc(x float64) float64 {
 | 
				
			||||||
 | 
						if x == 0 {
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return math.Sin(math.Pi*x) / (math.Pi * x)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						NearestNeighbor = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 0.0, // special case - not applying the filter
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Box = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 0.5,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x <= 0.5 {
 | 
				
			||||||
 | 
									return 1.0
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Linear = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 1.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 1.0 {
 | 
				
			||||||
 | 
									return 1.0 - x
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Hermite = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 1.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 1.0 {
 | 
				
			||||||
 | 
									return bcspline(x, 0.0, 0.0)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						MitchellNetravali = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 2.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 2.0 {
 | 
				
			||||||
 | 
									return bcspline(x, 1.0/3.0, 1.0/3.0)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CatmullRom = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 2.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 2.0 {
 | 
				
			||||||
 | 
									return bcspline(x, 0.0, 0.5)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BSpline = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 2.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 2.0 {
 | 
				
			||||||
 | 
									return bcspline(x, 1.0, 0.0)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Gaussian = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 2.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 2.0 {
 | 
				
			||||||
 | 
									return math.Exp(-2 * x * x)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Bartlett = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * (3.0 - x) / 3.0
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Lanczos = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * sinc(x/3.0)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Hann = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * (0.5 + 0.5*math.Cos(math.Pi*x/3.0))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Hamming = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * (0.54 + 0.46*math.Cos(math.Pi*x/3.0))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Blackman = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * (0.42 - 0.5*math.Cos(math.Pi*x/3.0+math.Pi) + 0.08*math.Cos(2.0*math.Pi*x/3.0))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Welch = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * (1.0 - (x * x / 9.0))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Cosine = ResampleFilter{
 | 
				
			||||||
 | 
							Support: 3.0,
 | 
				
			||||||
 | 
							Kernel: func(x float64) float64 {
 | 
				
			||||||
 | 
								x = math.Abs(x)
 | 
				
			||||||
 | 
								if x < 3.0 {
 | 
				
			||||||
 | 
									return sinc(x) * math.Cos((math.Pi/2.0)*(x/3.0))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										285
									
								
								vendor/github.com/disintegration/imaging/scanner.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								vendor/github.com/disintegration/imaging/scanner.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,285 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type scanner struct {
 | 
				
			||||||
 | 
						image   image.Image
 | 
				
			||||||
 | 
						w, h    int
 | 
				
			||||||
 | 
						palette []color.NRGBA
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newScanner(img image.Image) *scanner {
 | 
				
			||||||
 | 
						s := &scanner{
 | 
				
			||||||
 | 
							image: img,
 | 
				
			||||||
 | 
							w:     img.Bounds().Dx(),
 | 
				
			||||||
 | 
							h:     img.Bounds().Dy(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if img, ok := img.(*image.Paletted); ok {
 | 
				
			||||||
 | 
							s.palette = make([]color.NRGBA, len(img.Palette))
 | 
				
			||||||
 | 
							for i := 0; i < len(img.Palette); i++ {
 | 
				
			||||||
 | 
								s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// scan scans the given rectangular region of the image into dst.
 | 
				
			||||||
 | 
					func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
 | 
				
			||||||
 | 
						switch img := s.image.(type) {
 | 
				
			||||||
 | 
						case *image.NRGBA:
 | 
				
			||||||
 | 
							size := (x2 - x1) * 4
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							i := y1*img.Stride + x1*4
 | 
				
			||||||
 | 
							if size == 4 {
 | 
				
			||||||
 | 
								for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									s := img.Pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
									d[0] = s[0]
 | 
				
			||||||
 | 
									d[1] = s[1]
 | 
				
			||||||
 | 
									d[2] = s[2]
 | 
				
			||||||
 | 
									d[3] = s[3]
 | 
				
			||||||
 | 
									j += size
 | 
				
			||||||
 | 
									i += img.Stride
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
									copy(dst[j:j+size], img.Pix[i:i+size])
 | 
				
			||||||
 | 
									j += size
 | 
				
			||||||
 | 
									i += img.Stride
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.NRGBA64:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								i := y*img.Stride + x1*8
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									s := img.Pix[i : i+8 : i+8]
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									d[0] = s[0]
 | 
				
			||||||
 | 
									d[1] = s[2]
 | 
				
			||||||
 | 
									d[2] = s[4]
 | 
				
			||||||
 | 
									d[3] = s[6]
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
									i += 8
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.RGBA:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								i := y*img.Stride + x1*4
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									a := img.Pix[i+3]
 | 
				
			||||||
 | 
									switch a {
 | 
				
			||||||
 | 
									case 0:
 | 
				
			||||||
 | 
										d[0] = 0
 | 
				
			||||||
 | 
										d[1] = 0
 | 
				
			||||||
 | 
										d[2] = 0
 | 
				
			||||||
 | 
										d[3] = a
 | 
				
			||||||
 | 
									case 0xff:
 | 
				
			||||||
 | 
										s := img.Pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
										d[0] = s[0]
 | 
				
			||||||
 | 
										d[1] = s[1]
 | 
				
			||||||
 | 
										d[2] = s[2]
 | 
				
			||||||
 | 
										d[3] = a
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										s := img.Pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
										r16 := uint16(s[0])
 | 
				
			||||||
 | 
										g16 := uint16(s[1])
 | 
				
			||||||
 | 
										b16 := uint16(s[2])
 | 
				
			||||||
 | 
										a16 := uint16(a)
 | 
				
			||||||
 | 
										d[0] = uint8(r16 * 0xff / a16)
 | 
				
			||||||
 | 
										d[1] = uint8(g16 * 0xff / a16)
 | 
				
			||||||
 | 
										d[2] = uint8(b16 * 0xff / a16)
 | 
				
			||||||
 | 
										d[3] = a
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
									i += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.RGBA64:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								i := y*img.Stride + x1*8
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									s := img.Pix[i : i+8 : i+8]
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									a := s[6]
 | 
				
			||||||
 | 
									switch a {
 | 
				
			||||||
 | 
									case 0:
 | 
				
			||||||
 | 
										d[0] = 0
 | 
				
			||||||
 | 
										d[1] = 0
 | 
				
			||||||
 | 
										d[2] = 0
 | 
				
			||||||
 | 
									case 0xff:
 | 
				
			||||||
 | 
										d[0] = s[0]
 | 
				
			||||||
 | 
										d[1] = s[2]
 | 
				
			||||||
 | 
										d[2] = s[4]
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										r32 := uint32(s[0])<<8 | uint32(s[1])
 | 
				
			||||||
 | 
										g32 := uint32(s[2])<<8 | uint32(s[3])
 | 
				
			||||||
 | 
										b32 := uint32(s[4])<<8 | uint32(s[5])
 | 
				
			||||||
 | 
										a32 := uint32(s[6])<<8 | uint32(s[7])
 | 
				
			||||||
 | 
										d[0] = uint8((r32 * 0xffff / a32) >> 8)
 | 
				
			||||||
 | 
										d[1] = uint8((g32 * 0xffff / a32) >> 8)
 | 
				
			||||||
 | 
										d[2] = uint8((b32 * 0xffff / a32) >> 8)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									d[3] = a
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
									i += 8
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.Gray:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								i := y*img.Stride + x1
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									c := img.Pix[i]
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									d[0] = c
 | 
				
			||||||
 | 
									d[1] = c
 | 
				
			||||||
 | 
									d[2] = c
 | 
				
			||||||
 | 
									d[3] = 0xff
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
									i++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.Gray16:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								i := y*img.Stride + x1*2
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									c := img.Pix[i]
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									d[0] = c
 | 
				
			||||||
 | 
									d[1] = c
 | 
				
			||||||
 | 
									d[2] = c
 | 
				
			||||||
 | 
									d[3] = 0xff
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
									i += 2
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.YCbCr:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							x1 += img.Rect.Min.X
 | 
				
			||||||
 | 
							x2 += img.Rect.Min.X
 | 
				
			||||||
 | 
							y1 += img.Rect.Min.Y
 | 
				
			||||||
 | 
							y2 += img.Rect.Min.Y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hy := img.Rect.Min.Y / 2
 | 
				
			||||||
 | 
							hx := img.Rect.Min.X / 2
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var yBase int
 | 
				
			||||||
 | 
								switch img.SubsampleRatio {
 | 
				
			||||||
 | 
								case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio422:
 | 
				
			||||||
 | 
									yBase = (y - img.Rect.Min.Y) * img.CStride
 | 
				
			||||||
 | 
								case image.YCbCrSubsampleRatio420, image.YCbCrSubsampleRatio440:
 | 
				
			||||||
 | 
									yBase = (y/2 - hy) * img.CStride
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									var ic int
 | 
				
			||||||
 | 
									switch img.SubsampleRatio {
 | 
				
			||||||
 | 
									case image.YCbCrSubsampleRatio444, image.YCbCrSubsampleRatio440:
 | 
				
			||||||
 | 
										ic = yBase + (x - img.Rect.Min.X)
 | 
				
			||||||
 | 
									case image.YCbCrSubsampleRatio422, image.YCbCrSubsampleRatio420:
 | 
				
			||||||
 | 
										ic = yBase + (x/2 - hx)
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										ic = img.COffset(x, y)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									yy1 := int32(img.Y[iy]) * 0x10101
 | 
				
			||||||
 | 
									cb1 := int32(img.Cb[ic]) - 128
 | 
				
			||||||
 | 
									cr1 := int32(img.Cr[ic]) - 128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									r := yy1 + 91881*cr1
 | 
				
			||||||
 | 
									if uint32(r)&0xff000000 == 0 {
 | 
				
			||||||
 | 
										r >>= 16
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										r = ^(r >> 31)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									g := yy1 - 22554*cb1 - 46802*cr1
 | 
				
			||||||
 | 
									if uint32(g)&0xff000000 == 0 {
 | 
				
			||||||
 | 
										g >>= 16
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										g = ^(g >> 31)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									b := yy1 + 116130*cb1
 | 
				
			||||||
 | 
									if uint32(b)&0xff000000 == 0 {
 | 
				
			||||||
 | 
										b >>= 16
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										b = ^(b >> 31)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									d[0] = uint8(r)
 | 
				
			||||||
 | 
									d[1] = uint8(g)
 | 
				
			||||||
 | 
									d[2] = uint8(b)
 | 
				
			||||||
 | 
									d[3] = 0xff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									iy++
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.Paletted:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								i := y*img.Stride + x1
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									c := s.palette[img.Pix[i]]
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									d[0] = c.R
 | 
				
			||||||
 | 
									d[1] = c.G
 | 
				
			||||||
 | 
									d[2] = c.B
 | 
				
			||||||
 | 
									d[3] = c.A
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
									i++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							j := 0
 | 
				
			||||||
 | 
							b := s.image.Bounds()
 | 
				
			||||||
 | 
							x1 += b.Min.X
 | 
				
			||||||
 | 
							x2 += b.Min.X
 | 
				
			||||||
 | 
							y1 += b.Min.Y
 | 
				
			||||||
 | 
							y2 += b.Min.Y
 | 
				
			||||||
 | 
							for y := y1; y < y2; y++ {
 | 
				
			||||||
 | 
								for x := x1; x < x2; x++ {
 | 
				
			||||||
 | 
									r16, g16, b16, a16 := s.image.At(x, y).RGBA()
 | 
				
			||||||
 | 
									d := dst[j : j+4 : j+4]
 | 
				
			||||||
 | 
									switch a16 {
 | 
				
			||||||
 | 
									case 0xffff:
 | 
				
			||||||
 | 
										d[0] = uint8(r16 >> 8)
 | 
				
			||||||
 | 
										d[1] = uint8(g16 >> 8)
 | 
				
			||||||
 | 
										d[2] = uint8(b16 >> 8)
 | 
				
			||||||
 | 
										d[3] = 0xff
 | 
				
			||||||
 | 
									case 0:
 | 
				
			||||||
 | 
										d[0] = 0
 | 
				
			||||||
 | 
										d[1] = 0
 | 
				
			||||||
 | 
										d[2] = 0
 | 
				
			||||||
 | 
										d[3] = 0
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										d[0] = uint8(((r16 * 0xffff) / a16) >> 8)
 | 
				
			||||||
 | 
										d[1] = uint8(((g16 * 0xffff) / a16) >> 8)
 | 
				
			||||||
 | 
										d[2] = uint8(((b16 * 0xffff) / a16) >> 8)
 | 
				
			||||||
 | 
										d[3] = uint8(a16 >> 8)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										249
									
								
								vendor/github.com/disintegration/imaging/tools.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								vendor/github.com/disintegration/imaging/tools.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// New creates a new image with the specified width and height, and fills it with the specified color.
 | 
				
			||||||
 | 
					func New(width, height int, fillColor color.Color) *image.NRGBA {
 | 
				
			||||||
 | 
						if width <= 0 || height <= 0 {
 | 
				
			||||||
 | 
							return &image.NRGBA{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c := color.NRGBAModel.Convert(fillColor).(color.NRGBA)
 | 
				
			||||||
 | 
						if (c == color.NRGBA{0, 0, 0, 0}) {
 | 
				
			||||||
 | 
							return image.NewNRGBA(image.Rect(0, 0, width, height))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &image.NRGBA{
 | 
				
			||||||
 | 
							Pix:    bytes.Repeat([]byte{c.R, c.G, c.B, c.A}, width*height),
 | 
				
			||||||
 | 
							Stride: 4 * width,
 | 
				
			||||||
 | 
							Rect:   image.Rect(0, 0, width, height),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Clone returns a copy of the given image.
 | 
				
			||||||
 | 
					func Clone(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
				
			||||||
 | 
						size := src.w * 4
 | 
				
			||||||
 | 
						parallel(0, src.h, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								i := y * dst.Stride
 | 
				
			||||||
 | 
								src.scan(0, y, src.w, y+1, dst.Pix[i:i+size])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Anchor is the anchor point for image alignment.
 | 
				
			||||||
 | 
					type Anchor int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Anchor point positions.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						Center Anchor = iota
 | 
				
			||||||
 | 
						TopLeft
 | 
				
			||||||
 | 
						Top
 | 
				
			||||||
 | 
						TopRight
 | 
				
			||||||
 | 
						Left
 | 
				
			||||||
 | 
						Right
 | 
				
			||||||
 | 
						BottomLeft
 | 
				
			||||||
 | 
						Bottom
 | 
				
			||||||
 | 
						BottomRight
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func anchorPt(b image.Rectangle, w, h int, anchor Anchor) image.Point {
 | 
				
			||||||
 | 
						var x, y int
 | 
				
			||||||
 | 
						switch anchor {
 | 
				
			||||||
 | 
						case TopLeft:
 | 
				
			||||||
 | 
							x = b.Min.X
 | 
				
			||||||
 | 
							y = b.Min.Y
 | 
				
			||||||
 | 
						case Top:
 | 
				
			||||||
 | 
							x = b.Min.X + (b.Dx()-w)/2
 | 
				
			||||||
 | 
							y = b.Min.Y
 | 
				
			||||||
 | 
						case TopRight:
 | 
				
			||||||
 | 
							x = b.Max.X - w
 | 
				
			||||||
 | 
							y = b.Min.Y
 | 
				
			||||||
 | 
						case Left:
 | 
				
			||||||
 | 
							x = b.Min.X
 | 
				
			||||||
 | 
							y = b.Min.Y + (b.Dy()-h)/2
 | 
				
			||||||
 | 
						case Right:
 | 
				
			||||||
 | 
							x = b.Max.X - w
 | 
				
			||||||
 | 
							y = b.Min.Y + (b.Dy()-h)/2
 | 
				
			||||||
 | 
						case BottomLeft:
 | 
				
			||||||
 | 
							x = b.Min.X
 | 
				
			||||||
 | 
							y = b.Max.Y - h
 | 
				
			||||||
 | 
						case Bottom:
 | 
				
			||||||
 | 
							x = b.Min.X + (b.Dx()-w)/2
 | 
				
			||||||
 | 
							y = b.Max.Y - h
 | 
				
			||||||
 | 
						case BottomRight:
 | 
				
			||||||
 | 
							x = b.Max.X - w
 | 
				
			||||||
 | 
							y = b.Max.Y - h
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							x = b.Min.X + (b.Dx()-w)/2
 | 
				
			||||||
 | 
							y = b.Min.Y + (b.Dy()-h)/2
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return image.Pt(x, y)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Crop cuts out a rectangular region with the specified bounds
 | 
				
			||||||
 | 
					// from the image and returns the cropped image.
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CropAnchor cuts out a rectangular region with the specified size
 | 
				
			||||||
 | 
					// from the image using the specified anchor point and returns the cropped image.
 | 
				
			||||||
 | 
					func CropAnchor(img image.Image, width, height int, anchor Anchor) *image.NRGBA {
 | 
				
			||||||
 | 
						srcBounds := img.Bounds()
 | 
				
			||||||
 | 
						pt := anchorPt(srcBounds, width, height, anchor)
 | 
				
			||||||
 | 
						r := image.Rect(0, 0, width, height).Add(pt)
 | 
				
			||||||
 | 
						b := srcBounds.Intersect(r)
 | 
				
			||||||
 | 
						return Crop(img, b)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CropCenter cuts out a rectangular region with the specified size
 | 
				
			||||||
 | 
					// from the center of the image and returns the cropped image.
 | 
				
			||||||
 | 
					func CropCenter(img image.Image, width, height int) *image.NRGBA {
 | 
				
			||||||
 | 
						return CropAnchor(img, width, height, Center)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Paste pastes the img image to the background image at the specified position and returns the combined image.
 | 
				
			||||||
 | 
					func Paste(background, img image.Image, pos image.Point) *image.NRGBA {
 | 
				
			||||||
 | 
						dst := Clone(background)
 | 
				
			||||||
 | 
						pos = pos.Sub(background.Bounds().Min)
 | 
				
			||||||
 | 
						pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())}
 | 
				
			||||||
 | 
						interRect := pasteRect.Intersect(dst.Bounds())
 | 
				
			||||||
 | 
						if interRect.Empty() {
 | 
				
			||||||
 | 
							return dst
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								x1 := interRect.Min.X - pasteRect.Min.X
 | 
				
			||||||
 | 
								x2 := interRect.Max.X - pasteRect.Min.X
 | 
				
			||||||
 | 
								y1 := y - pasteRect.Min.Y
 | 
				
			||||||
 | 
								y2 := y1 + 1
 | 
				
			||||||
 | 
								i1 := y*dst.Stride + interRect.Min.X*4
 | 
				
			||||||
 | 
								i2 := i1 + interRect.Dx()*4
 | 
				
			||||||
 | 
								src.scan(x1, y1, x2, y2, dst.Pix[i1:i2])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PasteCenter pastes the img image to the center of the background image and returns the combined image.
 | 
				
			||||||
 | 
					func PasteCenter(background, img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						bgBounds := background.Bounds()
 | 
				
			||||||
 | 
						bgW := bgBounds.Dx()
 | 
				
			||||||
 | 
						bgH := bgBounds.Dy()
 | 
				
			||||||
 | 
						bgMinX := bgBounds.Min.X
 | 
				
			||||||
 | 
						bgMinY := bgBounds.Min.Y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						centerX := bgMinX + bgW/2
 | 
				
			||||||
 | 
						centerY := bgMinY + bgH/2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x0 := centerX - img.Bounds().Dx()/2
 | 
				
			||||||
 | 
						y0 := centerY - img.Bounds().Dy()/2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return Paste(background, img, image.Pt(x0, y0))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Overlay draws the img image over the background image at given position
 | 
				
			||||||
 | 
					// and returns the combined image. Opacity parameter is the opacity of the img
 | 
				
			||||||
 | 
					// image layer, used to compose the images, it must be from 0.0 to 1.0.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Examples:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// Draw spriteImage over backgroundImage at the given position (x=50, y=50).
 | 
				
			||||||
 | 
					//	dstImage := imaging.Overlay(backgroundImage, spriteImage, image.Pt(50, 50), 1.0)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//	// Blend two opaque images of the same size.
 | 
				
			||||||
 | 
					//	dstImage := imaging.Overlay(imageOne, imageTwo, image.Pt(0, 0), 0.5)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					func Overlay(background, img image.Image, pos image.Point, opacity float64) *image.NRGBA {
 | 
				
			||||||
 | 
						opacity = math.Min(math.Max(opacity, 0.0), 1.0) // Ensure 0.0 <= opacity <= 1.0.
 | 
				
			||||||
 | 
						dst := Clone(background)
 | 
				
			||||||
 | 
						pos = pos.Sub(background.Bounds().Min)
 | 
				
			||||||
 | 
						pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())}
 | 
				
			||||||
 | 
						interRect := pasteRect.Intersect(dst.Bounds())
 | 
				
			||||||
 | 
						if interRect.Empty() {
 | 
				
			||||||
 | 
							return dst
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) {
 | 
				
			||||||
 | 
							scanLine := make([]uint8, interRect.Dx()*4)
 | 
				
			||||||
 | 
							for y := range ys {
 | 
				
			||||||
 | 
								x1 := interRect.Min.X - pasteRect.Min.X
 | 
				
			||||||
 | 
								x2 := interRect.Max.X - pasteRect.Min.X
 | 
				
			||||||
 | 
								y1 := y - pasteRect.Min.Y
 | 
				
			||||||
 | 
								y2 := y1 + 1
 | 
				
			||||||
 | 
								src.scan(x1, y1, x2, y2, scanLine)
 | 
				
			||||||
 | 
								i := y*dst.Stride + interRect.Min.X*4
 | 
				
			||||||
 | 
								j := 0
 | 
				
			||||||
 | 
								for x := interRect.Min.X; x < interRect.Max.X; x++ {
 | 
				
			||||||
 | 
									d := dst.Pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
									r1 := float64(d[0])
 | 
				
			||||||
 | 
									g1 := float64(d[1])
 | 
				
			||||||
 | 
									b1 := float64(d[2])
 | 
				
			||||||
 | 
									a1 := float64(d[3])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									s := scanLine[j : j+4 : j+4]
 | 
				
			||||||
 | 
									r2 := float64(s[0])
 | 
				
			||||||
 | 
									g2 := float64(s[1])
 | 
				
			||||||
 | 
									b2 := float64(s[2])
 | 
				
			||||||
 | 
									a2 := float64(s[3])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									coef2 := opacity * a2 / 255
 | 
				
			||||||
 | 
									coef1 := (1 - coef2) * a1 / 255
 | 
				
			||||||
 | 
									coefSum := coef1 + coef2
 | 
				
			||||||
 | 
									coef1 /= coefSum
 | 
				
			||||||
 | 
									coef2 /= coefSum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									d[0] = uint8(r1*coef1 + r2*coef2)
 | 
				
			||||||
 | 
									d[1] = uint8(g1*coef1 + g2*coef2)
 | 
				
			||||||
 | 
									d[2] = uint8(b1*coef1 + b2*coef2)
 | 
				
			||||||
 | 
									d[3] = uint8(math.Min(a1+a2*opacity*(255-a1)/255, 255))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									i += 4
 | 
				
			||||||
 | 
									j += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OverlayCenter overlays the img image to the center of the background image and
 | 
				
			||||||
 | 
					// returns the combined image. Opacity parameter is the opacity of the img
 | 
				
			||||||
 | 
					// image layer, used to compose the images, it must be from 0.0 to 1.0.
 | 
				
			||||||
 | 
					func OverlayCenter(background, img image.Image, opacity float64) *image.NRGBA {
 | 
				
			||||||
 | 
						bgBounds := background.Bounds()
 | 
				
			||||||
 | 
						bgW := bgBounds.Dx()
 | 
				
			||||||
 | 
						bgH := bgBounds.Dy()
 | 
				
			||||||
 | 
						bgMinX := bgBounds.Min.X
 | 
				
			||||||
 | 
						bgMinY := bgBounds.Min.Y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						centerX := bgMinX + bgW/2
 | 
				
			||||||
 | 
						centerY := bgMinY + bgH/2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x0 := centerX - img.Bounds().Dx()/2
 | 
				
			||||||
 | 
						y0 := centerY - img.Bounds().Dy()/2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return Overlay(background, img, image.Point{x0, y0}, opacity)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										268
									
								
								vendor/github.com/disintegration/imaging/transform.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								vendor/github.com/disintegration/imaging/transform.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,268 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FlipH flips the image horizontally (from left to right) and returns the transformed image.
 | 
				
			||||||
 | 
					func FlipH(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.w
 | 
				
			||||||
 | 
						dstH := src.h
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcY := dstY
 | 
				
			||||||
 | 
								src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
								reverse(dst.Pix[i : i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FlipV flips the image vertically (from top to bottom) and returns the transformed image.
 | 
				
			||||||
 | 
					func FlipV(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.w
 | 
				
			||||||
 | 
						dstH := src.h
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcY := dstH - dstY - 1
 | 
				
			||||||
 | 
								src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Transpose flips the image horizontally and rotates 90 degrees counter-clockwise.
 | 
				
			||||||
 | 
					func Transpose(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.h
 | 
				
			||||||
 | 
						dstH := src.w
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcX := dstY
 | 
				
			||||||
 | 
								src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Transverse flips the image vertically and rotates 90 degrees counter-clockwise.
 | 
				
			||||||
 | 
					func Transverse(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.h
 | 
				
			||||||
 | 
						dstH := src.w
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcX := dstH - dstY - 1
 | 
				
			||||||
 | 
								src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
								reverse(dst.Pix[i : i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Rotate90 rotates the image 90 degrees counter-clockwise and returns the transformed image.
 | 
				
			||||||
 | 
					func Rotate90(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.h
 | 
				
			||||||
 | 
						dstH := src.w
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcX := dstH - dstY - 1
 | 
				
			||||||
 | 
								src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Rotate180 rotates the image 180 degrees counter-clockwise and returns the transformed image.
 | 
				
			||||||
 | 
					func Rotate180(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.w
 | 
				
			||||||
 | 
						dstH := src.h
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcY := dstH - dstY - 1
 | 
				
			||||||
 | 
								src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
								reverse(dst.Pix[i : i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Rotate270 rotates the image 270 degrees counter-clockwise and returns the transformed image.
 | 
				
			||||||
 | 
					func Rotate270(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						src := newScanner(img)
 | 
				
			||||||
 | 
						dstW := src.h
 | 
				
			||||||
 | 
						dstH := src.w
 | 
				
			||||||
 | 
						rowSize := dstW * 4
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								i := dstY * dst.Stride
 | 
				
			||||||
 | 
								srcX := dstY
 | 
				
			||||||
 | 
								src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
 | 
				
			||||||
 | 
								reverse(dst.Pix[i : i+rowSize])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Rotate rotates an image by the given angle counter-clockwise .
 | 
				
			||||||
 | 
					// The angle parameter is the rotation angle in degrees.
 | 
				
			||||||
 | 
					// The bgColor parameter specifies the color of the uncovered zone after the rotation.
 | 
				
			||||||
 | 
					func Rotate(img image.Image, angle float64, bgColor color.Color) *image.NRGBA {
 | 
				
			||||||
 | 
						angle = angle - math.Floor(angle/360)*360
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch angle {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							return Clone(img)
 | 
				
			||||||
 | 
						case 90:
 | 
				
			||||||
 | 
							return Rotate90(img)
 | 
				
			||||||
 | 
						case 180:
 | 
				
			||||||
 | 
							return Rotate180(img)
 | 
				
			||||||
 | 
						case 270:
 | 
				
			||||||
 | 
							return Rotate270(img)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						src := toNRGBA(img)
 | 
				
			||||||
 | 
						srcW := src.Bounds().Max.X
 | 
				
			||||||
 | 
						srcH := src.Bounds().Max.Y
 | 
				
			||||||
 | 
						dstW, dstH := rotatedSize(srcW, srcH, angle)
 | 
				
			||||||
 | 
						dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if dstW <= 0 || dstH <= 0 {
 | 
				
			||||||
 | 
							return dst
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srcXOff := float64(srcW)/2 - 0.5
 | 
				
			||||||
 | 
						srcYOff := float64(srcH)/2 - 0.5
 | 
				
			||||||
 | 
						dstXOff := float64(dstW)/2 - 0.5
 | 
				
			||||||
 | 
						dstYOff := float64(dstH)/2 - 0.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bgColorNRGBA := color.NRGBAModel.Convert(bgColor).(color.NRGBA)
 | 
				
			||||||
 | 
						sin, cos := math.Sincos(math.Pi * angle / 180)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						parallel(0, dstH, func(ys <-chan int) {
 | 
				
			||||||
 | 
							for dstY := range ys {
 | 
				
			||||||
 | 
								for dstX := 0; dstX < dstW; dstX++ {
 | 
				
			||||||
 | 
									xf, yf := rotatePoint(float64(dstX)-dstXOff, float64(dstY)-dstYOff, sin, cos)
 | 
				
			||||||
 | 
									xf, yf = xf+srcXOff, yf+srcYOff
 | 
				
			||||||
 | 
									interpolatePoint(dst, dstX, dstY, src, xf, yf, bgColorNRGBA)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dst
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func rotatePoint(x, y, sin, cos float64) (float64, float64) {
 | 
				
			||||||
 | 
						return x*cos - y*sin, x*sin + y*cos
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func rotatedSize(w, h int, angle float64) (int, int) {
 | 
				
			||||||
 | 
						if w <= 0 || h <= 0 {
 | 
				
			||||||
 | 
							return 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sin, cos := math.Sincos(math.Pi * angle / 180)
 | 
				
			||||||
 | 
						x1, y1 := rotatePoint(float64(w-1), 0, sin, cos)
 | 
				
			||||||
 | 
						x2, y2 := rotatePoint(float64(w-1), float64(h-1), sin, cos)
 | 
				
			||||||
 | 
						x3, y3 := rotatePoint(0, float64(h-1), sin, cos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						minx := math.Min(x1, math.Min(x2, math.Min(x3, 0)))
 | 
				
			||||||
 | 
						maxx := math.Max(x1, math.Max(x2, math.Max(x3, 0)))
 | 
				
			||||||
 | 
						miny := math.Min(y1, math.Min(y2, math.Min(y3, 0)))
 | 
				
			||||||
 | 
						maxy := math.Max(y1, math.Max(y2, math.Max(y3, 0)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						neww := maxx - minx + 1
 | 
				
			||||||
 | 
						if neww-math.Floor(neww) > 0.1 {
 | 
				
			||||||
 | 
							neww++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						newh := maxy - miny + 1
 | 
				
			||||||
 | 
						if newh-math.Floor(newh) > 0.1 {
 | 
				
			||||||
 | 
							newh++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return int(neww), int(newh)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func interpolatePoint(dst *image.NRGBA, dstX, dstY int, src *image.NRGBA, xf, yf float64, bgColor color.NRGBA) {
 | 
				
			||||||
 | 
						j := dstY*dst.Stride + dstX*4
 | 
				
			||||||
 | 
						d := dst.Pix[j : j+4 : j+4]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						x0 := int(math.Floor(xf))
 | 
				
			||||||
 | 
						y0 := int(math.Floor(yf))
 | 
				
			||||||
 | 
						bounds := src.Bounds()
 | 
				
			||||||
 | 
						if !image.Pt(x0, y0).In(image.Rect(bounds.Min.X-1, bounds.Min.Y-1, bounds.Max.X, bounds.Max.Y)) {
 | 
				
			||||||
 | 
							d[0] = bgColor.R
 | 
				
			||||||
 | 
							d[1] = bgColor.G
 | 
				
			||||||
 | 
							d[2] = bgColor.B
 | 
				
			||||||
 | 
							d[3] = bgColor.A
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xq := xf - float64(x0)
 | 
				
			||||||
 | 
						yq := yf - float64(y0)
 | 
				
			||||||
 | 
						points := [4]image.Point{
 | 
				
			||||||
 | 
							{x0, y0},
 | 
				
			||||||
 | 
							{x0 + 1, y0},
 | 
				
			||||||
 | 
							{x0, y0 + 1},
 | 
				
			||||||
 | 
							{x0 + 1, y0 + 1},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						weights := [4]float64{
 | 
				
			||||||
 | 
							(1 - xq) * (1 - yq),
 | 
				
			||||||
 | 
							xq * (1 - yq),
 | 
				
			||||||
 | 
							(1 - xq) * yq,
 | 
				
			||||||
 | 
							xq * yq,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var r, g, b, a float64
 | 
				
			||||||
 | 
						for i := 0; i < 4; i++ {
 | 
				
			||||||
 | 
							p := points[i]
 | 
				
			||||||
 | 
							w := weights[i]
 | 
				
			||||||
 | 
							if p.In(bounds) {
 | 
				
			||||||
 | 
								i := p.Y*src.Stride + p.X*4
 | 
				
			||||||
 | 
								s := src.Pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
								wa := float64(s[3]) * w
 | 
				
			||||||
 | 
								r += float64(s[0]) * wa
 | 
				
			||||||
 | 
								g += float64(s[1]) * wa
 | 
				
			||||||
 | 
								b += float64(s[2]) * wa
 | 
				
			||||||
 | 
								a += wa
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								wa := float64(bgColor.A) * w
 | 
				
			||||||
 | 
								r += float64(bgColor.R) * wa
 | 
				
			||||||
 | 
								g += float64(bgColor.G) * wa
 | 
				
			||||||
 | 
								b += float64(bgColor.B) * wa
 | 
				
			||||||
 | 
								a += wa
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if a != 0 {
 | 
				
			||||||
 | 
							aInv := 1 / a
 | 
				
			||||||
 | 
							d[0] = clamp(r * aInv)
 | 
				
			||||||
 | 
							d[1] = clamp(g * aInv)
 | 
				
			||||||
 | 
							d[2] = clamp(b * aInv)
 | 
				
			||||||
 | 
							d[3] = clamp(a)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										167
									
								
								vendor/github.com/disintegration/imaging/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								vendor/github.com/disintegration/imaging/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,167 @@
 | 
				
			|||||||
 | 
					package imaging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// parallel processes the data in separate goroutines.
 | 
				
			||||||
 | 
					func parallel(start, stop int, fn func(<-chan int)) {
 | 
				
			||||||
 | 
						count := stop - start
 | 
				
			||||||
 | 
						if count < 1 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						procs := runtime.GOMAXPROCS(0)
 | 
				
			||||||
 | 
						if procs > count {
 | 
				
			||||||
 | 
							procs = count
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c := make(chan int, count)
 | 
				
			||||||
 | 
						for i := start; i < stop; i++ {
 | 
				
			||||||
 | 
							c <- i
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						close(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var wg sync.WaitGroup
 | 
				
			||||||
 | 
						for i := 0; i < procs; i++ {
 | 
				
			||||||
 | 
							wg.Add(1)
 | 
				
			||||||
 | 
							go func() {
 | 
				
			||||||
 | 
								defer wg.Done()
 | 
				
			||||||
 | 
								fn(c)
 | 
				
			||||||
 | 
							}()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wg.Wait()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// absint returns the absolute value of i.
 | 
				
			||||||
 | 
					func absint(i int) int {
 | 
				
			||||||
 | 
						if i < 0 {
 | 
				
			||||||
 | 
							return -i
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return i
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// clamp rounds and clamps float64 value to fit into uint8.
 | 
				
			||||||
 | 
					func clamp(x float64) uint8 {
 | 
				
			||||||
 | 
						v := int64(x + 0.5)
 | 
				
			||||||
 | 
						if v > 255 {
 | 
				
			||||||
 | 
							return 255
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if v > 0 {
 | 
				
			||||||
 | 
							return uint8(v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func reverse(pix []uint8) {
 | 
				
			||||||
 | 
						if len(pix) <= 4 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i := 0
 | 
				
			||||||
 | 
						j := len(pix) - 4
 | 
				
			||||||
 | 
						for i < j {
 | 
				
			||||||
 | 
							pi := pix[i : i+4 : i+4]
 | 
				
			||||||
 | 
							pj := pix[j : j+4 : j+4]
 | 
				
			||||||
 | 
							pi[0], pj[0] = pj[0], pi[0]
 | 
				
			||||||
 | 
							pi[1], pj[1] = pj[1], pi[1]
 | 
				
			||||||
 | 
							pi[2], pj[2] = pj[2], pi[2]
 | 
				
			||||||
 | 
							pi[3], pj[3] = pj[3], pi[3]
 | 
				
			||||||
 | 
							i += 4
 | 
				
			||||||
 | 
							j -= 4
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func toNRGBA(img image.Image) *image.NRGBA {
 | 
				
			||||||
 | 
						if img, ok := img.(*image.NRGBA); ok {
 | 
				
			||||||
 | 
							return &image.NRGBA{
 | 
				
			||||||
 | 
								Pix:    img.Pix,
 | 
				
			||||||
 | 
								Stride: img.Stride,
 | 
				
			||||||
 | 
								Rect:   img.Rect.Sub(img.Rect.Min),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return Clone(img)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// rgbToHSL converts a color from RGB to HSL.
 | 
				
			||||||
 | 
					func rgbToHSL(r, g, b uint8) (float64, float64, float64) {
 | 
				
			||||||
 | 
						rr := float64(r) / 255
 | 
				
			||||||
 | 
						gg := float64(g) / 255
 | 
				
			||||||
 | 
						bb := float64(b) / 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						max := math.Max(rr, math.Max(gg, bb))
 | 
				
			||||||
 | 
						min := math.Min(rr, math.Min(gg, bb))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						l := (max + min) / 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if max == min {
 | 
				
			||||||
 | 
							return 0, 0, l
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var h, s float64
 | 
				
			||||||
 | 
						d := max - min
 | 
				
			||||||
 | 
						if l > 0.5 {
 | 
				
			||||||
 | 
							s = d / (2 - max - min)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							s = d / (max + min)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch max {
 | 
				
			||||||
 | 
						case rr:
 | 
				
			||||||
 | 
							h = (gg - bb) / d
 | 
				
			||||||
 | 
							if g < b {
 | 
				
			||||||
 | 
								h += 6
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case gg:
 | 
				
			||||||
 | 
							h = (bb-rr)/d + 2
 | 
				
			||||||
 | 
						case bb:
 | 
				
			||||||
 | 
							h = (rr-gg)/d + 4
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h /= 6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return h, s, l
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// hslToRGB converts a color from HSL to RGB.
 | 
				
			||||||
 | 
					func hslToRGB(h, s, l float64) (uint8, uint8, uint8) {
 | 
				
			||||||
 | 
						var r, g, b float64
 | 
				
			||||||
 | 
						if s == 0 {
 | 
				
			||||||
 | 
							v := clamp(l * 255)
 | 
				
			||||||
 | 
							return v, v, v
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var q float64
 | 
				
			||||||
 | 
						if l < 0.5 {
 | 
				
			||||||
 | 
							q = l * (1 + s)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							q = l + s - l*s
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						p := 2*l - q
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r = hueToRGB(p, q, h+1/3.0)
 | 
				
			||||||
 | 
						g = hueToRGB(p, q, h)
 | 
				
			||||||
 | 
						b = hueToRGB(p, q, h-1/3.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return clamp(r * 255), clamp(g * 255), clamp(b * 255)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func hueToRGB(p, q, t float64) float64 {
 | 
				
			||||||
 | 
						if t < 0 {
 | 
				
			||||||
 | 
							t++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if t > 1 {
 | 
				
			||||||
 | 
							t--
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if t < 1/6.0 {
 | 
				
			||||||
 | 
							return p + (q-p)*6*t
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if t < 1/2.0 {
 | 
				
			||||||
 | 
							return q
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if t < 2/3.0 {
 | 
				
			||||||
 | 
							return p + (q-p)*(2/3.0-t)*6
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return p
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/image/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/image/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					# This source code refers to The Go Authors for copyright purposes.
 | 
				
			||||||
 | 
					# The master list of authors is in the main Go distribution,
 | 
				
			||||||
 | 
					# visible at http://tip.golang.org/AUTHORS.
 | 
				
			||||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/image/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/image/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					# This source code was written by the Go contributors.
 | 
				
			||||||
 | 
					# The master list of contributors is in the main Go distribution,
 | 
				
			||||||
 | 
					# visible at http://tip.golang.org/CONTRIBUTORS.
 | 
				
			||||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/image/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/image/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					Copyright (c) 2009 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					modification, are permitted provided that the following conditions are
 | 
				
			||||||
 | 
					met:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					   * Redistributions in binary form must reproduce the above
 | 
				
			||||||
 | 
					copyright notice, this list of conditions and the following disclaimer
 | 
				
			||||||
 | 
					in the documentation and/or other materials provided with the
 | 
				
			||||||
 | 
					distribution.
 | 
				
			||||||
 | 
					   * Neither the name of Google Inc. nor the names of its
 | 
				
			||||||
 | 
					contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					this software without specific prior written permission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
				
			||||||
 | 
					"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
				
			||||||
 | 
					A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
				
			||||||
 | 
					OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
				
			||||||
 | 
					SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
				
			||||||
 | 
					LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
				
			||||||
 | 
					DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
				
			||||||
 | 
					THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
							
								
								
									
										22
									
								
								vendor/golang.org/x/image/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/golang.org/x/image/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					Additional IP Rights Grant (Patents)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"This implementation" means the copyrightable works distributed by
 | 
				
			||||||
 | 
					Google as part of the Go project.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Google hereby grants to You a perpetual, worldwide, non-exclusive,
 | 
				
			||||||
 | 
					no-charge, royalty-free, irrevocable (except as stated in this section)
 | 
				
			||||||
 | 
					patent license to make, have made, use, offer to sell, sell, import,
 | 
				
			||||||
 | 
					transfer and otherwise run, modify and propagate the contents of this
 | 
				
			||||||
 | 
					implementation of Go, where such license applies only to those patent
 | 
				
			||||||
 | 
					claims, both currently owned or controlled by Google and acquired in
 | 
				
			||||||
 | 
					the future, licensable by Google that are necessarily infringed by this
 | 
				
			||||||
 | 
					implementation of Go.  This grant does not include claims that would be
 | 
				
			||||||
 | 
					infringed only as a consequence of further modification of this
 | 
				
			||||||
 | 
					implementation.  If you or your agent or exclusive licensee institute or
 | 
				
			||||||
 | 
					order or agree to the institution of patent litigation against any
 | 
				
			||||||
 | 
					entity (including a cross-claim or counterclaim in a lawsuit) alleging
 | 
				
			||||||
 | 
					that this implementation of Go or any code incorporated within this
 | 
				
			||||||
 | 
					implementation of Go constitutes direct or contributory patent
 | 
				
			||||||
 | 
					infringement, or inducement of patent infringement, then any patent
 | 
				
			||||||
 | 
					rights granted to you under this License for this implementation of Go
 | 
				
			||||||
 | 
					shall terminate as of the date such litigation is filed.
 | 
				
			||||||
							
								
								
									
										213
									
								
								vendor/golang.org/x/image/bmp/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								vendor/golang.org/x/image/bmp/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,213 @@
 | 
				
			|||||||
 | 
					// Copyright 2011 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package bmp implements a BMP image decoder and encoder.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
 | 
				
			||||||
 | 
					package bmp // import "golang.org/x/image/bmp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrUnsupported means that the input BMP image uses a valid but unsupported
 | 
				
			||||||
 | 
					// feature.
 | 
				
			||||||
 | 
					var ErrUnsupported = errors.New("bmp: unsupported BMP image")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readUint16(b []byte) uint16 {
 | 
				
			||||||
 | 
						return uint16(b[0]) | uint16(b[1])<<8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readUint32(b []byte) uint32 {
 | 
				
			||||||
 | 
						return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// decodePaletted reads an 8 bit-per-pixel BMP image from r.
 | 
				
			||||||
 | 
					// If topDown is false, the image rows will be read bottom-up.
 | 
				
			||||||
 | 
					func decodePaletted(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
 | 
				
			||||||
 | 
						paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette))
 | 
				
			||||||
 | 
						if c.Width == 0 || c.Height == 0 {
 | 
				
			||||||
 | 
							return paletted, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var tmp [4]byte
 | 
				
			||||||
 | 
						y0, y1, yDelta := c.Height-1, -1, -1
 | 
				
			||||||
 | 
						if topDown {
 | 
				
			||||||
 | 
							y0, y1, yDelta = 0, c.Height, +1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for y := y0; y != y1; y += yDelta {
 | 
				
			||||||
 | 
							p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
 | 
				
			||||||
 | 
							if _, err := io.ReadFull(r, p); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Each row is 4-byte aligned.
 | 
				
			||||||
 | 
							if c.Width%4 != 0 {
 | 
				
			||||||
 | 
								_, err := io.ReadFull(r, tmp[:4-c.Width%4])
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return paletted, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// decodeRGB reads a 24 bit-per-pixel BMP image from r.
 | 
				
			||||||
 | 
					// If topDown is false, the image rows will be read bottom-up.
 | 
				
			||||||
 | 
					func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
 | 
				
			||||||
 | 
						rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))
 | 
				
			||||||
 | 
						if c.Width == 0 || c.Height == 0 {
 | 
				
			||||||
 | 
							return rgba, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// There are 3 bytes per pixel, and each row is 4-byte aligned.
 | 
				
			||||||
 | 
						b := make([]byte, (3*c.Width+3)&^3)
 | 
				
			||||||
 | 
						y0, y1, yDelta := c.Height-1, -1, -1
 | 
				
			||||||
 | 
						if topDown {
 | 
				
			||||||
 | 
							y0, y1, yDelta = 0, c.Height, +1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for y := y0; y != y1; y += yDelta {
 | 
				
			||||||
 | 
							if _, err := io.ReadFull(r, b); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
 | 
				
			||||||
 | 
							for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
 | 
				
			||||||
 | 
								// BMP images are stored in BGR order rather than RGB order.
 | 
				
			||||||
 | 
								p[i+0] = b[j+2]
 | 
				
			||||||
 | 
								p[i+1] = b[j+1]
 | 
				
			||||||
 | 
								p[i+2] = b[j+0]
 | 
				
			||||||
 | 
								p[i+3] = 0xFF
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rgba, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// decodeNRGBA reads a 32 bit-per-pixel BMP image from r.
 | 
				
			||||||
 | 
					// If topDown is false, the image rows will be read bottom-up.
 | 
				
			||||||
 | 
					func decodeNRGBA(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
 | 
				
			||||||
 | 
						rgba := image.NewNRGBA(image.Rect(0, 0, c.Width, c.Height))
 | 
				
			||||||
 | 
						if c.Width == 0 || c.Height == 0 {
 | 
				
			||||||
 | 
							return rgba, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						y0, y1, yDelta := c.Height-1, -1, -1
 | 
				
			||||||
 | 
						if topDown {
 | 
				
			||||||
 | 
							y0, y1, yDelta = 0, c.Height, +1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for y := y0; y != y1; y += yDelta {
 | 
				
			||||||
 | 
							p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
 | 
				
			||||||
 | 
							if _, err := io.ReadFull(r, p); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for i := 0; i < len(p); i += 4 {
 | 
				
			||||||
 | 
								// BMP images are stored in BGRA order rather than RGBA order.
 | 
				
			||||||
 | 
								p[i+0], p[i+2] = p[i+2], p[i+0]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rgba, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decode reads a BMP image from r and returns it as an image.Image.
 | 
				
			||||||
 | 
					// Limitation: The file must be 8, 24 or 32 bits per pixel.
 | 
				
			||||||
 | 
					func Decode(r io.Reader) (image.Image, error) {
 | 
				
			||||||
 | 
						c, bpp, topDown, err := decodeConfig(r)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch bpp {
 | 
				
			||||||
 | 
						case 8:
 | 
				
			||||||
 | 
							return decodePaletted(r, c, topDown)
 | 
				
			||||||
 | 
						case 24:
 | 
				
			||||||
 | 
							return decodeRGB(r, c, topDown)
 | 
				
			||||||
 | 
						case 32:
 | 
				
			||||||
 | 
							return decodeNRGBA(r, c, topDown)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						panic("unreachable")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeConfig returns the color model and dimensions of a BMP image without
 | 
				
			||||||
 | 
					// decoding the entire image.
 | 
				
			||||||
 | 
					// Limitation: The file must be 8, 24 or 32 bits per pixel.
 | 
				
			||||||
 | 
					func DecodeConfig(r io.Reader) (image.Config, error) {
 | 
				
			||||||
 | 
						config, _, _, err := decodeConfig(r)
 | 
				
			||||||
 | 
						return config, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, err error) {
 | 
				
			||||||
 | 
						// We only support those BMP images that are a BITMAPFILEHEADER
 | 
				
			||||||
 | 
						// immediately followed by a BITMAPINFOHEADER.
 | 
				
			||||||
 | 
						const (
 | 
				
			||||||
 | 
							fileHeaderLen   = 14
 | 
				
			||||||
 | 
							infoHeaderLen   = 40
 | 
				
			||||||
 | 
							v4InfoHeaderLen = 108
 | 
				
			||||||
 | 
							v5InfoHeaderLen = 124
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						var b [1024]byte
 | 
				
			||||||
 | 
						if _, err := io.ReadFull(r, b[:fileHeaderLen+4]); err != nil {
 | 
				
			||||||
 | 
							return image.Config{}, 0, false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if string(b[:2]) != "BM" {
 | 
				
			||||||
 | 
							return image.Config{}, 0, false, errors.New("bmp: invalid format")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						offset := readUint32(b[10:14])
 | 
				
			||||||
 | 
						infoLen := readUint32(b[14:18])
 | 
				
			||||||
 | 
						if infoLen != infoHeaderLen && infoLen != v4InfoHeaderLen && infoLen != v5InfoHeaderLen {
 | 
				
			||||||
 | 
							return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil {
 | 
				
			||||||
 | 
							return image.Config{}, 0, false, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						width := int(int32(readUint32(b[18:22])))
 | 
				
			||||||
 | 
						height := int(int32(readUint32(b[22:26])))
 | 
				
			||||||
 | 
						if height < 0 {
 | 
				
			||||||
 | 
							height, topDown = -height, true
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if width < 0 || height < 0 {
 | 
				
			||||||
 | 
							return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// We only support 1 plane and 8, 24 or 32 bits per pixel and no
 | 
				
			||||||
 | 
						// compression.
 | 
				
			||||||
 | 
						planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
 | 
				
			||||||
 | 
						// if compression is set to BITFIELDS, but the bitmask is set to the default bitmask
 | 
				
			||||||
 | 
						// that would be used if compression was set to 0, we can continue as if compression was 0
 | 
				
			||||||
 | 
						if compression == 3 && infoLen > infoHeaderLen &&
 | 
				
			||||||
 | 
							readUint32(b[54:58]) == 0xff0000 && readUint32(b[58:62]) == 0xff00 &&
 | 
				
			||||||
 | 
							readUint32(b[62:66]) == 0xff && readUint32(b[66:70]) == 0xff000000 {
 | 
				
			||||||
 | 
							compression = 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if planes != 1 || compression != 0 {
 | 
				
			||||||
 | 
							return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch bpp {
 | 
				
			||||||
 | 
						case 8:
 | 
				
			||||||
 | 
							if offset != fileHeaderLen+infoLen+256*4 {
 | 
				
			||||||
 | 
								return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_, err = io.ReadFull(r, b[:256*4])
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return image.Config{}, 0, false, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pcm := make(color.Palette, 256)
 | 
				
			||||||
 | 
							for i := range pcm {
 | 
				
			||||||
 | 
								// BMP images are stored in BGR order rather than RGB order.
 | 
				
			||||||
 | 
								// Every 4th byte is padding.
 | 
				
			||||||
 | 
								pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, nil
 | 
				
			||||||
 | 
						case 24:
 | 
				
			||||||
 | 
							if offset != fileHeaderLen+infoLen {
 | 
				
			||||||
 | 
								return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, nil
 | 
				
			||||||
 | 
						case 32:
 | 
				
			||||||
 | 
							if offset != fileHeaderLen+infoLen {
 | 
				
			||||||
 | 
								return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return image.Config{}, 0, false, ErrUnsupported
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										262
									
								
								vendor/golang.org/x/image/bmp/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								vendor/golang.org/x/image/bmp/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
				
			|||||||
 | 
					// Copyright 2013 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package bmp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type header struct {
 | 
				
			||||||
 | 
						sigBM           [2]byte
 | 
				
			||||||
 | 
						fileSize        uint32
 | 
				
			||||||
 | 
						resverved       [2]uint16
 | 
				
			||||||
 | 
						pixOffset       uint32
 | 
				
			||||||
 | 
						dibHeaderSize   uint32
 | 
				
			||||||
 | 
						width           uint32
 | 
				
			||||||
 | 
						height          uint32
 | 
				
			||||||
 | 
						colorPlane      uint16
 | 
				
			||||||
 | 
						bpp             uint16
 | 
				
			||||||
 | 
						compression     uint32
 | 
				
			||||||
 | 
						imageSize       uint32
 | 
				
			||||||
 | 
						xPixelsPerMeter uint32
 | 
				
			||||||
 | 
						yPixelsPerMeter uint32
 | 
				
			||||||
 | 
						colorUse        uint32
 | 
				
			||||||
 | 
						colorImportant  uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
 | 
				
			||||||
 | 
						var padding []byte
 | 
				
			||||||
 | 
						if dx < step {
 | 
				
			||||||
 | 
							padding = make([]byte, step-dx)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for y := dy - 1; y >= 0; y-- {
 | 
				
			||||||
 | 
							min := y*stride + 0
 | 
				
			||||||
 | 
							max := y*stride + dx
 | 
				
			||||||
 | 
							if _, err := w.Write(pix[min:max]); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if padding != nil {
 | 
				
			||||||
 | 
								if _, err := w.Write(padding); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
 | 
				
			||||||
 | 
						buf := make([]byte, step)
 | 
				
			||||||
 | 
						if opaque {
 | 
				
			||||||
 | 
							for y := dy - 1; y >= 0; y-- {
 | 
				
			||||||
 | 
								min := y*stride + 0
 | 
				
			||||||
 | 
								max := y*stride + dx*4
 | 
				
			||||||
 | 
								off := 0
 | 
				
			||||||
 | 
								for i := min; i < max; i += 4 {
 | 
				
			||||||
 | 
									buf[off+2] = pix[i+0]
 | 
				
			||||||
 | 
									buf[off+1] = pix[i+1]
 | 
				
			||||||
 | 
									buf[off+0] = pix[i+2]
 | 
				
			||||||
 | 
									off += 3
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for y := dy - 1; y >= 0; y-- {
 | 
				
			||||||
 | 
								min := y*stride + 0
 | 
				
			||||||
 | 
								max := y*stride + dx*4
 | 
				
			||||||
 | 
								off := 0
 | 
				
			||||||
 | 
								for i := min; i < max; i += 4 {
 | 
				
			||||||
 | 
									a := uint32(pix[i+3])
 | 
				
			||||||
 | 
									if a == 0 {
 | 
				
			||||||
 | 
										buf[off+2] = 0
 | 
				
			||||||
 | 
										buf[off+1] = 0
 | 
				
			||||||
 | 
										buf[off+0] = 0
 | 
				
			||||||
 | 
										buf[off+3] = 0
 | 
				
			||||||
 | 
										off += 4
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									} else if a == 0xff {
 | 
				
			||||||
 | 
										buf[off+2] = pix[i+0]
 | 
				
			||||||
 | 
										buf[off+1] = pix[i+1]
 | 
				
			||||||
 | 
										buf[off+0] = pix[i+2]
 | 
				
			||||||
 | 
										buf[off+3] = 0xff
 | 
				
			||||||
 | 
										off += 4
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									buf[off+2] = uint8(((uint32(pix[i+0]) * 0xffff) / a) >> 8)
 | 
				
			||||||
 | 
									buf[off+1] = uint8(((uint32(pix[i+1]) * 0xffff) / a) >> 8)
 | 
				
			||||||
 | 
									buf[off+0] = uint8(((uint32(pix[i+2]) * 0xffff) / a) >> 8)
 | 
				
			||||||
 | 
									buf[off+3] = uint8(a)
 | 
				
			||||||
 | 
									off += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeNRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
 | 
				
			||||||
 | 
						buf := make([]byte, step)
 | 
				
			||||||
 | 
						if opaque {
 | 
				
			||||||
 | 
							for y := dy - 1; y >= 0; y-- {
 | 
				
			||||||
 | 
								min := y*stride + 0
 | 
				
			||||||
 | 
								max := y*stride + dx*4
 | 
				
			||||||
 | 
								off := 0
 | 
				
			||||||
 | 
								for i := min; i < max; i += 4 {
 | 
				
			||||||
 | 
									buf[off+2] = pix[i+0]
 | 
				
			||||||
 | 
									buf[off+1] = pix[i+1]
 | 
				
			||||||
 | 
									buf[off+0] = pix[i+2]
 | 
				
			||||||
 | 
									off += 3
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							for y := dy - 1; y >= 0; y-- {
 | 
				
			||||||
 | 
								min := y*stride + 0
 | 
				
			||||||
 | 
								max := y*stride + dx*4
 | 
				
			||||||
 | 
								off := 0
 | 
				
			||||||
 | 
								for i := min; i < max; i += 4 {
 | 
				
			||||||
 | 
									buf[off+2] = pix[i+0]
 | 
				
			||||||
 | 
									buf[off+1] = pix[i+1]
 | 
				
			||||||
 | 
									buf[off+0] = pix[i+2]
 | 
				
			||||||
 | 
									buf[off+3] = pix[i+3]
 | 
				
			||||||
 | 
									off += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encode(w io.Writer, m image.Image, step int) error {
 | 
				
			||||||
 | 
						b := m.Bounds()
 | 
				
			||||||
 | 
						buf := make([]byte, step)
 | 
				
			||||||
 | 
						for y := b.Max.Y - 1; y >= b.Min.Y; y-- {
 | 
				
			||||||
 | 
							off := 0
 | 
				
			||||||
 | 
							for x := b.Min.X; x < b.Max.X; x++ {
 | 
				
			||||||
 | 
								r, g, b, _ := m.At(x, y).RGBA()
 | 
				
			||||||
 | 
								buf[off+2] = byte(r >> 8)
 | 
				
			||||||
 | 
								buf[off+1] = byte(g >> 8)
 | 
				
			||||||
 | 
								buf[off+0] = byte(b >> 8)
 | 
				
			||||||
 | 
								off += 3
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Encode writes the image m to w in BMP format.
 | 
				
			||||||
 | 
					func Encode(w io.Writer, m image.Image) error {
 | 
				
			||||||
 | 
						d := m.Bounds().Size()
 | 
				
			||||||
 | 
						if d.X < 0 || d.Y < 0 {
 | 
				
			||||||
 | 
							return errors.New("bmp: negative bounds")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h := &header{
 | 
				
			||||||
 | 
							sigBM:         [2]byte{'B', 'M'},
 | 
				
			||||||
 | 
							fileSize:      14 + 40,
 | 
				
			||||||
 | 
							pixOffset:     14 + 40,
 | 
				
			||||||
 | 
							dibHeaderSize: 40,
 | 
				
			||||||
 | 
							width:         uint32(d.X),
 | 
				
			||||||
 | 
							height:        uint32(d.Y),
 | 
				
			||||||
 | 
							colorPlane:    1,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var step int
 | 
				
			||||||
 | 
						var palette []byte
 | 
				
			||||||
 | 
						var opaque bool
 | 
				
			||||||
 | 
						switch m := m.(type) {
 | 
				
			||||||
 | 
						case *image.Gray:
 | 
				
			||||||
 | 
							step = (d.X + 3) &^ 3
 | 
				
			||||||
 | 
							palette = make([]byte, 1024)
 | 
				
			||||||
 | 
							for i := 0; i < 256; i++ {
 | 
				
			||||||
 | 
								palette[i*4+0] = uint8(i)
 | 
				
			||||||
 | 
								palette[i*4+1] = uint8(i)
 | 
				
			||||||
 | 
								palette[i*4+2] = uint8(i)
 | 
				
			||||||
 | 
								palette[i*4+3] = 0xFF
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							h.imageSize = uint32(d.Y * step)
 | 
				
			||||||
 | 
							h.fileSize += uint32(len(palette)) + h.imageSize
 | 
				
			||||||
 | 
							h.pixOffset += uint32(len(palette))
 | 
				
			||||||
 | 
							h.bpp = 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case *image.Paletted:
 | 
				
			||||||
 | 
							step = (d.X + 3) &^ 3
 | 
				
			||||||
 | 
							palette = make([]byte, 1024)
 | 
				
			||||||
 | 
							for i := 0; i < len(m.Palette) && i < 256; i++ {
 | 
				
			||||||
 | 
								r, g, b, _ := m.Palette[i].RGBA()
 | 
				
			||||||
 | 
								palette[i*4+0] = uint8(b >> 8)
 | 
				
			||||||
 | 
								palette[i*4+1] = uint8(g >> 8)
 | 
				
			||||||
 | 
								palette[i*4+2] = uint8(r >> 8)
 | 
				
			||||||
 | 
								palette[i*4+3] = 0xFF
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							h.imageSize = uint32(d.Y * step)
 | 
				
			||||||
 | 
							h.fileSize += uint32(len(palette)) + h.imageSize
 | 
				
			||||||
 | 
							h.pixOffset += uint32(len(palette))
 | 
				
			||||||
 | 
							h.bpp = 8
 | 
				
			||||||
 | 
						case *image.RGBA:
 | 
				
			||||||
 | 
							opaque = m.Opaque()
 | 
				
			||||||
 | 
							if opaque {
 | 
				
			||||||
 | 
								step = (3*d.X + 3) &^ 3
 | 
				
			||||||
 | 
								h.bpp = 24
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								step = 4 * d.X
 | 
				
			||||||
 | 
								h.bpp = 32
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							h.imageSize = uint32(d.Y * step)
 | 
				
			||||||
 | 
							h.fileSize += h.imageSize
 | 
				
			||||||
 | 
						case *image.NRGBA:
 | 
				
			||||||
 | 
							opaque = m.Opaque()
 | 
				
			||||||
 | 
							if opaque {
 | 
				
			||||||
 | 
								step = (3*d.X + 3) &^ 3
 | 
				
			||||||
 | 
								h.bpp = 24
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								step = 4 * d.X
 | 
				
			||||||
 | 
								h.bpp = 32
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							h.imageSize = uint32(d.Y * step)
 | 
				
			||||||
 | 
							h.fileSize += h.imageSize
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							step = (3*d.X + 3) &^ 3
 | 
				
			||||||
 | 
							h.imageSize = uint32(d.Y * step)
 | 
				
			||||||
 | 
							h.fileSize += h.imageSize
 | 
				
			||||||
 | 
							h.bpp = 24
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := binary.Write(w, binary.LittleEndian, h); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if palette != nil {
 | 
				
			||||||
 | 
							if err := binary.Write(w, binary.LittleEndian, palette); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d.X == 0 || d.Y == 0 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch m := m.(type) {
 | 
				
			||||||
 | 
						case *image.Gray:
 | 
				
			||||||
 | 
							return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
 | 
				
			||||||
 | 
						case *image.Paletted:
 | 
				
			||||||
 | 
							return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
 | 
				
			||||||
 | 
						case *image.RGBA:
 | 
				
			||||||
 | 
							return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
 | 
				
			||||||
 | 
						case *image.NRGBA:
 | 
				
			||||||
 | 
							return encodeNRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return encode(w, m, step)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										697
									
								
								vendor/golang.org/x/image/ccitt/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										697
									
								
								vendor/golang.org/x/image/ccitt/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,697 @@
 | 
				
			|||||||
 | 
					// Copyright 2019 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:generate go run gen.go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package ccitt implements a CCITT (fax) image decoder.
 | 
				
			||||||
 | 
					package ccitt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"math/bits"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						errInvalidBounds           = errors.New("ccitt: invalid bounds")
 | 
				
			||||||
 | 
						errInvalidCode             = errors.New("ccitt: invalid code")
 | 
				
			||||||
 | 
						errInvalidMode             = errors.New("ccitt: invalid mode")
 | 
				
			||||||
 | 
						errInvalidOffset           = errors.New("ccitt: invalid offset")
 | 
				
			||||||
 | 
						errMissingEOL              = errors.New("ccitt: missing End-of-Line")
 | 
				
			||||||
 | 
						errRunLengthOverflowsWidth = errors.New("ccitt: run length overflows width")
 | 
				
			||||||
 | 
						errRunLengthTooLong        = errors.New("ccitt: run length too long")
 | 
				
			||||||
 | 
						errUnsupportedMode         = errors.New("ccitt: unsupported mode")
 | 
				
			||||||
 | 
						errUnsupportedSubFormat    = errors.New("ccitt: unsupported sub-format")
 | 
				
			||||||
 | 
						errUnsupportedWidth        = errors.New("ccitt: unsupported width")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Order specifies the bit ordering in a CCITT data stream.
 | 
				
			||||||
 | 
					type Order uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// LSB means Least Significant Bits first.
 | 
				
			||||||
 | 
						LSB Order = iota
 | 
				
			||||||
 | 
						// MSB means Most Significant Bits first.
 | 
				
			||||||
 | 
						MSB
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SubFormat represents that the CCITT format consists of a number of
 | 
				
			||||||
 | 
					// sub-formats. Decoding or encoding a CCITT data stream requires knowing the
 | 
				
			||||||
 | 
					// sub-format context. It is not represented in the data stream per se.
 | 
				
			||||||
 | 
					type SubFormat uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						Group3 SubFormat = iota
 | 
				
			||||||
 | 
						Group4
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Options are optional parameters.
 | 
				
			||||||
 | 
					type Options struct {
 | 
				
			||||||
 | 
						// Align means that some variable-bit-width codes are byte-aligned.
 | 
				
			||||||
 | 
						Align bool
 | 
				
			||||||
 | 
						// Invert means that black is the 1 bit or 0xFF byte, and white is 0.
 | 
				
			||||||
 | 
						Invert bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// maxWidth is the maximum (inclusive) supported width. This is a limitation of
 | 
				
			||||||
 | 
					// this implementation, to guard against integer overflow, and not anything
 | 
				
			||||||
 | 
					// inherent to the CCITT format.
 | 
				
			||||||
 | 
					const maxWidth = 1 << 20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func invertBytes(b []byte) {
 | 
				
			||||||
 | 
						for i, c := range b {
 | 
				
			||||||
 | 
							b[i] = ^c
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func reverseBitsWithinBytes(b []byte) {
 | 
				
			||||||
 | 
						for i, c := range b {
 | 
				
			||||||
 | 
							b[i] = bits.Reverse8(c)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// highBits writes to dst (1 bit per pixel, most significant bit first) the
 | 
				
			||||||
 | 
					// high (0x80) bits from src (1 byte per pixel). It returns the number of bytes
 | 
				
			||||||
 | 
					// written and read such that dst[:d] is the packed form of src[:s].
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// For example, if src starts with the 8 bytes [0x7D, 0x7E, 0x7F, 0x80, 0x81,
 | 
				
			||||||
 | 
					// 0x82, 0x00, 0xFF] then 0x1D will be written to dst[0].
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If src has (8 * len(dst)) or more bytes then only len(dst) bytes are
 | 
				
			||||||
 | 
					// written, (8 * len(dst)) bytes are read, and invert is ignored.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Otherwise, if len(src) is not a multiple of 8 then the final byte written to
 | 
				
			||||||
 | 
					// dst is padded with 1 bits (if invert is true) or 0 bits. If inverted, the 1s
 | 
				
			||||||
 | 
					// are typically temporary, e.g. they will be flipped back to 0s by an
 | 
				
			||||||
 | 
					// invertBytes call in the highBits caller, reader.Read.
 | 
				
			||||||
 | 
					func highBits(dst []byte, src []byte, invert bool) (d int, s int) {
 | 
				
			||||||
 | 
						// Pack as many complete groups of 8 src bytes as we can.
 | 
				
			||||||
 | 
						n := len(src) / 8
 | 
				
			||||||
 | 
						if n > len(dst) {
 | 
				
			||||||
 | 
							n = len(dst)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dstN := dst[:n]
 | 
				
			||||||
 | 
						for i := range dstN {
 | 
				
			||||||
 | 
							src8 := src[i*8 : i*8+8]
 | 
				
			||||||
 | 
							dstN[i] = ((src8[0] & 0x80) >> 0) |
 | 
				
			||||||
 | 
								((src8[1] & 0x80) >> 1) |
 | 
				
			||||||
 | 
								((src8[2] & 0x80) >> 2) |
 | 
				
			||||||
 | 
								((src8[3] & 0x80) >> 3) |
 | 
				
			||||||
 | 
								((src8[4] & 0x80) >> 4) |
 | 
				
			||||||
 | 
								((src8[5] & 0x80) >> 5) |
 | 
				
			||||||
 | 
								((src8[6] & 0x80) >> 6) |
 | 
				
			||||||
 | 
								((src8[7] & 0x80) >> 7)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						d, s = n, 8*n
 | 
				
			||||||
 | 
						dst, src = dst[d:], src[s:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Pack up to 7 remaining src bytes, if there's room in dst.
 | 
				
			||||||
 | 
						if (len(dst) > 0) && (len(src) > 0) {
 | 
				
			||||||
 | 
							dstByte := byte(0)
 | 
				
			||||||
 | 
							if invert {
 | 
				
			||||||
 | 
								dstByte = 0xFF >> uint(len(src))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for n, srcByte := range src {
 | 
				
			||||||
 | 
								dstByte |= (srcByte & 0x80) >> uint(n)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							dst[0] = dstByte
 | 
				
			||||||
 | 
							d, s = d+1, s+len(src)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return d, s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type bitReader struct {
 | 
				
			||||||
 | 
						r io.Reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// readErr is the error returned from the most recent r.Read call. As the
 | 
				
			||||||
 | 
						// io.Reader documentation says, when r.Read returns (n, err), "always
 | 
				
			||||||
 | 
						// process the n > 0 bytes returned before considering the error err".
 | 
				
			||||||
 | 
						readErr error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// order is whether to process r's bytes LSB first or MSB first.
 | 
				
			||||||
 | 
						order Order
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The high nBits bits of the bits field hold upcoming bits in MSB order.
 | 
				
			||||||
 | 
						bits  uint64
 | 
				
			||||||
 | 
						nBits uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// bytes[br:bw] holds bytes read from r but not yet loaded into bits.
 | 
				
			||||||
 | 
						br    uint32
 | 
				
			||||||
 | 
						bw    uint32
 | 
				
			||||||
 | 
						bytes [1024]uint8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *bitReader) alignToByteBoundary() {
 | 
				
			||||||
 | 
						n := b.nBits & 7
 | 
				
			||||||
 | 
						b.bits <<= n
 | 
				
			||||||
 | 
						b.nBits -= n
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// nextBitMaxNBits is the maximum possible value of bitReader.nBits after a
 | 
				
			||||||
 | 
					// bitReader.nextBit call, provided that bitReader.nBits was not more than this
 | 
				
			||||||
 | 
					// value before that call.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Note that the decode function can unread bits, which can temporarily set the
 | 
				
			||||||
 | 
					// bitReader.nBits value above nextBitMaxNBits.
 | 
				
			||||||
 | 
					const nextBitMaxNBits = 31
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *bitReader) nextBit() (uint64, error) {
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							if b.nBits > 0 {
 | 
				
			||||||
 | 
								bit := b.bits >> 63
 | 
				
			||||||
 | 
								b.bits <<= 1
 | 
				
			||||||
 | 
								b.nBits--
 | 
				
			||||||
 | 
								return bit, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if available := b.bw - b.br; available >= 4 {
 | 
				
			||||||
 | 
								// Read 32 bits, even though b.bits is a uint64, since the decode
 | 
				
			||||||
 | 
								// function may need to unread up to maxCodeLength bits, putting
 | 
				
			||||||
 | 
								// them back in the remaining (64 - 32) bits. TestMaxCodeLength
 | 
				
			||||||
 | 
								// checks that the generated maxCodeLength constant fits.
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								// If changing the Uint32 call, also change nextBitMaxNBits.
 | 
				
			||||||
 | 
								b.bits = uint64(binary.BigEndian.Uint32(b.bytes[b.br:])) << 32
 | 
				
			||||||
 | 
								b.br += 4
 | 
				
			||||||
 | 
								b.nBits = 32
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							} else if available > 0 {
 | 
				
			||||||
 | 
								b.bits = uint64(b.bytes[b.br]) << (7 * 8)
 | 
				
			||||||
 | 
								b.br++
 | 
				
			||||||
 | 
								b.nBits = 8
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if b.readErr != nil {
 | 
				
			||||||
 | 
								return 0, b.readErr
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							n, err := b.r.Read(b.bytes[:])
 | 
				
			||||||
 | 
							b.br = 0
 | 
				
			||||||
 | 
							b.bw = uint32(n)
 | 
				
			||||||
 | 
							b.readErr = err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if b.order != MSB {
 | 
				
			||||||
 | 
								reverseBitsWithinBytes(b.bytes[:b.bw])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func decode(b *bitReader, decodeTable [][2]int16) (uint32, error) {
 | 
				
			||||||
 | 
						nBitsRead, bitsRead, state := uint32(0), uint64(0), int32(1)
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							bit, err := b.nextBit()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							bitsRead |= bit << (63 - nBitsRead)
 | 
				
			||||||
 | 
							nBitsRead++
 | 
				
			||||||
 | 
							// The "&1" is redundant, but can eliminate a bounds check.
 | 
				
			||||||
 | 
							state = int32(decodeTable[state][bit&1])
 | 
				
			||||||
 | 
							if state < 0 {
 | 
				
			||||||
 | 
								return uint32(^state), nil
 | 
				
			||||||
 | 
							} else if state == 0 {
 | 
				
			||||||
 | 
								// Unread the bits we've read, then return errInvalidCode.
 | 
				
			||||||
 | 
								b.bits = (b.bits >> nBitsRead) | bitsRead
 | 
				
			||||||
 | 
								b.nBits += nBitsRead
 | 
				
			||||||
 | 
								return 0, errInvalidCode
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type reader struct {
 | 
				
			||||||
 | 
						br        bitReader
 | 
				
			||||||
 | 
						subFormat SubFormat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// width is the image width in pixels.
 | 
				
			||||||
 | 
						width int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// rowsRemaining starts at the image height in pixels, when the reader is
 | 
				
			||||||
 | 
						// driven through the io.Reader interface, and decrements to zero as rows
 | 
				
			||||||
 | 
						// are decoded. When driven through DecodeIntoGray, this field is unused.
 | 
				
			||||||
 | 
						rowsRemaining int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// curr and prev hold the current and previous rows. Each element is either
 | 
				
			||||||
 | 
						// 0x00 (black) or 0xFF (white).
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// prev may be nil, when processing the first row.
 | 
				
			||||||
 | 
						curr []byte
 | 
				
			||||||
 | 
						prev []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ri is the read index. curr[:ri] are those bytes of curr that have been
 | 
				
			||||||
 | 
						// passed along via the Read method.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// When the reader is driven through DecodeIntoGray, instead of through the
 | 
				
			||||||
 | 
						// io.Reader interface, this field is unused.
 | 
				
			||||||
 | 
						ri int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// wi is the write index. curr[:wi] are those bytes of curr that have
 | 
				
			||||||
 | 
						// already been decoded via the decodeRow method.
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						// What this implementation calls wi is roughly equivalent to what the spec
 | 
				
			||||||
 | 
						// calls the a0 index.
 | 
				
			||||||
 | 
						wi int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// These fields are copied from the *Options (which may be nil).
 | 
				
			||||||
 | 
						align  bool
 | 
				
			||||||
 | 
						invert bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// atStartOfRow is whether we have just started the row. Some parts of the
 | 
				
			||||||
 | 
						// spec say to treat this situation as if "wi = -1".
 | 
				
			||||||
 | 
						atStartOfRow bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// penColorIsWhite is whether the next run is black or white.
 | 
				
			||||||
 | 
						penColorIsWhite bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// seenStartOfImage is whether we've called the startDecode method.
 | 
				
			||||||
 | 
						seenStartOfImage bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// readErr is a sticky error for the Read method.
 | 
				
			||||||
 | 
						readErr error
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) Read(p []byte) (int, error) {
 | 
				
			||||||
 | 
						if z.readErr != nil {
 | 
				
			||||||
 | 
							return 0, z.readErr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						originalP := p
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for len(p) > 0 {
 | 
				
			||||||
 | 
							// Allocate buffers (and decode any start-of-image codes), if
 | 
				
			||||||
 | 
							// processing the first or second row.
 | 
				
			||||||
 | 
							if z.curr == nil {
 | 
				
			||||||
 | 
								if !z.seenStartOfImage {
 | 
				
			||||||
 | 
									if z.readErr = z.startDecode(); z.readErr != nil {
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									z.atStartOfRow = true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								z.curr = make([]byte, z.width)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Decode the next row, if necessary.
 | 
				
			||||||
 | 
							if z.atStartOfRow {
 | 
				
			||||||
 | 
								if z.rowsRemaining <= 0 {
 | 
				
			||||||
 | 
									if z.readErr = z.finishDecode(); z.readErr != nil {
 | 
				
			||||||
 | 
										break
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									z.readErr = io.EOF
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if z.readErr = z.decodeRow(); z.readErr != nil {
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								z.rowsRemaining--
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Pack from z.curr (1 byte per pixel) to p (1 bit per pixel).
 | 
				
			||||||
 | 
							packD, packS := highBits(p, z.curr[z.ri:], z.invert)
 | 
				
			||||||
 | 
							p = p[packD:]
 | 
				
			||||||
 | 
							z.ri += packS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Prepare to decode the next row, if necessary.
 | 
				
			||||||
 | 
							if z.ri == len(z.curr) {
 | 
				
			||||||
 | 
								z.ri, z.curr, z.prev = 0, z.prev, z.curr
 | 
				
			||||||
 | 
								z.atStartOfRow = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n := len(originalP) - len(p)
 | 
				
			||||||
 | 
						if z.invert {
 | 
				
			||||||
 | 
							invertBytes(originalP[:n])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return n, z.readErr
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) penColor() byte {
 | 
				
			||||||
 | 
						if z.penColorIsWhite {
 | 
				
			||||||
 | 
							return 0xFF
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0x00
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) startDecode() error {
 | 
				
			||||||
 | 
						switch z.subFormat {
 | 
				
			||||||
 | 
						case Group3:
 | 
				
			||||||
 | 
							if err := z.decodeEOL(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case Group4:
 | 
				
			||||||
 | 
							// No-op.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return errUnsupportedSubFormat
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						z.seenStartOfImage = true
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) finishDecode() error {
 | 
				
			||||||
 | 
						numberOfEOLs := 0
 | 
				
			||||||
 | 
						switch z.subFormat {
 | 
				
			||||||
 | 
						case Group3:
 | 
				
			||||||
 | 
							// The stream ends with a RTC (Return To Control) of 6 consecutive
 | 
				
			||||||
 | 
							// EOL's, but we should have already just seen an EOL, either in
 | 
				
			||||||
 | 
							// z.startDecode (for a zero-height image) or in z.decodeRow.
 | 
				
			||||||
 | 
							numberOfEOLs = 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case Group4:
 | 
				
			||||||
 | 
							// The stream ends with two EOL's, the first of which is possibly
 | 
				
			||||||
 | 
							// byte-aligned.
 | 
				
			||||||
 | 
							numberOfEOLs = 2
 | 
				
			||||||
 | 
							if err := z.decodeEOL(); err == nil {
 | 
				
			||||||
 | 
								numberOfEOLs--
 | 
				
			||||||
 | 
							} else if err == errInvalidCode {
 | 
				
			||||||
 | 
								// Try again, this time starting from a byte boundary.
 | 
				
			||||||
 | 
								z.br.alignToByteBoundary()
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return errUnsupportedSubFormat
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for ; numberOfEOLs > 0; numberOfEOLs-- {
 | 
				
			||||||
 | 
							if err := z.decodeEOL(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) decodeEOL() error {
 | 
				
			||||||
 | 
						// TODO: EOL doesn't have to be in the modeDecodeTable. It could be in its
 | 
				
			||||||
 | 
						// own table, or we could just hard-code it, especially if we might need to
 | 
				
			||||||
 | 
						// cater for optional byte-alignment, or an arbitrary number (potentially
 | 
				
			||||||
 | 
						// more than 8) of 0-valued padding bits.
 | 
				
			||||||
 | 
						if mode, err := decode(&z.br, modeDecodeTable[:]); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						} else if mode != modeEOL {
 | 
				
			||||||
 | 
							return errMissingEOL
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) decodeRow() error {
 | 
				
			||||||
 | 
						z.wi = 0
 | 
				
			||||||
 | 
						z.atStartOfRow = true
 | 
				
			||||||
 | 
						z.penColorIsWhite = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if z.align {
 | 
				
			||||||
 | 
							z.br.alignToByteBoundary()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch z.subFormat {
 | 
				
			||||||
 | 
						case Group3:
 | 
				
			||||||
 | 
							for ; z.wi < len(z.curr); z.atStartOfRow = false {
 | 
				
			||||||
 | 
								if err := z.decodeRun(); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return z.decodeEOL()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case Group4:
 | 
				
			||||||
 | 
							for ; z.wi < len(z.curr); z.atStartOfRow = false {
 | 
				
			||||||
 | 
								mode, err := decode(&z.br, modeDecodeTable[:])
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								rm := readerMode{}
 | 
				
			||||||
 | 
								if mode < uint32(len(readerModes)) {
 | 
				
			||||||
 | 
									rm = readerModes[mode]
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if rm.function == nil {
 | 
				
			||||||
 | 
									return errInvalidMode
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if err := rm.function(z, rm.arg); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return errUnsupportedSubFormat
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (z *reader) decodeRun() error {
 | 
				
			||||||
 | 
						table := blackDecodeTable[:]
 | 
				
			||||||
 | 
						if z.penColorIsWhite {
 | 
				
			||||||
 | 
							table = whiteDecodeTable[:]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						total := 0
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							n, err := decode(&z.br, table)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n > maxWidth {
 | 
				
			||||||
 | 
								panic("unreachable")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							total += int(n)
 | 
				
			||||||
 | 
							if total > maxWidth {
 | 
				
			||||||
 | 
								return errRunLengthTooLong
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Anything 0x3F or below is a terminal code.
 | 
				
			||||||
 | 
							if n <= 0x3F {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if total > (len(z.curr) - z.wi) {
 | 
				
			||||||
 | 
							return errRunLengthOverflowsWidth
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dst := z.curr[z.wi : z.wi+total]
 | 
				
			||||||
 | 
						penColor := z.penColor()
 | 
				
			||||||
 | 
						for i := range dst {
 | 
				
			||||||
 | 
							dst[i] = penColor
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						z.wi += total
 | 
				
			||||||
 | 
						z.penColorIsWhite = !z.penColorIsWhite
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The various modes' semantics are based on determining a row of pixels'
 | 
				
			||||||
 | 
					// "changing elements": those pixels whose color differs from the one on its
 | 
				
			||||||
 | 
					// immediate left.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The row above the first row is implicitly all white. Similarly, the column
 | 
				
			||||||
 | 
					// to the left of the first column is implicitly all white.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// For example, here's Figure 1 in "ITU-T Recommendation T.6", where the
 | 
				
			||||||
 | 
					// current and previous rows contain black (B) and white (w) pixels. The a?
 | 
				
			||||||
 | 
					// indexes point into curr, the b? indexes point into prev.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//                 b1 b2
 | 
				
			||||||
 | 
					//                 v  v
 | 
				
			||||||
 | 
					// prev: BBBBBwwwwwBBBwwwww
 | 
				
			||||||
 | 
					// curr: BBBwwwwwBBBBBBwwww
 | 
				
			||||||
 | 
					//          ^    ^     ^
 | 
				
			||||||
 | 
					//          a0   a1    a2
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// a0 is the "reference element" or current decoder position, roughly
 | 
				
			||||||
 | 
					// equivalent to what this implementation calls reader.wi.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// a1 is the next changing element to the right of a0, on the "coding line"
 | 
				
			||||||
 | 
					// (the current row).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// a2 is the next changing element to the right of a1, again on curr.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// b1 is the first changing element on the "reference line" (the previous row)
 | 
				
			||||||
 | 
					// to the right of a0 and of opposite color to a0.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// b2 is the next changing element to the right of b1, again on prev.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The various modes calculate a1 (and a2, for modeH):
 | 
				
			||||||
 | 
					//  - modePass calculates that a1 is at or to the right of b2.
 | 
				
			||||||
 | 
					//  - modeH    calculates a1 and a2 without considering b1 or b2.
 | 
				
			||||||
 | 
					//  - modeV*   calculates a1 to be b1 plus an adjustment (between -3 and +3).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						findB1 = false
 | 
				
			||||||
 | 
						findB2 = true
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// findB finds either the b1 or b2 value.
 | 
				
			||||||
 | 
					func (z *reader) findB(whichB bool) int {
 | 
				
			||||||
 | 
						// The initial row is a special case. The previous row is implicitly all
 | 
				
			||||||
 | 
						// white, so that there are no changing pixel elements. We return b1 or b2
 | 
				
			||||||
 | 
						// to be at the end of the row.
 | 
				
			||||||
 | 
						if len(z.prev) != len(z.curr) {
 | 
				
			||||||
 | 
							return len(z.curr)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i := z.wi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if z.atStartOfRow {
 | 
				
			||||||
 | 
							// a0 is implicitly at -1, on a white pixel. b1 is the first black
 | 
				
			||||||
 | 
							// pixel in the previous row. b2 is the first white pixel after that.
 | 
				
			||||||
 | 
							for ; (i < len(z.prev)) && (z.prev[i] == 0xFF); i++ {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if whichB == findB2 {
 | 
				
			||||||
 | 
								for ; (i < len(z.prev)) && (z.prev[i] == 0x00); i++ {
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return i
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// As per figure 1 above, assume that the current pen color is white.
 | 
				
			||||||
 | 
						// First, walk past every contiguous black pixel in prev, starting at a0.
 | 
				
			||||||
 | 
						oppositeColor := ^z.penColor()
 | 
				
			||||||
 | 
						for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Then walk past every contiguous white pixel.
 | 
				
			||||||
 | 
						penColor := ^oppositeColor
 | 
				
			||||||
 | 
						for ; (i < len(z.prev)) && (z.prev[i] == penColor); i++ {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// We're now at a black pixel (or at the end of the row). That's b1.
 | 
				
			||||||
 | 
						if whichB == findB2 {
 | 
				
			||||||
 | 
							// If we're looking for b2, walk past every contiguous black pixel
 | 
				
			||||||
 | 
							// again.
 | 
				
			||||||
 | 
							oppositeColor := ^penColor
 | 
				
			||||||
 | 
							for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return i
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type readerMode struct {
 | 
				
			||||||
 | 
						function func(z *reader, arg int) error
 | 
				
			||||||
 | 
						arg      int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var readerModes = [...]readerMode{
 | 
				
			||||||
 | 
						modePass: {function: readerModePass},
 | 
				
			||||||
 | 
						modeH:    {function: readerModeH},
 | 
				
			||||||
 | 
						modeV0:   {function: readerModeV, arg: +0},
 | 
				
			||||||
 | 
						modeVR1:  {function: readerModeV, arg: +1},
 | 
				
			||||||
 | 
						modeVR2:  {function: readerModeV, arg: +2},
 | 
				
			||||||
 | 
						modeVR3:  {function: readerModeV, arg: +3},
 | 
				
			||||||
 | 
						modeVL1:  {function: readerModeV, arg: -1},
 | 
				
			||||||
 | 
						modeVL2:  {function: readerModeV, arg: -2},
 | 
				
			||||||
 | 
						modeVL3:  {function: readerModeV, arg: -3},
 | 
				
			||||||
 | 
						modeExt:  {function: readerModeExt},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readerModePass(z *reader, arg int) error {
 | 
				
			||||||
 | 
						b2 := z.findB(findB2)
 | 
				
			||||||
 | 
						if (b2 < z.wi) || (len(z.curr) < b2) {
 | 
				
			||||||
 | 
							return errInvalidOffset
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dst := z.curr[z.wi:b2]
 | 
				
			||||||
 | 
						penColor := z.penColor()
 | 
				
			||||||
 | 
						for i := range dst {
 | 
				
			||||||
 | 
							dst[i] = penColor
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						z.wi = b2
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readerModeH(z *reader, arg int) error {
 | 
				
			||||||
 | 
						// The first iteration finds a1. The second finds a2.
 | 
				
			||||||
 | 
						for i := 0; i < 2; i++ {
 | 
				
			||||||
 | 
							if err := z.decodeRun(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readerModeV(z *reader, arg int) error {
 | 
				
			||||||
 | 
						a1 := z.findB(findB1) + arg
 | 
				
			||||||
 | 
						if (a1 < z.wi) || (len(z.curr) < a1) {
 | 
				
			||||||
 | 
							return errInvalidOffset
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dst := z.curr[z.wi:a1]
 | 
				
			||||||
 | 
						penColor := z.penColor()
 | 
				
			||||||
 | 
						for i := range dst {
 | 
				
			||||||
 | 
							dst[i] = penColor
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						z.wi = a1
 | 
				
			||||||
 | 
						z.penColorIsWhite = !z.penColorIsWhite
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readerModeExt(z *reader, arg int) error {
 | 
				
			||||||
 | 
						return errUnsupportedMode
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeIntoGray decodes the CCITT-formatted data in r into dst.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It returns an error if dst's width and height don't match the implied width
 | 
				
			||||||
 | 
					// and height of CCITT-formatted data.
 | 
				
			||||||
 | 
					func DecodeIntoGray(dst *image.Gray, r io.Reader, order Order, sf SubFormat, opts *Options) error {
 | 
				
			||||||
 | 
						bounds := dst.Bounds()
 | 
				
			||||||
 | 
						if (bounds.Dx() < 0) || (bounds.Dy() < 0) {
 | 
				
			||||||
 | 
							return errInvalidBounds
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if bounds.Dx() > maxWidth {
 | 
				
			||||||
 | 
							return errUnsupportedWidth
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						z := reader{
 | 
				
			||||||
 | 
							br:        bitReader{r: r, order: order},
 | 
				
			||||||
 | 
							subFormat: sf,
 | 
				
			||||||
 | 
							align:     (opts != nil) && opts.Align,
 | 
				
			||||||
 | 
							invert:    (opts != nil) && opts.Invert,
 | 
				
			||||||
 | 
							width:     bounds.Dx(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := z.startDecode(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						width := bounds.Dx()
 | 
				
			||||||
 | 
						for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
 | 
				
			||||||
 | 
							p := (y - bounds.Min.Y) * dst.Stride
 | 
				
			||||||
 | 
							z.curr = dst.Pix[p : p+width]
 | 
				
			||||||
 | 
							if err := z.decodeRow(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							z.curr, z.prev = nil, z.curr
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := z.finishDecode(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if z.invert {
 | 
				
			||||||
 | 
							for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
 | 
				
			||||||
 | 
								p := (y - bounds.Min.Y) * dst.Stride
 | 
				
			||||||
 | 
								invertBytes(dst.Pix[p : p+width])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewReader returns an io.Reader that decodes the CCITT-formatted data in r.
 | 
				
			||||||
 | 
					// The resultant byte stream is one bit per pixel (MSB first), with 1 meaning
 | 
				
			||||||
 | 
					// white and 0 meaning black. Each row in the result is byte-aligned.
 | 
				
			||||||
 | 
					func NewReader(r io.Reader, order Order, sf SubFormat, width int, height int, opts *Options) io.Reader {
 | 
				
			||||||
 | 
						readErr := error(nil)
 | 
				
			||||||
 | 
						if (width < 0) || (height < 0) {
 | 
				
			||||||
 | 
							readErr = errInvalidBounds
 | 
				
			||||||
 | 
						} else if width > maxWidth {
 | 
				
			||||||
 | 
							readErr = errUnsupportedWidth
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &reader{
 | 
				
			||||||
 | 
							br:            bitReader{r: r, order: order},
 | 
				
			||||||
 | 
							subFormat:     sf,
 | 
				
			||||||
 | 
							align:         (opts != nil) && opts.Align,
 | 
				
			||||||
 | 
							invert:        (opts != nil) && opts.Invert,
 | 
				
			||||||
 | 
							width:         width,
 | 
				
			||||||
 | 
							rowsRemaining: height,
 | 
				
			||||||
 | 
							readErr:       readErr,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										989
									
								
								vendor/golang.org/x/image/ccitt/table.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										989
									
								
								vendor/golang.org/x/image/ccitt/table.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,989 @@
 | 
				
			|||||||
 | 
					// generated by "go run gen.go". DO NOT EDIT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package ccitt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Each decodeTable is represented by an array of [2]int16's: a binary tree.
 | 
				
			||||||
 | 
					// Each array element (other than element 0, which means invalid) is a branch
 | 
				
			||||||
 | 
					// node in that tree. The root node is always element 1 (the second element).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// To walk the tree, look at the next bit in the bit stream, using it to select
 | 
				
			||||||
 | 
					// the first or second element of the [2]int16. If that int16 is 0, we have an
 | 
				
			||||||
 | 
					// invalid code. If it is positive, go to that branch node. If it is negative,
 | 
				
			||||||
 | 
					// then we have a leaf node, whose value is the bitwise complement (the ^
 | 
				
			||||||
 | 
					// operator) of that int16.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Comments above each decodeTable also show the same structure visually. The
 | 
				
			||||||
 | 
					// "b123" lines show the 123'rd branch node. The "=XXXXX" lines show an invalid
 | 
				
			||||||
 | 
					// code. The "=v1234" lines show a leaf node with value 1234. When reading the
 | 
				
			||||||
 | 
					// bit stream, a 0 or 1 bit means to go up or down, as you move left to right.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// For example, in modeDecodeTable, branch node b005 is three steps up from the
 | 
				
			||||||
 | 
					// root node, meaning that we have already seen "000". If the next bit is "0"
 | 
				
			||||||
 | 
					// then we move to branch node b006. Otherwise, the next bit is "1", and we
 | 
				
			||||||
 | 
					// move to the leaf node v0000 (also known as the modePass constant). Indeed,
 | 
				
			||||||
 | 
					// the bits that encode modePass are "0001".
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Tables 1, 2 and 3 come from the "ITU-T Recommendation T.6: FACSIMILE CODING
 | 
				
			||||||
 | 
					// SCHEMES AND CODING CONTROL FUNCTIONS FOR GROUP 4 FACSIMILE APPARATUS"
 | 
				
			||||||
 | 
					// specification:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.6-198811-I!!PDF-E&type=items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// modeDecodeTable represents Table 1 and the End-of-Line code.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//                              +=XXXXX
 | 
				
			||||||
 | 
					// b015                       +-+
 | 
				
			||||||
 | 
					//                            | +=v0010
 | 
				
			||||||
 | 
					// b014                     +-+
 | 
				
			||||||
 | 
					//                          | +=XXXXX
 | 
				
			||||||
 | 
					// b013                   +-+
 | 
				
			||||||
 | 
					//                        | +=XXXXX
 | 
				
			||||||
 | 
					// b012                 +-+
 | 
				
			||||||
 | 
					//                      | +=XXXXX
 | 
				
			||||||
 | 
					// b011               +-+
 | 
				
			||||||
 | 
					//                    | +=XXXXX
 | 
				
			||||||
 | 
					// b009             +-+
 | 
				
			||||||
 | 
					//                  | +=v0009
 | 
				
			||||||
 | 
					// b007           +-+
 | 
				
			||||||
 | 
					//                | | +=v0008
 | 
				
			||||||
 | 
					// b010           | +-+
 | 
				
			||||||
 | 
					//                |   +=v0005
 | 
				
			||||||
 | 
					// b006         +-+
 | 
				
			||||||
 | 
					//              | | +=v0007
 | 
				
			||||||
 | 
					// b008         | +-+
 | 
				
			||||||
 | 
					//              |   +=v0004
 | 
				
			||||||
 | 
					// b005       +-+
 | 
				
			||||||
 | 
					//            | +=v0000
 | 
				
			||||||
 | 
					// b003     +-+
 | 
				
			||||||
 | 
					//          | +=v0001
 | 
				
			||||||
 | 
					// b002   +-+
 | 
				
			||||||
 | 
					//        | | +=v0006
 | 
				
			||||||
 | 
					// b004   | +-+
 | 
				
			||||||
 | 
					//        |   +=v0003
 | 
				
			||||||
 | 
					// b001 +-+
 | 
				
			||||||
 | 
					//        +=v0002
 | 
				
			||||||
 | 
					var modeDecodeTable = [...][2]int16{
 | 
				
			||||||
 | 
						0:  {0, 0},
 | 
				
			||||||
 | 
						1:  {2, ^2},
 | 
				
			||||||
 | 
						2:  {3, 4},
 | 
				
			||||||
 | 
						3:  {5, ^1},
 | 
				
			||||||
 | 
						4:  {^6, ^3},
 | 
				
			||||||
 | 
						5:  {6, ^0},
 | 
				
			||||||
 | 
						6:  {7, 8},
 | 
				
			||||||
 | 
						7:  {9, 10},
 | 
				
			||||||
 | 
						8:  {^7, ^4},
 | 
				
			||||||
 | 
						9:  {11, ^9},
 | 
				
			||||||
 | 
						10: {^8, ^5},
 | 
				
			||||||
 | 
						11: {12, 0},
 | 
				
			||||||
 | 
						12: {13, 0},
 | 
				
			||||||
 | 
						13: {14, 0},
 | 
				
			||||||
 | 
						14: {15, 0},
 | 
				
			||||||
 | 
						15: {0, ^10},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// whiteDecodeTable represents Tables 2 and 3 for a white run.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//                      +=XXXXX
 | 
				
			||||||
 | 
					// b059               +-+
 | 
				
			||||||
 | 
					//                    | |     +=v1792
 | 
				
			||||||
 | 
					// b096               | |   +-+
 | 
				
			||||||
 | 
					//                    | |   | | +=v1984
 | 
				
			||||||
 | 
					// b100               | |   | +-+
 | 
				
			||||||
 | 
					//                    | |   |   +=v2048
 | 
				
			||||||
 | 
					// b094               | | +-+
 | 
				
			||||||
 | 
					//                    | | | |   +=v2112
 | 
				
			||||||
 | 
					// b101               | | | | +-+
 | 
				
			||||||
 | 
					//                    | | | | | +=v2176
 | 
				
			||||||
 | 
					// b097               | | | +-+
 | 
				
			||||||
 | 
					//                    | | |   | +=v2240
 | 
				
			||||||
 | 
					// b102               | | |   +-+
 | 
				
			||||||
 | 
					//                    | | |     +=v2304
 | 
				
			||||||
 | 
					// b085               | +-+
 | 
				
			||||||
 | 
					//                    |   |   +=v1856
 | 
				
			||||||
 | 
					// b098               |   | +-+
 | 
				
			||||||
 | 
					//                    |   | | +=v1920
 | 
				
			||||||
 | 
					// b095               |   +-+
 | 
				
			||||||
 | 
					//                    |     |   +=v2368
 | 
				
			||||||
 | 
					// b103               |     | +-+
 | 
				
			||||||
 | 
					//                    |     | | +=v2432
 | 
				
			||||||
 | 
					// b099               |     +-+
 | 
				
			||||||
 | 
					//                    |       | +=v2496
 | 
				
			||||||
 | 
					// b104               |       +-+
 | 
				
			||||||
 | 
					//                    |         +=v2560
 | 
				
			||||||
 | 
					// b040             +-+
 | 
				
			||||||
 | 
					//                  | | +=v0029
 | 
				
			||||||
 | 
					// b060             | +-+
 | 
				
			||||||
 | 
					//                  |   +=v0030
 | 
				
			||||||
 | 
					// b026           +-+
 | 
				
			||||||
 | 
					//                | |   +=v0045
 | 
				
			||||||
 | 
					// b061           | | +-+
 | 
				
			||||||
 | 
					//                | | | +=v0046
 | 
				
			||||||
 | 
					// b041           | +-+
 | 
				
			||||||
 | 
					//                |   +=v0022
 | 
				
			||||||
 | 
					// b016         +-+
 | 
				
			||||||
 | 
					//              | |   +=v0023
 | 
				
			||||||
 | 
					// b042         | | +-+
 | 
				
			||||||
 | 
					//              | | | | +=v0047
 | 
				
			||||||
 | 
					// b062         | | | +-+
 | 
				
			||||||
 | 
					//              | | |   +=v0048
 | 
				
			||||||
 | 
					// b027         | +-+
 | 
				
			||||||
 | 
					//              |   +=v0013
 | 
				
			||||||
 | 
					// b008       +-+
 | 
				
			||||||
 | 
					//            | |     +=v0020
 | 
				
			||||||
 | 
					// b043       | |   +-+
 | 
				
			||||||
 | 
					//            | |   | | +=v0033
 | 
				
			||||||
 | 
					// b063       | |   | +-+
 | 
				
			||||||
 | 
					//            | |   |   +=v0034
 | 
				
			||||||
 | 
					// b028       | | +-+
 | 
				
			||||||
 | 
					//            | | | |   +=v0035
 | 
				
			||||||
 | 
					// b064       | | | | +-+
 | 
				
			||||||
 | 
					//            | | | | | +=v0036
 | 
				
			||||||
 | 
					// b044       | | | +-+
 | 
				
			||||||
 | 
					//            | | |   | +=v0037
 | 
				
			||||||
 | 
					// b065       | | |   +-+
 | 
				
			||||||
 | 
					//            | | |     +=v0038
 | 
				
			||||||
 | 
					// b017       | +-+
 | 
				
			||||||
 | 
					//            |   |   +=v0019
 | 
				
			||||||
 | 
					// b045       |   | +-+
 | 
				
			||||||
 | 
					//            |   | | | +=v0031
 | 
				
			||||||
 | 
					// b066       |   | | +-+
 | 
				
			||||||
 | 
					//            |   | |   +=v0032
 | 
				
			||||||
 | 
					// b029       |   +-+
 | 
				
			||||||
 | 
					//            |     +=v0001
 | 
				
			||||||
 | 
					// b004     +-+
 | 
				
			||||||
 | 
					//          | |     +=v0012
 | 
				
			||||||
 | 
					// b030     | |   +-+
 | 
				
			||||||
 | 
					//          | |   | |   +=v0053
 | 
				
			||||||
 | 
					// b067     | |   | | +-+
 | 
				
			||||||
 | 
					//          | |   | | | +=v0054
 | 
				
			||||||
 | 
					// b046     | |   | +-+
 | 
				
			||||||
 | 
					//          | |   |   +=v0026
 | 
				
			||||||
 | 
					// b018     | | +-+
 | 
				
			||||||
 | 
					//          | | | |     +=v0039
 | 
				
			||||||
 | 
					// b068     | | | |   +-+
 | 
				
			||||||
 | 
					//          | | | |   | +=v0040
 | 
				
			||||||
 | 
					// b047     | | | | +-+
 | 
				
			||||||
 | 
					//          | | | | | | +=v0041
 | 
				
			||||||
 | 
					// b069     | | | | | +-+
 | 
				
			||||||
 | 
					//          | | | | |   +=v0042
 | 
				
			||||||
 | 
					// b031     | | | +-+
 | 
				
			||||||
 | 
					//          | | |   |   +=v0043
 | 
				
			||||||
 | 
					// b070     | | |   | +-+
 | 
				
			||||||
 | 
					//          | | |   | | +=v0044
 | 
				
			||||||
 | 
					// b048     | | |   +-+
 | 
				
			||||||
 | 
					//          | | |     +=v0021
 | 
				
			||||||
 | 
					// b009     | +-+
 | 
				
			||||||
 | 
					//          |   |     +=v0028
 | 
				
			||||||
 | 
					// b049     |   |   +-+
 | 
				
			||||||
 | 
					//          |   |   | | +=v0061
 | 
				
			||||||
 | 
					// b071     |   |   | +-+
 | 
				
			||||||
 | 
					//          |   |   |   +=v0062
 | 
				
			||||||
 | 
					// b032     |   | +-+
 | 
				
			||||||
 | 
					//          |   | | |   +=v0063
 | 
				
			||||||
 | 
					// b072     |   | | | +-+
 | 
				
			||||||
 | 
					//          |   | | | | +=v0000
 | 
				
			||||||
 | 
					// b050     |   | | +-+
 | 
				
			||||||
 | 
					//          |   | |   | +=v0320
 | 
				
			||||||
 | 
					// b073     |   | |   +-+
 | 
				
			||||||
 | 
					//          |   | |     +=v0384
 | 
				
			||||||
 | 
					// b019     |   +-+
 | 
				
			||||||
 | 
					//          |     +=v0010
 | 
				
			||||||
 | 
					// b002   +-+
 | 
				
			||||||
 | 
					//        | |     +=v0011
 | 
				
			||||||
 | 
					// b020   | |   +-+
 | 
				
			||||||
 | 
					//        | |   | |   +=v0027
 | 
				
			||||||
 | 
					// b051   | |   | | +-+
 | 
				
			||||||
 | 
					//        | |   | | | | +=v0059
 | 
				
			||||||
 | 
					// b074   | |   | | | +-+
 | 
				
			||||||
 | 
					//        | |   | | |   +=v0060
 | 
				
			||||||
 | 
					// b033   | |   | +-+
 | 
				
			||||||
 | 
					//        | |   |   |     +=v1472
 | 
				
			||||||
 | 
					// b086   | |   |   |   +-+
 | 
				
			||||||
 | 
					//        | |   |   |   | +=v1536
 | 
				
			||||||
 | 
					// b075   | |   |   | +-+
 | 
				
			||||||
 | 
					//        | |   |   | | | +=v1600
 | 
				
			||||||
 | 
					// b087   | |   |   | | +-+
 | 
				
			||||||
 | 
					//        | |   |   | |   +=v1728
 | 
				
			||||||
 | 
					// b052   | |   |   +-+
 | 
				
			||||||
 | 
					//        | |   |     +=v0018
 | 
				
			||||||
 | 
					// b010   | | +-+
 | 
				
			||||||
 | 
					//        | | | |     +=v0024
 | 
				
			||||||
 | 
					// b053   | | | |   +-+
 | 
				
			||||||
 | 
					//        | | | |   | | +=v0049
 | 
				
			||||||
 | 
					// b076   | | | |   | +-+
 | 
				
			||||||
 | 
					//        | | | |   |   +=v0050
 | 
				
			||||||
 | 
					// b034   | | | | +-+
 | 
				
			||||||
 | 
					//        | | | | | |   +=v0051
 | 
				
			||||||
 | 
					// b077   | | | | | | +-+
 | 
				
			||||||
 | 
					//        | | | | | | | +=v0052
 | 
				
			||||||
 | 
					// b054   | | | | | +-+
 | 
				
			||||||
 | 
					//        | | | | |   +=v0025
 | 
				
			||||||
 | 
					// b021   | | | +-+
 | 
				
			||||||
 | 
					//        | | |   |     +=v0055
 | 
				
			||||||
 | 
					// b078   | | |   |   +-+
 | 
				
			||||||
 | 
					//        | | |   |   | +=v0056
 | 
				
			||||||
 | 
					// b055   | | |   | +-+
 | 
				
			||||||
 | 
					//        | | |   | | | +=v0057
 | 
				
			||||||
 | 
					// b079   | | |   | | +-+
 | 
				
			||||||
 | 
					//        | | |   | |   +=v0058
 | 
				
			||||||
 | 
					// b035   | | |   +-+
 | 
				
			||||||
 | 
					//        | | |     +=v0192
 | 
				
			||||||
 | 
					// b005   | +-+
 | 
				
			||||||
 | 
					//        |   |     +=v1664
 | 
				
			||||||
 | 
					// b036   |   |   +-+
 | 
				
			||||||
 | 
					//        |   |   | |   +=v0448
 | 
				
			||||||
 | 
					// b080   |   |   | | +-+
 | 
				
			||||||
 | 
					//        |   |   | | | +=v0512
 | 
				
			||||||
 | 
					// b056   |   |   | +-+
 | 
				
			||||||
 | 
					//        |   |   |   |   +=v0704
 | 
				
			||||||
 | 
					// b088   |   |   |   | +-+
 | 
				
			||||||
 | 
					//        |   |   |   | | +=v0768
 | 
				
			||||||
 | 
					// b081   |   |   |   +-+
 | 
				
			||||||
 | 
					//        |   |   |     +=v0640
 | 
				
			||||||
 | 
					// b022   |   | +-+
 | 
				
			||||||
 | 
					//        |   | | |     +=v0576
 | 
				
			||||||
 | 
					// b082   |   | | |   +-+
 | 
				
			||||||
 | 
					//        |   | | |   | | +=v0832
 | 
				
			||||||
 | 
					// b089   |   | | |   | +-+
 | 
				
			||||||
 | 
					//        |   | | |   |   +=v0896
 | 
				
			||||||
 | 
					// b057   |   | | | +-+
 | 
				
			||||||
 | 
					//        |   | | | | |   +=v0960
 | 
				
			||||||
 | 
					// b090   |   | | | | | +-+
 | 
				
			||||||
 | 
					//        |   | | | | | | +=v1024
 | 
				
			||||||
 | 
					// b083   |   | | | | +-+
 | 
				
			||||||
 | 
					//        |   | | | |   | +=v1088
 | 
				
			||||||
 | 
					// b091   |   | | | |   +-+
 | 
				
			||||||
 | 
					//        |   | | | |     +=v1152
 | 
				
			||||||
 | 
					// b037   |   | | +-+
 | 
				
			||||||
 | 
					//        |   | |   |     +=v1216
 | 
				
			||||||
 | 
					// b092   |   | |   |   +-+
 | 
				
			||||||
 | 
					//        |   | |   |   | +=v1280
 | 
				
			||||||
 | 
					// b084   |   | |   | +-+
 | 
				
			||||||
 | 
					//        |   | |   | | | +=v1344
 | 
				
			||||||
 | 
					// b093   |   | |   | | +-+
 | 
				
			||||||
 | 
					//        |   | |   | |   +=v1408
 | 
				
			||||||
 | 
					// b058   |   | |   +-+
 | 
				
			||||||
 | 
					//        |   | |     +=v0256
 | 
				
			||||||
 | 
					// b011   |   +-+
 | 
				
			||||||
 | 
					//        |     +=v0002
 | 
				
			||||||
 | 
					// b001 +-+
 | 
				
			||||||
 | 
					//        |     +=v0003
 | 
				
			||||||
 | 
					// b012   |   +-+
 | 
				
			||||||
 | 
					//        |   | | +=v0128
 | 
				
			||||||
 | 
					// b023   |   | +-+
 | 
				
			||||||
 | 
					//        |   |   +=v0008
 | 
				
			||||||
 | 
					// b006   | +-+
 | 
				
			||||||
 | 
					//        | | |   +=v0009
 | 
				
			||||||
 | 
					// b024   | | | +-+
 | 
				
			||||||
 | 
					//        | | | | | +=v0016
 | 
				
			||||||
 | 
					// b038   | | | | +-+
 | 
				
			||||||
 | 
					//        | | | |   +=v0017
 | 
				
			||||||
 | 
					// b013   | | +-+
 | 
				
			||||||
 | 
					//        | |   +=v0004
 | 
				
			||||||
 | 
					// b003   +-+
 | 
				
			||||||
 | 
					//          |   +=v0005
 | 
				
			||||||
 | 
					// b014     | +-+
 | 
				
			||||||
 | 
					//          | | |   +=v0014
 | 
				
			||||||
 | 
					// b039     | | | +-+
 | 
				
			||||||
 | 
					//          | | | | +=v0015
 | 
				
			||||||
 | 
					// b025     | | +-+
 | 
				
			||||||
 | 
					//          | |   +=v0064
 | 
				
			||||||
 | 
					// b007     +-+
 | 
				
			||||||
 | 
					//            | +=v0006
 | 
				
			||||||
 | 
					// b015       +-+
 | 
				
			||||||
 | 
					//              +=v0007
 | 
				
			||||||
 | 
					var whiteDecodeTable = [...][2]int16{
 | 
				
			||||||
 | 
						0:   {0, 0},
 | 
				
			||||||
 | 
						1:   {2, 3},
 | 
				
			||||||
 | 
						2:   {4, 5},
 | 
				
			||||||
 | 
						3:   {6, 7},
 | 
				
			||||||
 | 
						4:   {8, 9},
 | 
				
			||||||
 | 
						5:   {10, 11},
 | 
				
			||||||
 | 
						6:   {12, 13},
 | 
				
			||||||
 | 
						7:   {14, 15},
 | 
				
			||||||
 | 
						8:   {16, 17},
 | 
				
			||||||
 | 
						9:   {18, 19},
 | 
				
			||||||
 | 
						10:  {20, 21},
 | 
				
			||||||
 | 
						11:  {22, ^2},
 | 
				
			||||||
 | 
						12:  {^3, 23},
 | 
				
			||||||
 | 
						13:  {24, ^4},
 | 
				
			||||||
 | 
						14:  {^5, 25},
 | 
				
			||||||
 | 
						15:  {^6, ^7},
 | 
				
			||||||
 | 
						16:  {26, 27},
 | 
				
			||||||
 | 
						17:  {28, 29},
 | 
				
			||||||
 | 
						18:  {30, 31},
 | 
				
			||||||
 | 
						19:  {32, ^10},
 | 
				
			||||||
 | 
						20:  {^11, 33},
 | 
				
			||||||
 | 
						21:  {34, 35},
 | 
				
			||||||
 | 
						22:  {36, 37},
 | 
				
			||||||
 | 
						23:  {^128, ^8},
 | 
				
			||||||
 | 
						24:  {^9, 38},
 | 
				
			||||||
 | 
						25:  {39, ^64},
 | 
				
			||||||
 | 
						26:  {40, 41},
 | 
				
			||||||
 | 
						27:  {42, ^13},
 | 
				
			||||||
 | 
						28:  {43, 44},
 | 
				
			||||||
 | 
						29:  {45, ^1},
 | 
				
			||||||
 | 
						30:  {^12, 46},
 | 
				
			||||||
 | 
						31:  {47, 48},
 | 
				
			||||||
 | 
						32:  {49, 50},
 | 
				
			||||||
 | 
						33:  {51, 52},
 | 
				
			||||||
 | 
						34:  {53, 54},
 | 
				
			||||||
 | 
						35:  {55, ^192},
 | 
				
			||||||
 | 
						36:  {^1664, 56},
 | 
				
			||||||
 | 
						37:  {57, 58},
 | 
				
			||||||
 | 
						38:  {^16, ^17},
 | 
				
			||||||
 | 
						39:  {^14, ^15},
 | 
				
			||||||
 | 
						40:  {59, 60},
 | 
				
			||||||
 | 
						41:  {61, ^22},
 | 
				
			||||||
 | 
						42:  {^23, 62},
 | 
				
			||||||
 | 
						43:  {^20, 63},
 | 
				
			||||||
 | 
						44:  {64, 65},
 | 
				
			||||||
 | 
						45:  {^19, 66},
 | 
				
			||||||
 | 
						46:  {67, ^26},
 | 
				
			||||||
 | 
						47:  {68, 69},
 | 
				
			||||||
 | 
						48:  {70, ^21},
 | 
				
			||||||
 | 
						49:  {^28, 71},
 | 
				
			||||||
 | 
						50:  {72, 73},
 | 
				
			||||||
 | 
						51:  {^27, 74},
 | 
				
			||||||
 | 
						52:  {75, ^18},
 | 
				
			||||||
 | 
						53:  {^24, 76},
 | 
				
			||||||
 | 
						54:  {77, ^25},
 | 
				
			||||||
 | 
						55:  {78, 79},
 | 
				
			||||||
 | 
						56:  {80, 81},
 | 
				
			||||||
 | 
						57:  {82, 83},
 | 
				
			||||||
 | 
						58:  {84, ^256},
 | 
				
			||||||
 | 
						59:  {0, 85},
 | 
				
			||||||
 | 
						60:  {^29, ^30},
 | 
				
			||||||
 | 
						61:  {^45, ^46},
 | 
				
			||||||
 | 
						62:  {^47, ^48},
 | 
				
			||||||
 | 
						63:  {^33, ^34},
 | 
				
			||||||
 | 
						64:  {^35, ^36},
 | 
				
			||||||
 | 
						65:  {^37, ^38},
 | 
				
			||||||
 | 
						66:  {^31, ^32},
 | 
				
			||||||
 | 
						67:  {^53, ^54},
 | 
				
			||||||
 | 
						68:  {^39, ^40},
 | 
				
			||||||
 | 
						69:  {^41, ^42},
 | 
				
			||||||
 | 
						70:  {^43, ^44},
 | 
				
			||||||
 | 
						71:  {^61, ^62},
 | 
				
			||||||
 | 
						72:  {^63, ^0},
 | 
				
			||||||
 | 
						73:  {^320, ^384},
 | 
				
			||||||
 | 
						74:  {^59, ^60},
 | 
				
			||||||
 | 
						75:  {86, 87},
 | 
				
			||||||
 | 
						76:  {^49, ^50},
 | 
				
			||||||
 | 
						77:  {^51, ^52},
 | 
				
			||||||
 | 
						78:  {^55, ^56},
 | 
				
			||||||
 | 
						79:  {^57, ^58},
 | 
				
			||||||
 | 
						80:  {^448, ^512},
 | 
				
			||||||
 | 
						81:  {88, ^640},
 | 
				
			||||||
 | 
						82:  {^576, 89},
 | 
				
			||||||
 | 
						83:  {90, 91},
 | 
				
			||||||
 | 
						84:  {92, 93},
 | 
				
			||||||
 | 
						85:  {94, 95},
 | 
				
			||||||
 | 
						86:  {^1472, ^1536},
 | 
				
			||||||
 | 
						87:  {^1600, ^1728},
 | 
				
			||||||
 | 
						88:  {^704, ^768},
 | 
				
			||||||
 | 
						89:  {^832, ^896},
 | 
				
			||||||
 | 
						90:  {^960, ^1024},
 | 
				
			||||||
 | 
						91:  {^1088, ^1152},
 | 
				
			||||||
 | 
						92:  {^1216, ^1280},
 | 
				
			||||||
 | 
						93:  {^1344, ^1408},
 | 
				
			||||||
 | 
						94:  {96, 97},
 | 
				
			||||||
 | 
						95:  {98, 99},
 | 
				
			||||||
 | 
						96:  {^1792, 100},
 | 
				
			||||||
 | 
						97:  {101, 102},
 | 
				
			||||||
 | 
						98:  {^1856, ^1920},
 | 
				
			||||||
 | 
						99:  {103, 104},
 | 
				
			||||||
 | 
						100: {^1984, ^2048},
 | 
				
			||||||
 | 
						101: {^2112, ^2176},
 | 
				
			||||||
 | 
						102: {^2240, ^2304},
 | 
				
			||||||
 | 
						103: {^2368, ^2432},
 | 
				
			||||||
 | 
						104: {^2496, ^2560},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// blackDecodeTable represents Tables 2 and 3 for a black run.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//                      +=XXXXX
 | 
				
			||||||
 | 
					// b017               +-+
 | 
				
			||||||
 | 
					//                    | |     +=v1792
 | 
				
			||||||
 | 
					// b042               | |   +-+
 | 
				
			||||||
 | 
					//                    | |   | | +=v1984
 | 
				
			||||||
 | 
					// b063               | |   | +-+
 | 
				
			||||||
 | 
					//                    | |   |   +=v2048
 | 
				
			||||||
 | 
					// b029               | | +-+
 | 
				
			||||||
 | 
					//                    | | | |   +=v2112
 | 
				
			||||||
 | 
					// b064               | | | | +-+
 | 
				
			||||||
 | 
					//                    | | | | | +=v2176
 | 
				
			||||||
 | 
					// b043               | | | +-+
 | 
				
			||||||
 | 
					//                    | | |   | +=v2240
 | 
				
			||||||
 | 
					// b065               | | |   +-+
 | 
				
			||||||
 | 
					//                    | | |     +=v2304
 | 
				
			||||||
 | 
					// b022               | +-+
 | 
				
			||||||
 | 
					//                    |   |   +=v1856
 | 
				
			||||||
 | 
					// b044               |   | +-+
 | 
				
			||||||
 | 
					//                    |   | | +=v1920
 | 
				
			||||||
 | 
					// b030               |   +-+
 | 
				
			||||||
 | 
					//                    |     |   +=v2368
 | 
				
			||||||
 | 
					// b066               |     | +-+
 | 
				
			||||||
 | 
					//                    |     | | +=v2432
 | 
				
			||||||
 | 
					// b045               |     +-+
 | 
				
			||||||
 | 
					//                    |       | +=v2496
 | 
				
			||||||
 | 
					// b067               |       +-+
 | 
				
			||||||
 | 
					//                    |         +=v2560
 | 
				
			||||||
 | 
					// b013             +-+
 | 
				
			||||||
 | 
					//                  | |     +=v0018
 | 
				
			||||||
 | 
					// b031             | |   +-+
 | 
				
			||||||
 | 
					//                  | |   | |   +=v0052
 | 
				
			||||||
 | 
					// b068             | |   | | +-+
 | 
				
			||||||
 | 
					//                  | |   | | | | +=v0640
 | 
				
			||||||
 | 
					// b095             | |   | | | +-+
 | 
				
			||||||
 | 
					//                  | |   | | |   +=v0704
 | 
				
			||||||
 | 
					// b046             | |   | +-+
 | 
				
			||||||
 | 
					//                  | |   |   |   +=v0768
 | 
				
			||||||
 | 
					// b096             | |   |   | +-+
 | 
				
			||||||
 | 
					//                  | |   |   | | +=v0832
 | 
				
			||||||
 | 
					// b069             | |   |   +-+
 | 
				
			||||||
 | 
					//                  | |   |     +=v0055
 | 
				
			||||||
 | 
					// b023             | | +-+
 | 
				
			||||||
 | 
					//                  | | | |     +=v0056
 | 
				
			||||||
 | 
					// b070             | | | |   +-+
 | 
				
			||||||
 | 
					//                  | | | |   | | +=v1280
 | 
				
			||||||
 | 
					// b097             | | | |   | +-+
 | 
				
			||||||
 | 
					//                  | | | |   |   +=v1344
 | 
				
			||||||
 | 
					// b047             | | | | +-+
 | 
				
			||||||
 | 
					//                  | | | | | |   +=v1408
 | 
				
			||||||
 | 
					// b098             | | | | | | +-+
 | 
				
			||||||
 | 
					//                  | | | | | | | +=v1472
 | 
				
			||||||
 | 
					// b071             | | | | | +-+
 | 
				
			||||||
 | 
					//                  | | | | |   +=v0059
 | 
				
			||||||
 | 
					// b032             | | | +-+
 | 
				
			||||||
 | 
					//                  | | |   |   +=v0060
 | 
				
			||||||
 | 
					// b072             | | |   | +-+
 | 
				
			||||||
 | 
					//                  | | |   | | | +=v1536
 | 
				
			||||||
 | 
					// b099             | | |   | | +-+
 | 
				
			||||||
 | 
					//                  | | |   | |   +=v1600
 | 
				
			||||||
 | 
					// b048             | | |   +-+
 | 
				
			||||||
 | 
					//                  | | |     +=v0024
 | 
				
			||||||
 | 
					// b018             | +-+
 | 
				
			||||||
 | 
					//                  |   |     +=v0025
 | 
				
			||||||
 | 
					// b049             |   |   +-+
 | 
				
			||||||
 | 
					//                  |   |   | |   +=v1664
 | 
				
			||||||
 | 
					// b100             |   |   | | +-+
 | 
				
			||||||
 | 
					//                  |   |   | | | +=v1728
 | 
				
			||||||
 | 
					// b073             |   |   | +-+
 | 
				
			||||||
 | 
					//                  |   |   |   +=v0320
 | 
				
			||||||
 | 
					// b033             |   | +-+
 | 
				
			||||||
 | 
					//                  |   | | |   +=v0384
 | 
				
			||||||
 | 
					// b074             |   | | | +-+
 | 
				
			||||||
 | 
					//                  |   | | | | +=v0448
 | 
				
			||||||
 | 
					// b050             |   | | +-+
 | 
				
			||||||
 | 
					//                  |   | |   |   +=v0512
 | 
				
			||||||
 | 
					// b101             |   | |   | +-+
 | 
				
			||||||
 | 
					//                  |   | |   | | +=v0576
 | 
				
			||||||
 | 
					// b075             |   | |   +-+
 | 
				
			||||||
 | 
					//                  |   | |     +=v0053
 | 
				
			||||||
 | 
					// b024             |   +-+
 | 
				
			||||||
 | 
					//                  |     |     +=v0054
 | 
				
			||||||
 | 
					// b076             |     |   +-+
 | 
				
			||||||
 | 
					//                  |     |   | | +=v0896
 | 
				
			||||||
 | 
					// b102             |     |   | +-+
 | 
				
			||||||
 | 
					//                  |     |   |   +=v0960
 | 
				
			||||||
 | 
					// b051             |     | +-+
 | 
				
			||||||
 | 
					//                  |     | | |   +=v1024
 | 
				
			||||||
 | 
					// b103             |     | | | +-+
 | 
				
			||||||
 | 
					//                  |     | | | | +=v1088
 | 
				
			||||||
 | 
					// b077             |     | | +-+
 | 
				
			||||||
 | 
					//                  |     | |   | +=v1152
 | 
				
			||||||
 | 
					// b104             |     | |   +-+
 | 
				
			||||||
 | 
					//                  |     | |     +=v1216
 | 
				
			||||||
 | 
					// b034             |     +-+
 | 
				
			||||||
 | 
					//                  |       +=v0064
 | 
				
			||||||
 | 
					// b010           +-+
 | 
				
			||||||
 | 
					//                | |   +=v0013
 | 
				
			||||||
 | 
					// b019           | | +-+
 | 
				
			||||||
 | 
					//                | | | |     +=v0023
 | 
				
			||||||
 | 
					// b052           | | | |   +-+
 | 
				
			||||||
 | 
					//                | | | |   | | +=v0050
 | 
				
			||||||
 | 
					// b078           | | | |   | +-+
 | 
				
			||||||
 | 
					//                | | | |   |   +=v0051
 | 
				
			||||||
 | 
					// b035           | | | | +-+
 | 
				
			||||||
 | 
					//                | | | | | |   +=v0044
 | 
				
			||||||
 | 
					// b079           | | | | | | +-+
 | 
				
			||||||
 | 
					//                | | | | | | | +=v0045
 | 
				
			||||||
 | 
					// b053           | | | | | +-+
 | 
				
			||||||
 | 
					//                | | | | |   | +=v0046
 | 
				
			||||||
 | 
					// b080           | | | | |   +-+
 | 
				
			||||||
 | 
					//                | | | | |     +=v0047
 | 
				
			||||||
 | 
					// b025           | | | +-+
 | 
				
			||||||
 | 
					//                | | |   |     +=v0057
 | 
				
			||||||
 | 
					// b081           | | |   |   +-+
 | 
				
			||||||
 | 
					//                | | |   |   | +=v0058
 | 
				
			||||||
 | 
					// b054           | | |   | +-+
 | 
				
			||||||
 | 
					//                | | |   | | | +=v0061
 | 
				
			||||||
 | 
					// b082           | | |   | | +-+
 | 
				
			||||||
 | 
					//                | | |   | |   +=v0256
 | 
				
			||||||
 | 
					// b036           | | |   +-+
 | 
				
			||||||
 | 
					//                | | |     +=v0016
 | 
				
			||||||
 | 
					// b014           | +-+
 | 
				
			||||||
 | 
					//                |   |     +=v0017
 | 
				
			||||||
 | 
					// b037           |   |   +-+
 | 
				
			||||||
 | 
					//                |   |   | |   +=v0048
 | 
				
			||||||
 | 
					// b083           |   |   | | +-+
 | 
				
			||||||
 | 
					//                |   |   | | | +=v0049
 | 
				
			||||||
 | 
					// b055           |   |   | +-+
 | 
				
			||||||
 | 
					//                |   |   |   | +=v0062
 | 
				
			||||||
 | 
					// b084           |   |   |   +-+
 | 
				
			||||||
 | 
					//                |   |   |     +=v0063
 | 
				
			||||||
 | 
					// b026           |   | +-+
 | 
				
			||||||
 | 
					//                |   | | |     +=v0030
 | 
				
			||||||
 | 
					// b085           |   | | |   +-+
 | 
				
			||||||
 | 
					//                |   | | |   | +=v0031
 | 
				
			||||||
 | 
					// b056           |   | | | +-+
 | 
				
			||||||
 | 
					//                |   | | | | | +=v0032
 | 
				
			||||||
 | 
					// b086           |   | | | | +-+
 | 
				
			||||||
 | 
					//                |   | | | |   +=v0033
 | 
				
			||||||
 | 
					// b038           |   | | +-+
 | 
				
			||||||
 | 
					//                |   | |   |   +=v0040
 | 
				
			||||||
 | 
					// b087           |   | |   | +-+
 | 
				
			||||||
 | 
					//                |   | |   | | +=v0041
 | 
				
			||||||
 | 
					// b057           |   | |   +-+
 | 
				
			||||||
 | 
					//                |   | |     +=v0022
 | 
				
			||||||
 | 
					// b020           |   +-+
 | 
				
			||||||
 | 
					//                |     +=v0014
 | 
				
			||||||
 | 
					// b008         +-+
 | 
				
			||||||
 | 
					//              | |   +=v0010
 | 
				
			||||||
 | 
					// b015         | | +-+
 | 
				
			||||||
 | 
					//              | | | +=v0011
 | 
				
			||||||
 | 
					// b011         | +-+
 | 
				
			||||||
 | 
					//              |   |     +=v0015
 | 
				
			||||||
 | 
					// b027         |   |   +-+
 | 
				
			||||||
 | 
					//              |   |   | |     +=v0128
 | 
				
			||||||
 | 
					// b088         |   |   | |   +-+
 | 
				
			||||||
 | 
					//              |   |   | |   | +=v0192
 | 
				
			||||||
 | 
					// b058         |   |   | | +-+
 | 
				
			||||||
 | 
					//              |   |   | | | | +=v0026
 | 
				
			||||||
 | 
					// b089         |   |   | | | +-+
 | 
				
			||||||
 | 
					//              |   |   | | |   +=v0027
 | 
				
			||||||
 | 
					// b039         |   |   | +-+
 | 
				
			||||||
 | 
					//              |   |   |   |   +=v0028
 | 
				
			||||||
 | 
					// b090         |   |   |   | +-+
 | 
				
			||||||
 | 
					//              |   |   |   | | +=v0029
 | 
				
			||||||
 | 
					// b059         |   |   |   +-+
 | 
				
			||||||
 | 
					//              |   |   |     +=v0019
 | 
				
			||||||
 | 
					// b021         |   | +-+
 | 
				
			||||||
 | 
					//              |   | | |     +=v0020
 | 
				
			||||||
 | 
					// b060         |   | | |   +-+
 | 
				
			||||||
 | 
					//              |   | | |   | | +=v0034
 | 
				
			||||||
 | 
					// b091         |   | | |   | +-+
 | 
				
			||||||
 | 
					//              |   | | |   |   +=v0035
 | 
				
			||||||
 | 
					// b040         |   | | | +-+
 | 
				
			||||||
 | 
					//              |   | | | | |   +=v0036
 | 
				
			||||||
 | 
					// b092         |   | | | | | +-+
 | 
				
			||||||
 | 
					//              |   | | | | | | +=v0037
 | 
				
			||||||
 | 
					// b061         |   | | | | +-+
 | 
				
			||||||
 | 
					//              |   | | | |   | +=v0038
 | 
				
			||||||
 | 
					// b093         |   | | | |   +-+
 | 
				
			||||||
 | 
					//              |   | | | |     +=v0039
 | 
				
			||||||
 | 
					// b028         |   | | +-+
 | 
				
			||||||
 | 
					//              |   | |   |   +=v0021
 | 
				
			||||||
 | 
					// b062         |   | |   | +-+
 | 
				
			||||||
 | 
					//              |   | |   | | | +=v0042
 | 
				
			||||||
 | 
					// b094         |   | |   | | +-+
 | 
				
			||||||
 | 
					//              |   | |   | |   +=v0043
 | 
				
			||||||
 | 
					// b041         |   | |   +-+
 | 
				
			||||||
 | 
					//              |   | |     +=v0000
 | 
				
			||||||
 | 
					// b016         |   +-+
 | 
				
			||||||
 | 
					//              |     +=v0012
 | 
				
			||||||
 | 
					// b006       +-+
 | 
				
			||||||
 | 
					//            | |   +=v0009
 | 
				
			||||||
 | 
					// b012       | | +-+
 | 
				
			||||||
 | 
					//            | | | +=v0008
 | 
				
			||||||
 | 
					// b009       | +-+
 | 
				
			||||||
 | 
					//            |   +=v0007
 | 
				
			||||||
 | 
					// b004     +-+
 | 
				
			||||||
 | 
					//          | | +=v0006
 | 
				
			||||||
 | 
					// b007     | +-+
 | 
				
			||||||
 | 
					//          |   +=v0005
 | 
				
			||||||
 | 
					// b002   +-+
 | 
				
			||||||
 | 
					//        | | +=v0001
 | 
				
			||||||
 | 
					// b005   | +-+
 | 
				
			||||||
 | 
					//        |   +=v0004
 | 
				
			||||||
 | 
					// b001 +-+
 | 
				
			||||||
 | 
					//        | +=v0003
 | 
				
			||||||
 | 
					// b003   +-+
 | 
				
			||||||
 | 
					//          +=v0002
 | 
				
			||||||
 | 
					var blackDecodeTable = [...][2]int16{
 | 
				
			||||||
 | 
						0:   {0, 0},
 | 
				
			||||||
 | 
						1:   {2, 3},
 | 
				
			||||||
 | 
						2:   {4, 5},
 | 
				
			||||||
 | 
						3:   {^3, ^2},
 | 
				
			||||||
 | 
						4:   {6, 7},
 | 
				
			||||||
 | 
						5:   {^1, ^4},
 | 
				
			||||||
 | 
						6:   {8, 9},
 | 
				
			||||||
 | 
						7:   {^6, ^5},
 | 
				
			||||||
 | 
						8:   {10, 11},
 | 
				
			||||||
 | 
						9:   {12, ^7},
 | 
				
			||||||
 | 
						10:  {13, 14},
 | 
				
			||||||
 | 
						11:  {15, 16},
 | 
				
			||||||
 | 
						12:  {^9, ^8},
 | 
				
			||||||
 | 
						13:  {17, 18},
 | 
				
			||||||
 | 
						14:  {19, 20},
 | 
				
			||||||
 | 
						15:  {^10, ^11},
 | 
				
			||||||
 | 
						16:  {21, ^12},
 | 
				
			||||||
 | 
						17:  {0, 22},
 | 
				
			||||||
 | 
						18:  {23, 24},
 | 
				
			||||||
 | 
						19:  {^13, 25},
 | 
				
			||||||
 | 
						20:  {26, ^14},
 | 
				
			||||||
 | 
						21:  {27, 28},
 | 
				
			||||||
 | 
						22:  {29, 30},
 | 
				
			||||||
 | 
						23:  {31, 32},
 | 
				
			||||||
 | 
						24:  {33, 34},
 | 
				
			||||||
 | 
						25:  {35, 36},
 | 
				
			||||||
 | 
						26:  {37, 38},
 | 
				
			||||||
 | 
						27:  {^15, 39},
 | 
				
			||||||
 | 
						28:  {40, 41},
 | 
				
			||||||
 | 
						29:  {42, 43},
 | 
				
			||||||
 | 
						30:  {44, 45},
 | 
				
			||||||
 | 
						31:  {^18, 46},
 | 
				
			||||||
 | 
						32:  {47, 48},
 | 
				
			||||||
 | 
						33:  {49, 50},
 | 
				
			||||||
 | 
						34:  {51, ^64},
 | 
				
			||||||
 | 
						35:  {52, 53},
 | 
				
			||||||
 | 
						36:  {54, ^16},
 | 
				
			||||||
 | 
						37:  {^17, 55},
 | 
				
			||||||
 | 
						38:  {56, 57},
 | 
				
			||||||
 | 
						39:  {58, 59},
 | 
				
			||||||
 | 
						40:  {60, 61},
 | 
				
			||||||
 | 
						41:  {62, ^0},
 | 
				
			||||||
 | 
						42:  {^1792, 63},
 | 
				
			||||||
 | 
						43:  {64, 65},
 | 
				
			||||||
 | 
						44:  {^1856, ^1920},
 | 
				
			||||||
 | 
						45:  {66, 67},
 | 
				
			||||||
 | 
						46:  {68, 69},
 | 
				
			||||||
 | 
						47:  {70, 71},
 | 
				
			||||||
 | 
						48:  {72, ^24},
 | 
				
			||||||
 | 
						49:  {^25, 73},
 | 
				
			||||||
 | 
						50:  {74, 75},
 | 
				
			||||||
 | 
						51:  {76, 77},
 | 
				
			||||||
 | 
						52:  {^23, 78},
 | 
				
			||||||
 | 
						53:  {79, 80},
 | 
				
			||||||
 | 
						54:  {81, 82},
 | 
				
			||||||
 | 
						55:  {83, 84},
 | 
				
			||||||
 | 
						56:  {85, 86},
 | 
				
			||||||
 | 
						57:  {87, ^22},
 | 
				
			||||||
 | 
						58:  {88, 89},
 | 
				
			||||||
 | 
						59:  {90, ^19},
 | 
				
			||||||
 | 
						60:  {^20, 91},
 | 
				
			||||||
 | 
						61:  {92, 93},
 | 
				
			||||||
 | 
						62:  {^21, 94},
 | 
				
			||||||
 | 
						63:  {^1984, ^2048},
 | 
				
			||||||
 | 
						64:  {^2112, ^2176},
 | 
				
			||||||
 | 
						65:  {^2240, ^2304},
 | 
				
			||||||
 | 
						66:  {^2368, ^2432},
 | 
				
			||||||
 | 
						67:  {^2496, ^2560},
 | 
				
			||||||
 | 
						68:  {^52, 95},
 | 
				
			||||||
 | 
						69:  {96, ^55},
 | 
				
			||||||
 | 
						70:  {^56, 97},
 | 
				
			||||||
 | 
						71:  {98, ^59},
 | 
				
			||||||
 | 
						72:  {^60, 99},
 | 
				
			||||||
 | 
						73:  {100, ^320},
 | 
				
			||||||
 | 
						74:  {^384, ^448},
 | 
				
			||||||
 | 
						75:  {101, ^53},
 | 
				
			||||||
 | 
						76:  {^54, 102},
 | 
				
			||||||
 | 
						77:  {103, 104},
 | 
				
			||||||
 | 
						78:  {^50, ^51},
 | 
				
			||||||
 | 
						79:  {^44, ^45},
 | 
				
			||||||
 | 
						80:  {^46, ^47},
 | 
				
			||||||
 | 
						81:  {^57, ^58},
 | 
				
			||||||
 | 
						82:  {^61, ^256},
 | 
				
			||||||
 | 
						83:  {^48, ^49},
 | 
				
			||||||
 | 
						84:  {^62, ^63},
 | 
				
			||||||
 | 
						85:  {^30, ^31},
 | 
				
			||||||
 | 
						86:  {^32, ^33},
 | 
				
			||||||
 | 
						87:  {^40, ^41},
 | 
				
			||||||
 | 
						88:  {^128, ^192},
 | 
				
			||||||
 | 
						89:  {^26, ^27},
 | 
				
			||||||
 | 
						90:  {^28, ^29},
 | 
				
			||||||
 | 
						91:  {^34, ^35},
 | 
				
			||||||
 | 
						92:  {^36, ^37},
 | 
				
			||||||
 | 
						93:  {^38, ^39},
 | 
				
			||||||
 | 
						94:  {^42, ^43},
 | 
				
			||||||
 | 
						95:  {^640, ^704},
 | 
				
			||||||
 | 
						96:  {^768, ^832},
 | 
				
			||||||
 | 
						97:  {^1280, ^1344},
 | 
				
			||||||
 | 
						98:  {^1408, ^1472},
 | 
				
			||||||
 | 
						99:  {^1536, ^1600},
 | 
				
			||||||
 | 
						100: {^1664, ^1728},
 | 
				
			||||||
 | 
						101: {^512, ^576},
 | 
				
			||||||
 | 
						102: {^896, ^960},
 | 
				
			||||||
 | 
						103: {^1024, ^1088},
 | 
				
			||||||
 | 
						104: {^1152, ^1216},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const maxCodeLength = 13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Each encodeTable is represented by an array of bitStrings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// bitString is a pair of uint32 values representing a bit code.
 | 
				
			||||||
 | 
					// The nBits low bits of bits make up the actual bit code.
 | 
				
			||||||
 | 
					// Eg. bitString{0x0004, 8} represents the bitcode "00000100".
 | 
				
			||||||
 | 
					type bitString struct {
 | 
				
			||||||
 | 
						bits  uint32
 | 
				
			||||||
 | 
						nBits uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// modeEncodeTable represents Table 1 and the End-of-Line code.
 | 
				
			||||||
 | 
					var modeEncodeTable = [...]bitString{
 | 
				
			||||||
 | 
						0:  {0x0001, 4},  // "0001"
 | 
				
			||||||
 | 
						1:  {0x0001, 3},  // "001"
 | 
				
			||||||
 | 
						2:  {0x0001, 1},  // "1"
 | 
				
			||||||
 | 
						3:  {0x0003, 3},  // "011"
 | 
				
			||||||
 | 
						4:  {0x0003, 6},  // "000011"
 | 
				
			||||||
 | 
						5:  {0x0003, 7},  // "0000011"
 | 
				
			||||||
 | 
						6:  {0x0002, 3},  // "010"
 | 
				
			||||||
 | 
						7:  {0x0002, 6},  // "000010"
 | 
				
			||||||
 | 
						8:  {0x0002, 7},  // "0000010"
 | 
				
			||||||
 | 
						9:  {0x0001, 7},  // "0000001"
 | 
				
			||||||
 | 
						10: {0x0001, 12}, // "000000000001"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// whiteEncodeTable2 represents Table 2 for a white run.
 | 
				
			||||||
 | 
					var whiteEncodeTable2 = [...]bitString{
 | 
				
			||||||
 | 
						0:  {0x0035, 8}, // "00110101"
 | 
				
			||||||
 | 
						1:  {0x0007, 6}, // "000111"
 | 
				
			||||||
 | 
						2:  {0x0007, 4}, // "0111"
 | 
				
			||||||
 | 
						3:  {0x0008, 4}, // "1000"
 | 
				
			||||||
 | 
						4:  {0x000b, 4}, // "1011"
 | 
				
			||||||
 | 
						5:  {0x000c, 4}, // "1100"
 | 
				
			||||||
 | 
						6:  {0x000e, 4}, // "1110"
 | 
				
			||||||
 | 
						7:  {0x000f, 4}, // "1111"
 | 
				
			||||||
 | 
						8:  {0x0013, 5}, // "10011"
 | 
				
			||||||
 | 
						9:  {0x0014, 5}, // "10100"
 | 
				
			||||||
 | 
						10: {0x0007, 5}, // "00111"
 | 
				
			||||||
 | 
						11: {0x0008, 5}, // "01000"
 | 
				
			||||||
 | 
						12: {0x0008, 6}, // "001000"
 | 
				
			||||||
 | 
						13: {0x0003, 6}, // "000011"
 | 
				
			||||||
 | 
						14: {0x0034, 6}, // "110100"
 | 
				
			||||||
 | 
						15: {0x0035, 6}, // "110101"
 | 
				
			||||||
 | 
						16: {0x002a, 6}, // "101010"
 | 
				
			||||||
 | 
						17: {0x002b, 6}, // "101011"
 | 
				
			||||||
 | 
						18: {0x0027, 7}, // "0100111"
 | 
				
			||||||
 | 
						19: {0x000c, 7}, // "0001100"
 | 
				
			||||||
 | 
						20: {0x0008, 7}, // "0001000"
 | 
				
			||||||
 | 
						21: {0x0017, 7}, // "0010111"
 | 
				
			||||||
 | 
						22: {0x0003, 7}, // "0000011"
 | 
				
			||||||
 | 
						23: {0x0004, 7}, // "0000100"
 | 
				
			||||||
 | 
						24: {0x0028, 7}, // "0101000"
 | 
				
			||||||
 | 
						25: {0x002b, 7}, // "0101011"
 | 
				
			||||||
 | 
						26: {0x0013, 7}, // "0010011"
 | 
				
			||||||
 | 
						27: {0x0024, 7}, // "0100100"
 | 
				
			||||||
 | 
						28: {0x0018, 7}, // "0011000"
 | 
				
			||||||
 | 
						29: {0x0002, 8}, // "00000010"
 | 
				
			||||||
 | 
						30: {0x0003, 8}, // "00000011"
 | 
				
			||||||
 | 
						31: {0x001a, 8}, // "00011010"
 | 
				
			||||||
 | 
						32: {0x001b, 8}, // "00011011"
 | 
				
			||||||
 | 
						33: {0x0012, 8}, // "00010010"
 | 
				
			||||||
 | 
						34: {0x0013, 8}, // "00010011"
 | 
				
			||||||
 | 
						35: {0x0014, 8}, // "00010100"
 | 
				
			||||||
 | 
						36: {0x0015, 8}, // "00010101"
 | 
				
			||||||
 | 
						37: {0x0016, 8}, // "00010110"
 | 
				
			||||||
 | 
						38: {0x0017, 8}, // "00010111"
 | 
				
			||||||
 | 
						39: {0x0028, 8}, // "00101000"
 | 
				
			||||||
 | 
						40: {0x0029, 8}, // "00101001"
 | 
				
			||||||
 | 
						41: {0x002a, 8}, // "00101010"
 | 
				
			||||||
 | 
						42: {0x002b, 8}, // "00101011"
 | 
				
			||||||
 | 
						43: {0x002c, 8}, // "00101100"
 | 
				
			||||||
 | 
						44: {0x002d, 8}, // "00101101"
 | 
				
			||||||
 | 
						45: {0x0004, 8}, // "00000100"
 | 
				
			||||||
 | 
						46: {0x0005, 8}, // "00000101"
 | 
				
			||||||
 | 
						47: {0x000a, 8}, // "00001010"
 | 
				
			||||||
 | 
						48: {0x000b, 8}, // "00001011"
 | 
				
			||||||
 | 
						49: {0x0052, 8}, // "01010010"
 | 
				
			||||||
 | 
						50: {0x0053, 8}, // "01010011"
 | 
				
			||||||
 | 
						51: {0x0054, 8}, // "01010100"
 | 
				
			||||||
 | 
						52: {0x0055, 8}, // "01010101"
 | 
				
			||||||
 | 
						53: {0x0024, 8}, // "00100100"
 | 
				
			||||||
 | 
						54: {0x0025, 8}, // "00100101"
 | 
				
			||||||
 | 
						55: {0x0058, 8}, // "01011000"
 | 
				
			||||||
 | 
						56: {0x0059, 8}, // "01011001"
 | 
				
			||||||
 | 
						57: {0x005a, 8}, // "01011010"
 | 
				
			||||||
 | 
						58: {0x005b, 8}, // "01011011"
 | 
				
			||||||
 | 
						59: {0x004a, 8}, // "01001010"
 | 
				
			||||||
 | 
						60: {0x004b, 8}, // "01001011"
 | 
				
			||||||
 | 
						61: {0x0032, 8}, // "00110010"
 | 
				
			||||||
 | 
						62: {0x0033, 8}, // "00110011"
 | 
				
			||||||
 | 
						63: {0x0034, 8}, // "00110100"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// whiteEncodeTable3 represents Table 3 for a white run.
 | 
				
			||||||
 | 
					var whiteEncodeTable3 = [...]bitString{
 | 
				
			||||||
 | 
						0:  {0x001b, 5},  // "11011"
 | 
				
			||||||
 | 
						1:  {0x0012, 5},  // "10010"
 | 
				
			||||||
 | 
						2:  {0x0017, 6},  // "010111"
 | 
				
			||||||
 | 
						3:  {0x0037, 7},  // "0110111"
 | 
				
			||||||
 | 
						4:  {0x0036, 8},  // "00110110"
 | 
				
			||||||
 | 
						5:  {0x0037, 8},  // "00110111"
 | 
				
			||||||
 | 
						6:  {0x0064, 8},  // "01100100"
 | 
				
			||||||
 | 
						7:  {0x0065, 8},  // "01100101"
 | 
				
			||||||
 | 
						8:  {0x0068, 8},  // "01101000"
 | 
				
			||||||
 | 
						9:  {0x0067, 8},  // "01100111"
 | 
				
			||||||
 | 
						10: {0x00cc, 9},  // "011001100"
 | 
				
			||||||
 | 
						11: {0x00cd, 9},  // "011001101"
 | 
				
			||||||
 | 
						12: {0x00d2, 9},  // "011010010"
 | 
				
			||||||
 | 
						13: {0x00d3, 9},  // "011010011"
 | 
				
			||||||
 | 
						14: {0x00d4, 9},  // "011010100"
 | 
				
			||||||
 | 
						15: {0x00d5, 9},  // "011010101"
 | 
				
			||||||
 | 
						16: {0x00d6, 9},  // "011010110"
 | 
				
			||||||
 | 
						17: {0x00d7, 9},  // "011010111"
 | 
				
			||||||
 | 
						18: {0x00d8, 9},  // "011011000"
 | 
				
			||||||
 | 
						19: {0x00d9, 9},  // "011011001"
 | 
				
			||||||
 | 
						20: {0x00da, 9},  // "011011010"
 | 
				
			||||||
 | 
						21: {0x00db, 9},  // "011011011"
 | 
				
			||||||
 | 
						22: {0x0098, 9},  // "010011000"
 | 
				
			||||||
 | 
						23: {0x0099, 9},  // "010011001"
 | 
				
			||||||
 | 
						24: {0x009a, 9},  // "010011010"
 | 
				
			||||||
 | 
						25: {0x0018, 6},  // "011000"
 | 
				
			||||||
 | 
						26: {0x009b, 9},  // "010011011"
 | 
				
			||||||
 | 
						27: {0x0008, 11}, // "00000001000"
 | 
				
			||||||
 | 
						28: {0x000c, 11}, // "00000001100"
 | 
				
			||||||
 | 
						29: {0x000d, 11}, // "00000001101"
 | 
				
			||||||
 | 
						30: {0x0012, 12}, // "000000010010"
 | 
				
			||||||
 | 
						31: {0x0013, 12}, // "000000010011"
 | 
				
			||||||
 | 
						32: {0x0014, 12}, // "000000010100"
 | 
				
			||||||
 | 
						33: {0x0015, 12}, // "000000010101"
 | 
				
			||||||
 | 
						34: {0x0016, 12}, // "000000010110"
 | 
				
			||||||
 | 
						35: {0x0017, 12}, // "000000010111"
 | 
				
			||||||
 | 
						36: {0x001c, 12}, // "000000011100"
 | 
				
			||||||
 | 
						37: {0x001d, 12}, // "000000011101"
 | 
				
			||||||
 | 
						38: {0x001e, 12}, // "000000011110"
 | 
				
			||||||
 | 
						39: {0x001f, 12}, // "000000011111"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// blackEncodeTable2 represents Table 2 for a black run.
 | 
				
			||||||
 | 
					var blackEncodeTable2 = [...]bitString{
 | 
				
			||||||
 | 
						0:  {0x0037, 10}, // "0000110111"
 | 
				
			||||||
 | 
						1:  {0x0002, 3},  // "010"
 | 
				
			||||||
 | 
						2:  {0x0003, 2},  // "11"
 | 
				
			||||||
 | 
						3:  {0x0002, 2},  // "10"
 | 
				
			||||||
 | 
						4:  {0x0003, 3},  // "011"
 | 
				
			||||||
 | 
						5:  {0x0003, 4},  // "0011"
 | 
				
			||||||
 | 
						6:  {0x0002, 4},  // "0010"
 | 
				
			||||||
 | 
						7:  {0x0003, 5},  // "00011"
 | 
				
			||||||
 | 
						8:  {0x0005, 6},  // "000101"
 | 
				
			||||||
 | 
						9:  {0x0004, 6},  // "000100"
 | 
				
			||||||
 | 
						10: {0x0004, 7},  // "0000100"
 | 
				
			||||||
 | 
						11: {0x0005, 7},  // "0000101"
 | 
				
			||||||
 | 
						12: {0x0007, 7},  // "0000111"
 | 
				
			||||||
 | 
						13: {0x0004, 8},  // "00000100"
 | 
				
			||||||
 | 
						14: {0x0007, 8},  // "00000111"
 | 
				
			||||||
 | 
						15: {0x0018, 9},  // "000011000"
 | 
				
			||||||
 | 
						16: {0x0017, 10}, // "0000010111"
 | 
				
			||||||
 | 
						17: {0x0018, 10}, // "0000011000"
 | 
				
			||||||
 | 
						18: {0x0008, 10}, // "0000001000"
 | 
				
			||||||
 | 
						19: {0x0067, 11}, // "00001100111"
 | 
				
			||||||
 | 
						20: {0x0068, 11}, // "00001101000"
 | 
				
			||||||
 | 
						21: {0x006c, 11}, // "00001101100"
 | 
				
			||||||
 | 
						22: {0x0037, 11}, // "00000110111"
 | 
				
			||||||
 | 
						23: {0x0028, 11}, // "00000101000"
 | 
				
			||||||
 | 
						24: {0x0017, 11}, // "00000010111"
 | 
				
			||||||
 | 
						25: {0x0018, 11}, // "00000011000"
 | 
				
			||||||
 | 
						26: {0x00ca, 12}, // "000011001010"
 | 
				
			||||||
 | 
						27: {0x00cb, 12}, // "000011001011"
 | 
				
			||||||
 | 
						28: {0x00cc, 12}, // "000011001100"
 | 
				
			||||||
 | 
						29: {0x00cd, 12}, // "000011001101"
 | 
				
			||||||
 | 
						30: {0x0068, 12}, // "000001101000"
 | 
				
			||||||
 | 
						31: {0x0069, 12}, // "000001101001"
 | 
				
			||||||
 | 
						32: {0x006a, 12}, // "000001101010"
 | 
				
			||||||
 | 
						33: {0x006b, 12}, // "000001101011"
 | 
				
			||||||
 | 
						34: {0x00d2, 12}, // "000011010010"
 | 
				
			||||||
 | 
						35: {0x00d3, 12}, // "000011010011"
 | 
				
			||||||
 | 
						36: {0x00d4, 12}, // "000011010100"
 | 
				
			||||||
 | 
						37: {0x00d5, 12}, // "000011010101"
 | 
				
			||||||
 | 
						38: {0x00d6, 12}, // "000011010110"
 | 
				
			||||||
 | 
						39: {0x00d7, 12}, // "000011010111"
 | 
				
			||||||
 | 
						40: {0x006c, 12}, // "000001101100"
 | 
				
			||||||
 | 
						41: {0x006d, 12}, // "000001101101"
 | 
				
			||||||
 | 
						42: {0x00da, 12}, // "000011011010"
 | 
				
			||||||
 | 
						43: {0x00db, 12}, // "000011011011"
 | 
				
			||||||
 | 
						44: {0x0054, 12}, // "000001010100"
 | 
				
			||||||
 | 
						45: {0x0055, 12}, // "000001010101"
 | 
				
			||||||
 | 
						46: {0x0056, 12}, // "000001010110"
 | 
				
			||||||
 | 
						47: {0x0057, 12}, // "000001010111"
 | 
				
			||||||
 | 
						48: {0x0064, 12}, // "000001100100"
 | 
				
			||||||
 | 
						49: {0x0065, 12}, // "000001100101"
 | 
				
			||||||
 | 
						50: {0x0052, 12}, // "000001010010"
 | 
				
			||||||
 | 
						51: {0x0053, 12}, // "000001010011"
 | 
				
			||||||
 | 
						52: {0x0024, 12}, // "000000100100"
 | 
				
			||||||
 | 
						53: {0x0037, 12}, // "000000110111"
 | 
				
			||||||
 | 
						54: {0x0038, 12}, // "000000111000"
 | 
				
			||||||
 | 
						55: {0x0027, 12}, // "000000100111"
 | 
				
			||||||
 | 
						56: {0x0028, 12}, // "000000101000"
 | 
				
			||||||
 | 
						57: {0x0058, 12}, // "000001011000"
 | 
				
			||||||
 | 
						58: {0x0059, 12}, // "000001011001"
 | 
				
			||||||
 | 
						59: {0x002b, 12}, // "000000101011"
 | 
				
			||||||
 | 
						60: {0x002c, 12}, // "000000101100"
 | 
				
			||||||
 | 
						61: {0x005a, 12}, // "000001011010"
 | 
				
			||||||
 | 
						62: {0x0066, 12}, // "000001100110"
 | 
				
			||||||
 | 
						63: {0x0067, 12}, // "000001100111"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// blackEncodeTable3 represents Table 3 for a black run.
 | 
				
			||||||
 | 
					var blackEncodeTable3 = [...]bitString{
 | 
				
			||||||
 | 
						0:  {0x000f, 10}, // "0000001111"
 | 
				
			||||||
 | 
						1:  {0x00c8, 12}, // "000011001000"
 | 
				
			||||||
 | 
						2:  {0x00c9, 12}, // "000011001001"
 | 
				
			||||||
 | 
						3:  {0x005b, 12}, // "000001011011"
 | 
				
			||||||
 | 
						4:  {0x0033, 12}, // "000000110011"
 | 
				
			||||||
 | 
						5:  {0x0034, 12}, // "000000110100"
 | 
				
			||||||
 | 
						6:  {0x0035, 12}, // "000000110101"
 | 
				
			||||||
 | 
						7:  {0x006c, 13}, // "0000001101100"
 | 
				
			||||||
 | 
						8:  {0x006d, 13}, // "0000001101101"
 | 
				
			||||||
 | 
						9:  {0x004a, 13}, // "0000001001010"
 | 
				
			||||||
 | 
						10: {0x004b, 13}, // "0000001001011"
 | 
				
			||||||
 | 
						11: {0x004c, 13}, // "0000001001100"
 | 
				
			||||||
 | 
						12: {0x004d, 13}, // "0000001001101"
 | 
				
			||||||
 | 
						13: {0x0072, 13}, // "0000001110010"
 | 
				
			||||||
 | 
						14: {0x0073, 13}, // "0000001110011"
 | 
				
			||||||
 | 
						15: {0x0074, 13}, // "0000001110100"
 | 
				
			||||||
 | 
						16: {0x0075, 13}, // "0000001110101"
 | 
				
			||||||
 | 
						17: {0x0076, 13}, // "0000001110110"
 | 
				
			||||||
 | 
						18: {0x0077, 13}, // "0000001110111"
 | 
				
			||||||
 | 
						19: {0x0052, 13}, // "0000001010010"
 | 
				
			||||||
 | 
						20: {0x0053, 13}, // "0000001010011"
 | 
				
			||||||
 | 
						21: {0x0054, 13}, // "0000001010100"
 | 
				
			||||||
 | 
						22: {0x0055, 13}, // "0000001010101"
 | 
				
			||||||
 | 
						23: {0x005a, 13}, // "0000001011010"
 | 
				
			||||||
 | 
						24: {0x005b, 13}, // "0000001011011"
 | 
				
			||||||
 | 
						25: {0x0064, 13}, // "0000001100100"
 | 
				
			||||||
 | 
						26: {0x0065, 13}, // "0000001100101"
 | 
				
			||||||
 | 
						27: {0x0008, 11}, // "00000001000"
 | 
				
			||||||
 | 
						28: {0x000c, 11}, // "00000001100"
 | 
				
			||||||
 | 
						29: {0x000d, 11}, // "00000001101"
 | 
				
			||||||
 | 
						30: {0x0012, 12}, // "000000010010"
 | 
				
			||||||
 | 
						31: {0x0013, 12}, // "000000010011"
 | 
				
			||||||
 | 
						32: {0x0014, 12}, // "000000010100"
 | 
				
			||||||
 | 
						33: {0x0015, 12}, // "000000010101"
 | 
				
			||||||
 | 
						34: {0x0016, 12}, // "000000010110"
 | 
				
			||||||
 | 
						35: {0x0017, 12}, // "000000010111"
 | 
				
			||||||
 | 
						36: {0x001c, 12}, // "000000011100"
 | 
				
			||||||
 | 
						37: {0x001d, 12}, // "000000011101"
 | 
				
			||||||
 | 
						38: {0x001e, 12}, // "000000011110"
 | 
				
			||||||
 | 
						39: {0x001f, 12}, // "000000011111"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// COPY PASTE table.go BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						modePass = iota // Pass
 | 
				
			||||||
 | 
						modeH           // Horizontal
 | 
				
			||||||
 | 
						modeV0          // Vertical-0
 | 
				
			||||||
 | 
						modeVR1         // Vertical-Right-1
 | 
				
			||||||
 | 
						modeVR2         // Vertical-Right-2
 | 
				
			||||||
 | 
						modeVR3         // Vertical-Right-3
 | 
				
			||||||
 | 
						modeVL1         // Vertical-Left-1
 | 
				
			||||||
 | 
						modeVL2         // Vertical-Left-2
 | 
				
			||||||
 | 
						modeVL3         // Vertical-Left-3
 | 
				
			||||||
 | 
						modeExt         // Extension
 | 
				
			||||||
 | 
						modeEOL         // End-of-Line
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// COPY PASTE table.go END
 | 
				
			||||||
							
								
								
									
										102
									
								
								vendor/golang.org/x/image/ccitt/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								vendor/golang.org/x/image/ccitt/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					// Copyright 2019 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package ccitt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type bitWriter struct {
 | 
				
			||||||
 | 
						w io.Writer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// order is whether to process w's bytes LSB first or MSB first.
 | 
				
			||||||
 | 
						order Order
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The high nBits bits of the bits field hold encoded bits to be written to w.
 | 
				
			||||||
 | 
						bits  uint64
 | 
				
			||||||
 | 
						nBits uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// bytes[:bw] holds encoded bytes not yet written to w.
 | 
				
			||||||
 | 
						// Overflow protection is ensured by using a multiple of 8 as bytes length.
 | 
				
			||||||
 | 
						bw    uint32
 | 
				
			||||||
 | 
						bytes [1024]uint8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// flushBits copies 64 bits from b.bits to b.bytes. If b.bytes is then full, it
 | 
				
			||||||
 | 
					// is written to b.w.
 | 
				
			||||||
 | 
					func (b *bitWriter) flushBits() error {
 | 
				
			||||||
 | 
						binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits)
 | 
				
			||||||
 | 
						b.bits = 0
 | 
				
			||||||
 | 
						b.nBits = 0
 | 
				
			||||||
 | 
						b.bw += 8
 | 
				
			||||||
 | 
						if b.bw < uint32(len(b.bytes)) {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b.bw = 0
 | 
				
			||||||
 | 
						if b.order != MSB {
 | 
				
			||||||
 | 
							reverseBitsWithinBytes(b.bytes[:])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := b.w.Write(b.bytes[:])
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// close finalizes a bitcode stream by writing any
 | 
				
			||||||
 | 
					// pending bits to bitWriter's underlying io.Writer.
 | 
				
			||||||
 | 
					func (b *bitWriter) close() error {
 | 
				
			||||||
 | 
						// Write any encoded bits to bytes.
 | 
				
			||||||
 | 
						if b.nBits > 0 {
 | 
				
			||||||
 | 
							binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits)
 | 
				
			||||||
 | 
							b.bw += (b.nBits + 7) >> 3
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if b.order != MSB {
 | 
				
			||||||
 | 
							reverseBitsWithinBytes(b.bytes[:b.bw])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Write b.bw bytes to b.w.
 | 
				
			||||||
 | 
						_, err := b.w.Write(b.bytes[:b.bw])
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// alignToByteBoundary rounds b.nBits up to a multiple of 8.
 | 
				
			||||||
 | 
					// If all 64 bits are used, flush them to bitWriter's bytes.
 | 
				
			||||||
 | 
					func (b *bitWriter) alignToByteBoundary() error {
 | 
				
			||||||
 | 
						if b.nBits = (b.nBits + 7) &^ 7; b.nBits == 64 {
 | 
				
			||||||
 | 
							return b.flushBits()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// writeCode writes a variable length bitcode to b's underlying io.Writer.
 | 
				
			||||||
 | 
					func (b *bitWriter) writeCode(bs bitString) error {
 | 
				
			||||||
 | 
						bits := bs.bits
 | 
				
			||||||
 | 
						nBits := bs.nBits
 | 
				
			||||||
 | 
						if 64-b.nBits >= nBits {
 | 
				
			||||||
 | 
							// b.bits has sufficient room for storing nBits bits.
 | 
				
			||||||
 | 
							b.bits |= uint64(bits) << (64 - nBits - b.nBits)
 | 
				
			||||||
 | 
							b.nBits += nBits
 | 
				
			||||||
 | 
							if b.nBits == 64 {
 | 
				
			||||||
 | 
								return b.flushBits()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Number of leading bits that fill b.bits.
 | 
				
			||||||
 | 
						i := 64 - b.nBits
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Fill b.bits then flush and write remaining bits.
 | 
				
			||||||
 | 
						b.bits |= uint64(bits) >> (nBits - i)
 | 
				
			||||||
 | 
						b.nBits = 64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := b.flushBits(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nBits -= i
 | 
				
			||||||
 | 
						b.bits = uint64(bits) << (64 - nBits)
 | 
				
			||||||
 | 
						b.nBits = nBits
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										69
									
								
								vendor/golang.org/x/image/tiff/buffer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/golang.org/x/image/tiff/buffer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					// Copyright 2011 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tiff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// buffer buffers an io.Reader to satisfy io.ReaderAt.
 | 
				
			||||||
 | 
					type buffer struct {
 | 
				
			||||||
 | 
						r   io.Reader
 | 
				
			||||||
 | 
						buf []byte
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// fill reads data from b.r until the buffer contains at least end bytes.
 | 
				
			||||||
 | 
					func (b *buffer) fill(end int) error {
 | 
				
			||||||
 | 
						m := len(b.buf)
 | 
				
			||||||
 | 
						if end > m {
 | 
				
			||||||
 | 
							if end > cap(b.buf) {
 | 
				
			||||||
 | 
								newcap := 1024
 | 
				
			||||||
 | 
								for newcap < end {
 | 
				
			||||||
 | 
									newcap *= 2
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								newbuf := make([]byte, end, newcap)
 | 
				
			||||||
 | 
								copy(newbuf, b.buf)
 | 
				
			||||||
 | 
								b.buf = newbuf
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								b.buf = b.buf[:end]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
 | 
				
			||||||
 | 
								end = m + n
 | 
				
			||||||
 | 
								b.buf = b.buf[:end]
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *buffer) ReadAt(p []byte, off int64) (int, error) {
 | 
				
			||||||
 | 
						o := int(off)
 | 
				
			||||||
 | 
						end := o + len(p)
 | 
				
			||||||
 | 
						if int64(end) != off+int64(len(p)) {
 | 
				
			||||||
 | 
							return 0, io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := b.fill(end)
 | 
				
			||||||
 | 
						return copy(p, b.buf[o:end]), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Slice returns a slice of the underlying buffer. The slice contains
 | 
				
			||||||
 | 
					// n bytes starting at offset off.
 | 
				
			||||||
 | 
					func (b *buffer) Slice(off, n int) ([]byte, error) {
 | 
				
			||||||
 | 
						end := off + n
 | 
				
			||||||
 | 
						if err := b.fill(end); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return b.buf[off:end], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// newReaderAt converts an io.Reader into an io.ReaderAt.
 | 
				
			||||||
 | 
					func newReaderAt(r io.Reader) io.ReaderAt {
 | 
				
			||||||
 | 
						if ra, ok := r.(io.ReaderAt); ok {
 | 
				
			||||||
 | 
							return ra
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return &buffer{
 | 
				
			||||||
 | 
							r:   r,
 | 
				
			||||||
 | 
							buf: make([]byte, 0, 1024),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										58
									
								
								vendor/golang.org/x/image/tiff/compress.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								vendor/golang.org/x/image/tiff/compress.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					// Copyright 2011 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tiff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type byteReader interface {
 | 
				
			||||||
 | 
						io.Reader
 | 
				
			||||||
 | 
						io.ByteReader
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// unpackBits decodes the PackBits-compressed data in src and returns the
 | 
				
			||||||
 | 
					// uncompressed data.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The PackBits compression format is described in section 9 (p. 42)
 | 
				
			||||||
 | 
					// of the TIFF spec.
 | 
				
			||||||
 | 
					func unpackBits(r io.Reader) ([]byte, error) {
 | 
				
			||||||
 | 
						buf := make([]byte, 128)
 | 
				
			||||||
 | 
						dst := make([]byte, 0, 1024)
 | 
				
			||||||
 | 
						br, ok := r.(byteReader)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							br = bufio.NewReader(r)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							b, err := br.ReadByte()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if err == io.EOF {
 | 
				
			||||||
 | 
									return dst, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							code := int(int8(b))
 | 
				
			||||||
 | 
							switch {
 | 
				
			||||||
 | 
							case code >= 0:
 | 
				
			||||||
 | 
								n, err := io.ReadFull(br, buf[:code+1])
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dst = append(dst, buf[:n]...)
 | 
				
			||||||
 | 
							case code == -128:
 | 
				
			||||||
 | 
								// No-op.
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								if b, err = br.ReadByte(); err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for j := 0; j < 1-code; j++ {
 | 
				
			||||||
 | 
									buf[j] = b
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dst = append(dst, buf[:1-code]...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										149
									
								
								vendor/golang.org/x/image/tiff/consts.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/golang.org/x/image/tiff/consts.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					// Copyright 2011 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tiff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A tiff image file contains one or more images. The metadata
 | 
				
			||||||
 | 
					// of each image is contained in an Image File Directory (IFD),
 | 
				
			||||||
 | 
					// which contains entries of 12 bytes each and is described
 | 
				
			||||||
 | 
					// on page 14-16 of the specification. An IFD entry consists of
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//  - a tag, which describes the signification of the entry,
 | 
				
			||||||
 | 
					//  - the data type and length of the entry,
 | 
				
			||||||
 | 
					//  - the data itself or a pointer to it if it is more than 4 bytes.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The presence of a length means that each IFD is effectively an array.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						leHeader = "II\x2A\x00" // Header for little-endian files.
 | 
				
			||||||
 | 
						beHeader = "MM\x00\x2A" // Header for big-endian files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifdLen = 12 // Length of an IFD entry in bytes.
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Data types (p. 14-16 of the spec).
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						dtByte     = 1
 | 
				
			||||||
 | 
						dtASCII    = 2
 | 
				
			||||||
 | 
						dtShort    = 3
 | 
				
			||||||
 | 
						dtLong     = 4
 | 
				
			||||||
 | 
						dtRational = 5
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The length of one instance of each data type in bytes.
 | 
				
			||||||
 | 
					var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Tags (see p. 28-41 of the spec).
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						tImageWidth                = 256
 | 
				
			||||||
 | 
						tImageLength               = 257
 | 
				
			||||||
 | 
						tBitsPerSample             = 258
 | 
				
			||||||
 | 
						tCompression               = 259
 | 
				
			||||||
 | 
						tPhotometricInterpretation = 262
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tFillOrder = 266
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tStripOffsets    = 273
 | 
				
			||||||
 | 
						tSamplesPerPixel = 277
 | 
				
			||||||
 | 
						tRowsPerStrip    = 278
 | 
				
			||||||
 | 
						tStripByteCounts = 279
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tT4Options = 292 // CCITT Group 3 options, a set of 32 flag bits.
 | 
				
			||||||
 | 
						tT6Options = 293 // CCITT Group 4 options, a set of 32 flag bits.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tTileWidth      = 322
 | 
				
			||||||
 | 
						tTileLength     = 323
 | 
				
			||||||
 | 
						tTileOffsets    = 324
 | 
				
			||||||
 | 
						tTileByteCounts = 325
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tXResolution    = 282
 | 
				
			||||||
 | 
						tYResolution    = 283
 | 
				
			||||||
 | 
						tResolutionUnit = 296
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tPredictor    = 317
 | 
				
			||||||
 | 
						tColorMap     = 320
 | 
				
			||||||
 | 
						tExtraSamples = 338
 | 
				
			||||||
 | 
						tSampleFormat = 339
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Compression types (defined in various places in the spec and supplements).
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						cNone       = 1
 | 
				
			||||||
 | 
						cCCITT      = 2
 | 
				
			||||||
 | 
						cG3         = 3 // Group 3 Fax.
 | 
				
			||||||
 | 
						cG4         = 4 // Group 4 Fax.
 | 
				
			||||||
 | 
						cLZW        = 5
 | 
				
			||||||
 | 
						cJPEGOld    = 6 // Superseded by cJPEG.
 | 
				
			||||||
 | 
						cJPEG       = 7
 | 
				
			||||||
 | 
						cDeflate    = 8 // zlib compression.
 | 
				
			||||||
 | 
						cPackBits   = 32773
 | 
				
			||||||
 | 
						cDeflateOld = 32946 // Superseded by cDeflate.
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Photometric interpretation values (see p. 37 of the spec).
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						pWhiteIsZero = 0
 | 
				
			||||||
 | 
						pBlackIsZero = 1
 | 
				
			||||||
 | 
						pRGB         = 2
 | 
				
			||||||
 | 
						pPaletted    = 3
 | 
				
			||||||
 | 
						pTransMask   = 4 // transparency mask
 | 
				
			||||||
 | 
						pCMYK        = 5
 | 
				
			||||||
 | 
						pYCbCr       = 6
 | 
				
			||||||
 | 
						pCIELab      = 8
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Values for the tPredictor tag (page 64-65 of the spec).
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						prNone       = 1
 | 
				
			||||||
 | 
						prHorizontal = 2
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Values for the tResolutionUnit tag (page 18).
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						resNone    = 1
 | 
				
			||||||
 | 
						resPerInch = 2 // Dots per inch.
 | 
				
			||||||
 | 
						resPerCM   = 3 // Dots per centimeter.
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// imageMode represents the mode of the image.
 | 
				
			||||||
 | 
					type imageMode int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						mBilevel imageMode = iota
 | 
				
			||||||
 | 
						mPaletted
 | 
				
			||||||
 | 
						mGray
 | 
				
			||||||
 | 
						mGrayInvert
 | 
				
			||||||
 | 
						mRGB
 | 
				
			||||||
 | 
						mRGBA
 | 
				
			||||||
 | 
						mNRGBA
 | 
				
			||||||
 | 
						mCMYK
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CompressionType describes the type of compression used in Options.
 | 
				
			||||||
 | 
					type CompressionType int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Constants for supported compression types.
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						Uncompressed CompressionType = iota
 | 
				
			||||||
 | 
						Deflate
 | 
				
			||||||
 | 
						LZW
 | 
				
			||||||
 | 
						CCITTGroup3
 | 
				
			||||||
 | 
						CCITTGroup4
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// specValue returns the compression type constant from the TIFF spec that
 | 
				
			||||||
 | 
					// is equivalent to c.
 | 
				
			||||||
 | 
					func (c CompressionType) specValue() uint32 {
 | 
				
			||||||
 | 
						switch c {
 | 
				
			||||||
 | 
						case LZW:
 | 
				
			||||||
 | 
							return cLZW
 | 
				
			||||||
 | 
						case Deflate:
 | 
				
			||||||
 | 
							return cDeflate
 | 
				
			||||||
 | 
						case CCITTGroup3:
 | 
				
			||||||
 | 
							return cG3
 | 
				
			||||||
 | 
						case CCITTGroup4:
 | 
				
			||||||
 | 
							return cG4
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cNone
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								vendor/golang.org/x/image/tiff/fuzz.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/golang.org/x/image/tiff/fuzz.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					// Copyright 2019 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build gofuzz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tiff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "bytes"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Fuzz(data []byte) int {
 | 
				
			||||||
 | 
						cfg, err := DecodeConfig(bytes.NewReader(data))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if cfg.Width*cfg.Height > 1e6 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						img, err := Decode(bytes.NewReader(data))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var w bytes.Buffer
 | 
				
			||||||
 | 
						err = Encode(&w, img, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										272
									
								
								vendor/golang.org/x/image/tiff/lzw/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								vendor/golang.org/x/image/tiff/lzw/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					// Copyright 2011 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package lzw implements the Lempel-Ziv-Welch compressed data format,
 | 
				
			||||||
 | 
					// described in T. A. Welch, ``A Technique for High-Performance Data
 | 
				
			||||||
 | 
					// Compression'', Computer, 17(6) (June 1984), pp 8-19.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// In particular, it implements LZW as used by the TIFF file format, including
 | 
				
			||||||
 | 
					// an "off by one" algorithmic difference when compared to standard LZW.
 | 
				
			||||||
 | 
					package lzw // import "golang.org/x/image/tiff/lzw"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					This file was branched from src/pkg/compress/lzw/reader.go in the
 | 
				
			||||||
 | 
					standard library. Differences from the original are marked with "NOTE".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The tif_lzw.c file in the libtiff C library has this comment:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					The 5.0 spec describes a different algorithm than Aldus
 | 
				
			||||||
 | 
					implements.  Specifically, Aldus does code length transitions
 | 
				
			||||||
 | 
					one code earlier than should be done (for real LZW).
 | 
				
			||||||
 | 
					Earlier versions of this library implemented the correct
 | 
				
			||||||
 | 
					LZW algorithm, but emitted codes in a bit order opposite
 | 
				
			||||||
 | 
					to the TIFF spec.  Thus, to maintain compatibility w/ Aldus
 | 
				
			||||||
 | 
					we interpret MSB-LSB ordered codes to be images written w/
 | 
				
			||||||
 | 
					old versions of this library, but otherwise adhere to the
 | 
				
			||||||
 | 
					Aldus "off by one" algorithm.
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The Go code doesn't read (invalid) TIFF files written by old versions of
 | 
				
			||||||
 | 
					libtiff, but the LZW algorithm in this package still differs from the one in
 | 
				
			||||||
 | 
					Go's standard package library to accomodate this "off by one" in valid TIFFs.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Order specifies the bit ordering in an LZW data stream.
 | 
				
			||||||
 | 
					type Order int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// LSB means Least Significant Bits first, as used in the GIF file format.
 | 
				
			||||||
 | 
						LSB Order = iota
 | 
				
			||||||
 | 
						// MSB means Most Significant Bits first, as used in the TIFF and PDF
 | 
				
			||||||
 | 
						// file formats.
 | 
				
			||||||
 | 
						MSB
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						maxWidth           = 12
 | 
				
			||||||
 | 
						decoderInvalidCode = 0xffff
 | 
				
			||||||
 | 
						flushBuffer        = 1 << maxWidth
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// decoder is the state from which the readXxx method converts a byte
 | 
				
			||||||
 | 
					// stream into a code stream.
 | 
				
			||||||
 | 
					type decoder struct {
 | 
				
			||||||
 | 
						r        io.ByteReader
 | 
				
			||||||
 | 
						bits     uint32
 | 
				
			||||||
 | 
						nBits    uint
 | 
				
			||||||
 | 
						width    uint
 | 
				
			||||||
 | 
						read     func(*decoder) (uint16, error) // readLSB or readMSB
 | 
				
			||||||
 | 
						litWidth int                            // width in bits of literal codes
 | 
				
			||||||
 | 
						err      error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The first 1<<litWidth codes are literal codes.
 | 
				
			||||||
 | 
						// The next two codes mean clear and EOF.
 | 
				
			||||||
 | 
						// Other valid codes are in the range [lo, hi] where lo := clear + 2,
 | 
				
			||||||
 | 
						// with the upper bound incrementing on each code seen.
 | 
				
			||||||
 | 
						// overflow is the code at which hi overflows the code width. NOTE: TIFF's LZW is "off by one".
 | 
				
			||||||
 | 
						// last is the most recently seen code, or decoderInvalidCode.
 | 
				
			||||||
 | 
						clear, eof, hi, overflow, last uint16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Each code c in [lo, hi] expands to two or more bytes. For c != hi:
 | 
				
			||||||
 | 
						//   suffix[c] is the last of these bytes.
 | 
				
			||||||
 | 
						//   prefix[c] is the code for all but the last byte.
 | 
				
			||||||
 | 
						//   This code can either be a literal code or another code in [lo, c).
 | 
				
			||||||
 | 
						// The c == hi case is a special case.
 | 
				
			||||||
 | 
						suffix [1 << maxWidth]uint8
 | 
				
			||||||
 | 
						prefix [1 << maxWidth]uint16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// output is the temporary output buffer.
 | 
				
			||||||
 | 
						// Literal codes are accumulated from the start of the buffer.
 | 
				
			||||||
 | 
						// Non-literal codes decode to a sequence of suffixes that are first
 | 
				
			||||||
 | 
						// written right-to-left from the end of the buffer before being copied
 | 
				
			||||||
 | 
						// to the start of the buffer.
 | 
				
			||||||
 | 
						// It is flushed when it contains >= 1<<maxWidth bytes,
 | 
				
			||||||
 | 
						// so that there is always room to decode an entire code.
 | 
				
			||||||
 | 
						output [2 * 1 << maxWidth]byte
 | 
				
			||||||
 | 
						o      int    // write index into output
 | 
				
			||||||
 | 
						toRead []byte // bytes to return from Read
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// readLSB returns the next code for "Least Significant Bits first" data.
 | 
				
			||||||
 | 
					func (d *decoder) readLSB() (uint16, error) {
 | 
				
			||||||
 | 
						for d.nBits < d.width {
 | 
				
			||||||
 | 
							x, err := d.r.ReadByte()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.bits |= uint32(x) << d.nBits
 | 
				
			||||||
 | 
							d.nBits += 8
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						code := uint16(d.bits & (1<<d.width - 1))
 | 
				
			||||||
 | 
						d.bits >>= d.width
 | 
				
			||||||
 | 
						d.nBits -= d.width
 | 
				
			||||||
 | 
						return code, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// readMSB returns the next code for "Most Significant Bits first" data.
 | 
				
			||||||
 | 
					func (d *decoder) readMSB() (uint16, error) {
 | 
				
			||||||
 | 
						for d.nBits < d.width {
 | 
				
			||||||
 | 
							x, err := d.r.ReadByte()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.bits |= uint32(x) << (24 - d.nBits)
 | 
				
			||||||
 | 
							d.nBits += 8
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						code := uint16(d.bits >> (32 - d.width))
 | 
				
			||||||
 | 
						d.bits <<= d.width
 | 
				
			||||||
 | 
						d.nBits -= d.width
 | 
				
			||||||
 | 
						return code, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *decoder) Read(b []byte) (int, error) {
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							if len(d.toRead) > 0 {
 | 
				
			||||||
 | 
								n := copy(b, d.toRead)
 | 
				
			||||||
 | 
								d.toRead = d.toRead[n:]
 | 
				
			||||||
 | 
								return n, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if d.err != nil {
 | 
				
			||||||
 | 
								return 0, d.err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.decode()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// decode decompresses bytes from r and leaves them in d.toRead.
 | 
				
			||||||
 | 
					// read specifies how to decode bytes into codes.
 | 
				
			||||||
 | 
					// litWidth is the width in bits of literal codes.
 | 
				
			||||||
 | 
					func (d *decoder) decode() {
 | 
				
			||||||
 | 
						// Loop over the code stream, converting codes into decompressed bytes.
 | 
				
			||||||
 | 
					loop:
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							code, err := d.read(d)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if err == io.EOF {
 | 
				
			||||||
 | 
									err = io.ErrUnexpectedEOF
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								d.err = err
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							switch {
 | 
				
			||||||
 | 
							case code < d.clear:
 | 
				
			||||||
 | 
								// We have a literal code.
 | 
				
			||||||
 | 
								d.output[d.o] = uint8(code)
 | 
				
			||||||
 | 
								d.o++
 | 
				
			||||||
 | 
								if d.last != decoderInvalidCode {
 | 
				
			||||||
 | 
									// Save what the hi code expands to.
 | 
				
			||||||
 | 
									d.suffix[d.hi] = uint8(code)
 | 
				
			||||||
 | 
									d.prefix[d.hi] = d.last
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case code == d.clear:
 | 
				
			||||||
 | 
								d.width = 1 + uint(d.litWidth)
 | 
				
			||||||
 | 
								d.hi = d.eof
 | 
				
			||||||
 | 
								d.overflow = 1 << d.width
 | 
				
			||||||
 | 
								d.last = decoderInvalidCode
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							case code == d.eof:
 | 
				
			||||||
 | 
								d.err = io.EOF
 | 
				
			||||||
 | 
								break loop
 | 
				
			||||||
 | 
							case code <= d.hi:
 | 
				
			||||||
 | 
								c, i := code, len(d.output)-1
 | 
				
			||||||
 | 
								if code == d.hi && d.last != decoderInvalidCode {
 | 
				
			||||||
 | 
									// code == hi is a special case which expands to the last expansion
 | 
				
			||||||
 | 
									// followed by the head of the last expansion. To find the head, we walk
 | 
				
			||||||
 | 
									// the prefix chain until we find a literal code.
 | 
				
			||||||
 | 
									c = d.last
 | 
				
			||||||
 | 
									for c >= d.clear {
 | 
				
			||||||
 | 
										c = d.prefix[c]
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									d.output[i] = uint8(c)
 | 
				
			||||||
 | 
									i--
 | 
				
			||||||
 | 
									c = d.last
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Copy the suffix chain into output and then write that to w.
 | 
				
			||||||
 | 
								for c >= d.clear {
 | 
				
			||||||
 | 
									d.output[i] = d.suffix[c]
 | 
				
			||||||
 | 
									i--
 | 
				
			||||||
 | 
									c = d.prefix[c]
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								d.output[i] = uint8(c)
 | 
				
			||||||
 | 
								d.o += copy(d.output[d.o:], d.output[i:])
 | 
				
			||||||
 | 
								if d.last != decoderInvalidCode {
 | 
				
			||||||
 | 
									// Save what the hi code expands to.
 | 
				
			||||||
 | 
									d.suffix[d.hi] = uint8(c)
 | 
				
			||||||
 | 
									d.prefix[d.hi] = d.last
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								d.err = errors.New("lzw: invalid code")
 | 
				
			||||||
 | 
								break loop
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.last, d.hi = code, d.hi+1
 | 
				
			||||||
 | 
							if d.hi+1 >= d.overflow { // NOTE: the "+1" is where TIFF's LZW differs from the standard algorithm.
 | 
				
			||||||
 | 
								if d.width == maxWidth {
 | 
				
			||||||
 | 
									d.last = decoderInvalidCode
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									d.width++
 | 
				
			||||||
 | 
									d.overflow <<= 1
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if d.o >= flushBuffer {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Flush pending output.
 | 
				
			||||||
 | 
						d.toRead = d.output[:d.o]
 | 
				
			||||||
 | 
						d.o = 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var errClosed = errors.New("lzw: reader/writer is closed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *decoder) Close() error {
 | 
				
			||||||
 | 
						d.err = errClosed // in case any Reads come along
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewReader creates a new io.ReadCloser.
 | 
				
			||||||
 | 
					// Reads from the returned io.ReadCloser read and decompress data from r.
 | 
				
			||||||
 | 
					// If r does not also implement io.ByteReader,
 | 
				
			||||||
 | 
					// the decompressor may read more data than necessary from r.
 | 
				
			||||||
 | 
					// It is the caller's responsibility to call Close on the ReadCloser when
 | 
				
			||||||
 | 
					// finished reading.
 | 
				
			||||||
 | 
					// The number of bits to use for literal codes, litWidth, must be in the
 | 
				
			||||||
 | 
					// range [2,8] and is typically 8. It must equal the litWidth
 | 
				
			||||||
 | 
					// used during compression.
 | 
				
			||||||
 | 
					func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
 | 
				
			||||||
 | 
						d := new(decoder)
 | 
				
			||||||
 | 
						switch order {
 | 
				
			||||||
 | 
						case LSB:
 | 
				
			||||||
 | 
							d.read = (*decoder).readLSB
 | 
				
			||||||
 | 
						case MSB:
 | 
				
			||||||
 | 
							d.read = (*decoder).readMSB
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							d.err = errors.New("lzw: unknown order")
 | 
				
			||||||
 | 
							return d
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if litWidth < 2 || 8 < litWidth {
 | 
				
			||||||
 | 
							d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
 | 
				
			||||||
 | 
							return d
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if br, ok := r.(io.ByteReader); ok {
 | 
				
			||||||
 | 
							d.r = br
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							d.r = bufio.NewReader(r)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						d.litWidth = litWidth
 | 
				
			||||||
 | 
						d.width = 1 + uint(litWidth)
 | 
				
			||||||
 | 
						d.clear = uint16(1) << uint(litWidth)
 | 
				
			||||||
 | 
						d.eof, d.hi = d.clear+1, d.clear+1
 | 
				
			||||||
 | 
						d.overflow = uint16(1) << d.width
 | 
				
			||||||
 | 
						d.last = decoderInvalidCode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return d
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										706
									
								
								vendor/golang.org/x/image/tiff/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										706
									
								
								vendor/golang.org/x/image/tiff/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,706 @@
 | 
				
			|||||||
 | 
					// Copyright 2011 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package tiff implements a TIFF image decoder and encoder.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
 | 
				
			||||||
 | 
					package tiff // import "golang.org/x/image/tiff"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"compress/zlib"
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"image/color"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"golang.org/x/image/ccitt"
 | 
				
			||||||
 | 
						"golang.org/x/image/tiff/lzw"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A FormatError reports that the input is not a valid TIFF image.
 | 
				
			||||||
 | 
					type FormatError string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (e FormatError) Error() string {
 | 
				
			||||||
 | 
						return "tiff: invalid format: " + string(e)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// An UnsupportedError reports that the input uses a valid but
 | 
				
			||||||
 | 
					// unimplemented feature.
 | 
				
			||||||
 | 
					type UnsupportedError string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (e UnsupportedError) Error() string {
 | 
				
			||||||
 | 
						return "tiff: unsupported feature: " + string(e)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var errNoPixels = FormatError("not enough pixel data")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type decoder struct {
 | 
				
			||||||
 | 
						r         io.ReaderAt
 | 
				
			||||||
 | 
						byteOrder binary.ByteOrder
 | 
				
			||||||
 | 
						config    image.Config
 | 
				
			||||||
 | 
						mode      imageMode
 | 
				
			||||||
 | 
						bpp       uint
 | 
				
			||||||
 | 
						features  map[int][]uint
 | 
				
			||||||
 | 
						palette   []color.Color
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf   []byte
 | 
				
			||||||
 | 
						off   int    // Current offset in buf.
 | 
				
			||||||
 | 
						v     uint32 // Buffer value for reading with arbitrary bit depths.
 | 
				
			||||||
 | 
						nbits uint   // Remaining number of bits in v.
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// firstVal returns the first uint of the features entry with the given tag,
 | 
				
			||||||
 | 
					// or 0 if the tag does not exist.
 | 
				
			||||||
 | 
					func (d *decoder) firstVal(tag int) uint {
 | 
				
			||||||
 | 
						f := d.features[tag]
 | 
				
			||||||
 | 
						if len(f) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return f[0]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
 | 
				
			||||||
 | 
					// or Long type, and returns the decoded uint values.
 | 
				
			||||||
 | 
					func (d *decoder) ifdUint(p []byte) (u []uint, err error) {
 | 
				
			||||||
 | 
						var raw []byte
 | 
				
			||||||
 | 
						if len(p) < ifdLen {
 | 
				
			||||||
 | 
							return nil, FormatError("bad IFD entry")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						datatype := d.byteOrder.Uint16(p[2:4])
 | 
				
			||||||
 | 
						if dt := int(datatype); dt <= 0 || dt >= len(lengths) {
 | 
				
			||||||
 | 
							return nil, UnsupportedError("IFD entry datatype")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						count := d.byteOrder.Uint32(p[4:8])
 | 
				
			||||||
 | 
						if count > math.MaxInt32/lengths[datatype] {
 | 
				
			||||||
 | 
							return nil, FormatError("IFD data too large")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if datalen := lengths[datatype] * count; datalen > 4 {
 | 
				
			||||||
 | 
							// The IFD contains a pointer to the real value.
 | 
				
			||||||
 | 
							raw = make([]byte, datalen)
 | 
				
			||||||
 | 
							_, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12])))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							raw = p[8 : 8+datalen]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u = make([]uint, count)
 | 
				
			||||||
 | 
						switch datatype {
 | 
				
			||||||
 | 
						case dtByte:
 | 
				
			||||||
 | 
							for i := uint32(0); i < count; i++ {
 | 
				
			||||||
 | 
								u[i] = uint(raw[i])
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case dtShort:
 | 
				
			||||||
 | 
							for i := uint32(0); i < count; i++ {
 | 
				
			||||||
 | 
								u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case dtLong:
 | 
				
			||||||
 | 
							for i := uint32(0); i < count; i++ {
 | 
				
			||||||
 | 
								u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return nil, UnsupportedError("data type")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return u, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// parseIFD decides whether the IFD entry in p is "interesting" and
 | 
				
			||||||
 | 
					// stows away the data in the decoder. It returns the tag number of the
 | 
				
			||||||
 | 
					// entry and an error, if any.
 | 
				
			||||||
 | 
					func (d *decoder) parseIFD(p []byte) (int, error) {
 | 
				
			||||||
 | 
						tag := d.byteOrder.Uint16(p[0:2])
 | 
				
			||||||
 | 
						switch tag {
 | 
				
			||||||
 | 
						case tBitsPerSample,
 | 
				
			||||||
 | 
							tExtraSamples,
 | 
				
			||||||
 | 
							tPhotometricInterpretation,
 | 
				
			||||||
 | 
							tCompression,
 | 
				
			||||||
 | 
							tPredictor,
 | 
				
			||||||
 | 
							tStripOffsets,
 | 
				
			||||||
 | 
							tStripByteCounts,
 | 
				
			||||||
 | 
							tRowsPerStrip,
 | 
				
			||||||
 | 
							tTileWidth,
 | 
				
			||||||
 | 
							tTileLength,
 | 
				
			||||||
 | 
							tTileOffsets,
 | 
				
			||||||
 | 
							tTileByteCounts,
 | 
				
			||||||
 | 
							tImageLength,
 | 
				
			||||||
 | 
							tImageWidth,
 | 
				
			||||||
 | 
							tFillOrder,
 | 
				
			||||||
 | 
							tT4Options,
 | 
				
			||||||
 | 
							tT6Options:
 | 
				
			||||||
 | 
							val, err := d.ifdUint(p)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.features[int(tag)] = val
 | 
				
			||||||
 | 
						case tColorMap:
 | 
				
			||||||
 | 
							val, err := d.ifdUint(p)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							numcolors := len(val) / 3
 | 
				
			||||||
 | 
							if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
 | 
				
			||||||
 | 
								return 0, FormatError("bad ColorMap length")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.palette = make([]color.Color, numcolors)
 | 
				
			||||||
 | 
							for i := 0; i < numcolors; i++ {
 | 
				
			||||||
 | 
								d.palette[i] = color.RGBA64{
 | 
				
			||||||
 | 
									uint16(val[i]),
 | 
				
			||||||
 | 
									uint16(val[i+numcolors]),
 | 
				
			||||||
 | 
									uint16(val[i+2*numcolors]),
 | 
				
			||||||
 | 
									0xffff,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case tSampleFormat:
 | 
				
			||||||
 | 
							// Page 27 of the spec: If the SampleFormat is present and
 | 
				
			||||||
 | 
							// the value is not 1 [= unsigned integer data], a Baseline
 | 
				
			||||||
 | 
							// TIFF reader that cannot handle the SampleFormat value
 | 
				
			||||||
 | 
							// must terminate the import process gracefully.
 | 
				
			||||||
 | 
							val, err := d.ifdUint(p)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return 0, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for _, v := range val {
 | 
				
			||||||
 | 
								if v != 1 {
 | 
				
			||||||
 | 
									return 0, UnsupportedError("sample format")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return int(tag), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// readBits reads n bits from the internal buffer starting at the current offset.
 | 
				
			||||||
 | 
					func (d *decoder) readBits(n uint) (v uint32, ok bool) {
 | 
				
			||||||
 | 
						for d.nbits < n {
 | 
				
			||||||
 | 
							d.v <<= 8
 | 
				
			||||||
 | 
							if d.off >= len(d.buf) {
 | 
				
			||||||
 | 
								return 0, false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							d.v |= uint32(d.buf[d.off])
 | 
				
			||||||
 | 
							d.off++
 | 
				
			||||||
 | 
							d.nbits += 8
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						d.nbits -= n
 | 
				
			||||||
 | 
						rv := d.v >> d.nbits
 | 
				
			||||||
 | 
						d.v &^= rv << d.nbits
 | 
				
			||||||
 | 
						return rv, true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// flushBits discards the unread bits in the buffer used by readBits.
 | 
				
			||||||
 | 
					// It is used at the end of a line.
 | 
				
			||||||
 | 
					func (d *decoder) flushBits() {
 | 
				
			||||||
 | 
						d.v = 0
 | 
				
			||||||
 | 
						d.nbits = 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// minInt returns the smaller of x or y.
 | 
				
			||||||
 | 
					func minInt(a, b int) int {
 | 
				
			||||||
 | 
						if a <= b {
 | 
				
			||||||
 | 
							return a
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return b
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// decode decodes the raw data of an image.
 | 
				
			||||||
 | 
					// It reads from d.buf and writes the strip or tile into dst.
 | 
				
			||||||
 | 
					func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
 | 
				
			||||||
 | 
						d.off = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Apply horizontal predictor if necessary.
 | 
				
			||||||
 | 
						// In this case, p contains the color difference to the preceding pixel.
 | 
				
			||||||
 | 
						// See page 64-65 of the spec.
 | 
				
			||||||
 | 
						if d.firstVal(tPredictor) == prHorizontal {
 | 
				
			||||||
 | 
							switch d.bpp {
 | 
				
			||||||
 | 
							case 16:
 | 
				
			||||||
 | 
								var off int
 | 
				
			||||||
 | 
								n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
 | 
				
			||||||
 | 
								for y := ymin; y < ymax; y++ {
 | 
				
			||||||
 | 
									off += n
 | 
				
			||||||
 | 
									for x := 0; x < (xmax-xmin-1)*n; x += 2 {
 | 
				
			||||||
 | 
										if off+2 > len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2])
 | 
				
			||||||
 | 
										v1 := d.byteOrder.Uint16(d.buf[off : off+2])
 | 
				
			||||||
 | 
										d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0)
 | 
				
			||||||
 | 
										off += 2
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case 8:
 | 
				
			||||||
 | 
								var off int
 | 
				
			||||||
 | 
								n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
 | 
				
			||||||
 | 
								for y := ymin; y < ymax; y++ {
 | 
				
			||||||
 | 
									off += n
 | 
				
			||||||
 | 
									for x := 0; x < (xmax-xmin-1)*n; x++ {
 | 
				
			||||||
 | 
										if off >= len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										d.buf[off] += d.buf[off-n]
 | 
				
			||||||
 | 
										off++
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
 | 
								return UnsupportedError("horizontal predictor with 1 BitsPerSample")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rMaxX := minInt(xmax, dst.Bounds().Max.X)
 | 
				
			||||||
 | 
						rMaxY := minInt(ymax, dst.Bounds().Max.Y)
 | 
				
			||||||
 | 
						switch d.mode {
 | 
				
			||||||
 | 
						case mGray, mGrayInvert:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img := dst.(*image.Gray16)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									for x := xmin; x < rMaxX; x++ {
 | 
				
			||||||
 | 
										if d.off+2 > len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										v := d.byteOrder.Uint16(d.buf[d.off : d.off+2])
 | 
				
			||||||
 | 
										d.off += 2
 | 
				
			||||||
 | 
										if d.mode == mGrayInvert {
 | 
				
			||||||
 | 
											v = 0xffff - v
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										img.SetGray16(x, y, color.Gray16{v})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if rMaxX == img.Bounds().Max.X {
 | 
				
			||||||
 | 
										d.off += 2 * (xmax - img.Bounds().Max.X)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img := dst.(*image.Gray)
 | 
				
			||||||
 | 
								max := uint32((1 << d.bpp) - 1)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									for x := xmin; x < rMaxX; x++ {
 | 
				
			||||||
 | 
										v, ok := d.readBits(d.bpp)
 | 
				
			||||||
 | 
										if !ok {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										v = v * 0xff / max
 | 
				
			||||||
 | 
										if d.mode == mGrayInvert {
 | 
				
			||||||
 | 
											v = 0xff - v
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										img.SetGray(x, y, color.Gray{uint8(v)})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									d.flushBits()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case mPaletted:
 | 
				
			||||||
 | 
							img := dst.(*image.Paletted)
 | 
				
			||||||
 | 
							for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
								for x := xmin; x < rMaxX; x++ {
 | 
				
			||||||
 | 
									v, ok := d.readBits(d.bpp)
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										return errNoPixels
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									img.SetColorIndex(x, y, uint8(v))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								d.flushBits()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case mRGB:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img := dst.(*image.RGBA64)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									for x := xmin; x < rMaxX; x++ {
 | 
				
			||||||
 | 
										if d.off+6 > len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
 | 
				
			||||||
 | 
										g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
 | 
				
			||||||
 | 
										b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
 | 
				
			||||||
 | 
										d.off += 6
 | 
				
			||||||
 | 
										img.SetRGBA64(x, y, color.RGBA64{r, g, b, 0xffff})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img := dst.(*image.RGBA)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									min := img.PixOffset(xmin, y)
 | 
				
			||||||
 | 
									max := img.PixOffset(rMaxX, y)
 | 
				
			||||||
 | 
									off := (y - ymin) * (xmax - xmin) * 3
 | 
				
			||||||
 | 
									for i := min; i < max; i += 4 {
 | 
				
			||||||
 | 
										if off+3 > len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										img.Pix[i+0] = d.buf[off+0]
 | 
				
			||||||
 | 
										img.Pix[i+1] = d.buf[off+1]
 | 
				
			||||||
 | 
										img.Pix[i+2] = d.buf[off+2]
 | 
				
			||||||
 | 
										img.Pix[i+3] = 0xff
 | 
				
			||||||
 | 
										off += 3
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case mNRGBA:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img := dst.(*image.NRGBA64)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									for x := xmin; x < rMaxX; x++ {
 | 
				
			||||||
 | 
										if d.off+8 > len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
 | 
				
			||||||
 | 
										g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
 | 
				
			||||||
 | 
										b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
 | 
				
			||||||
 | 
										a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
 | 
				
			||||||
 | 
										d.off += 8
 | 
				
			||||||
 | 
										img.SetNRGBA64(x, y, color.NRGBA64{r, g, b, a})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img := dst.(*image.NRGBA)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									min := img.PixOffset(xmin, y)
 | 
				
			||||||
 | 
									max := img.PixOffset(rMaxX, y)
 | 
				
			||||||
 | 
									i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
 | 
				
			||||||
 | 
									if i1 > len(d.buf) {
 | 
				
			||||||
 | 
										return errNoPixels
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									copy(img.Pix[min:max], d.buf[i0:i1])
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case mRGBA:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img := dst.(*image.RGBA64)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									for x := xmin; x < rMaxX; x++ {
 | 
				
			||||||
 | 
										if d.off+8 > len(d.buf) {
 | 
				
			||||||
 | 
											return errNoPixels
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
 | 
				
			||||||
 | 
										g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
 | 
				
			||||||
 | 
										b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
 | 
				
			||||||
 | 
										a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
 | 
				
			||||||
 | 
										d.off += 8
 | 
				
			||||||
 | 
										img.SetRGBA64(x, y, color.RGBA64{r, g, b, a})
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img := dst.(*image.RGBA)
 | 
				
			||||||
 | 
								for y := ymin; y < rMaxY; y++ {
 | 
				
			||||||
 | 
									min := img.PixOffset(xmin, y)
 | 
				
			||||||
 | 
									max := img.PixOffset(rMaxX, y)
 | 
				
			||||||
 | 
									i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
 | 
				
			||||||
 | 
									if i1 > len(d.buf) {
 | 
				
			||||||
 | 
										return errNoPixels
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									copy(img.Pix[min:max], d.buf[i0:i1])
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newDecoder(r io.Reader) (*decoder, error) {
 | 
				
			||||||
 | 
						d := &decoder{
 | 
				
			||||||
 | 
							r:        newReaderAt(r),
 | 
				
			||||||
 | 
							features: make(map[int][]uint),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p := make([]byte, 8)
 | 
				
			||||||
 | 
						if _, err := d.r.ReadAt(p, 0); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch string(p[0:4]) {
 | 
				
			||||||
 | 
						case leHeader:
 | 
				
			||||||
 | 
							d.byteOrder = binary.LittleEndian
 | 
				
			||||||
 | 
						case beHeader:
 | 
				
			||||||
 | 
							d.byteOrder = binary.BigEndian
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return nil, FormatError("malformed header")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The first two bytes contain the number of entries (12 bytes each).
 | 
				
			||||||
 | 
						if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						numItems := int(d.byteOrder.Uint16(p[0:2]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// All IFD entries are read in one chunk.
 | 
				
			||||||
 | 
						p = make([]byte, ifdLen*numItems)
 | 
				
			||||||
 | 
						if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prevTag := -1
 | 
				
			||||||
 | 
						for i := 0; i < len(p); i += ifdLen {
 | 
				
			||||||
 | 
							tag, err := d.parseIFD(p[i : i+ifdLen])
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if tag <= prevTag {
 | 
				
			||||||
 | 
								return nil, FormatError("tags are not sorted in ascending order")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							prevTag = tag
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d.config.Width = int(d.firstVal(tImageWidth))
 | 
				
			||||||
 | 
						d.config.Height = int(d.firstVal(tImageLength))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, ok := d.features[tBitsPerSample]; !ok {
 | 
				
			||||||
 | 
							// Default is 1 per specification.
 | 
				
			||||||
 | 
							d.features[tBitsPerSample] = []uint{1}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						d.bpp = d.firstVal(tBitsPerSample)
 | 
				
			||||||
 | 
						switch d.bpp {
 | 
				
			||||||
 | 
						case 0:
 | 
				
			||||||
 | 
							return nil, FormatError("BitsPerSample must not be 0")
 | 
				
			||||||
 | 
						case 1, 8, 16:
 | 
				
			||||||
 | 
							// Nothing to do, these are accepted by this implementation.
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Determine the image mode.
 | 
				
			||||||
 | 
						switch d.firstVal(tPhotometricInterpretation) {
 | 
				
			||||||
 | 
						case pRGB:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								for _, b := range d.features[tBitsPerSample] {
 | 
				
			||||||
 | 
									if b != 16 {
 | 
				
			||||||
 | 
										return nil, FormatError("wrong number of samples for 16bit RGB")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								for _, b := range d.features[tBitsPerSample] {
 | 
				
			||||||
 | 
									if b != 8 {
 | 
				
			||||||
 | 
										return nil, FormatError("wrong number of samples for 8bit RGB")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// RGB images normally have 3 samples per pixel.
 | 
				
			||||||
 | 
							// If there are more, ExtraSamples (p. 31-32 of the spec)
 | 
				
			||||||
 | 
							// gives their meaning (usually an alpha channel).
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							// This implementation does not support extra samples
 | 
				
			||||||
 | 
							// of an unspecified type.
 | 
				
			||||||
 | 
							switch len(d.features[tBitsPerSample]) {
 | 
				
			||||||
 | 
							case 3:
 | 
				
			||||||
 | 
								d.mode = mRGB
 | 
				
			||||||
 | 
								if d.bpp == 16 {
 | 
				
			||||||
 | 
									d.config.ColorModel = color.RGBA64Model
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									d.config.ColorModel = color.RGBAModel
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							case 4:
 | 
				
			||||||
 | 
								switch d.firstVal(tExtraSamples) {
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									d.mode = mRGBA
 | 
				
			||||||
 | 
									if d.bpp == 16 {
 | 
				
			||||||
 | 
										d.config.ColorModel = color.RGBA64Model
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										d.config.ColorModel = color.RGBAModel
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case 2:
 | 
				
			||||||
 | 
									d.mode = mNRGBA
 | 
				
			||||||
 | 
									if d.bpp == 16 {
 | 
				
			||||||
 | 
										d.config.ColorModel = color.NRGBA64Model
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										d.config.ColorModel = color.NRGBAModel
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return nil, FormatError("wrong number of samples for RGB")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return nil, FormatError("wrong number of samples for RGB")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case pPaletted:
 | 
				
			||||||
 | 
							d.mode = mPaletted
 | 
				
			||||||
 | 
							d.config.ColorModel = color.Palette(d.palette)
 | 
				
			||||||
 | 
						case pWhiteIsZero:
 | 
				
			||||||
 | 
							d.mode = mGrayInvert
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								d.config.ColorModel = color.Gray16Model
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								d.config.ColorModel = color.GrayModel
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case pBlackIsZero:
 | 
				
			||||||
 | 
							d.mode = mGray
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								d.config.ColorModel = color.Gray16Model
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								d.config.ColorModel = color.GrayModel
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return nil, UnsupportedError("color model")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return d, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeConfig returns the color model and dimensions of a TIFF image without
 | 
				
			||||||
 | 
					// decoding the entire image.
 | 
				
			||||||
 | 
					func DecodeConfig(r io.Reader) (image.Config, error) {
 | 
				
			||||||
 | 
						d, err := newDecoder(r)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return image.Config{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return d.config, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ccittFillOrder(tiffFillOrder uint) ccitt.Order {
 | 
				
			||||||
 | 
						if tiffFillOrder == 2 {
 | 
				
			||||||
 | 
							return ccitt.LSB
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ccitt.MSB
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decode reads a TIFF image from r and returns it as an image.Image.
 | 
				
			||||||
 | 
					// The type of Image returned depends on the contents of the TIFF.
 | 
				
			||||||
 | 
					func Decode(r io.Reader) (img image.Image, err error) {
 | 
				
			||||||
 | 
						d, err := newDecoder(r)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						blockPadding := false
 | 
				
			||||||
 | 
						blockWidth := d.config.Width
 | 
				
			||||||
 | 
						blockHeight := d.config.Height
 | 
				
			||||||
 | 
						blocksAcross := 1
 | 
				
			||||||
 | 
						blocksDown := 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if d.config.Width == 0 {
 | 
				
			||||||
 | 
							blocksAcross = 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if d.config.Height == 0 {
 | 
				
			||||||
 | 
							blocksDown = 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var blockOffsets, blockCounts []uint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if int(d.firstVal(tTileWidth)) != 0 {
 | 
				
			||||||
 | 
							blockPadding = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							blockWidth = int(d.firstVal(tTileWidth))
 | 
				
			||||||
 | 
							blockHeight = int(d.firstVal(tTileLength))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if blockWidth != 0 {
 | 
				
			||||||
 | 
								blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if blockHeight != 0 {
 | 
				
			||||||
 | 
								blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							blockCounts = d.features[tTileByteCounts]
 | 
				
			||||||
 | 
							blockOffsets = d.features[tTileOffsets]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if int(d.firstVal(tRowsPerStrip)) != 0 {
 | 
				
			||||||
 | 
								blockHeight = int(d.firstVal(tRowsPerStrip))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if blockHeight != 0 {
 | 
				
			||||||
 | 
								blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							blockOffsets = d.features[tStripOffsets]
 | 
				
			||||||
 | 
							blockCounts = d.features[tStripByteCounts]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check if we have the right number of strips/tiles, offsets and counts.
 | 
				
			||||||
 | 
						if n := blocksAcross * blocksDown; len(blockOffsets) < n || len(blockCounts) < n {
 | 
				
			||||||
 | 
							return nil, FormatError("inconsistent header")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imgRect := image.Rect(0, 0, d.config.Width, d.config.Height)
 | 
				
			||||||
 | 
						switch d.mode {
 | 
				
			||||||
 | 
						case mGray, mGrayInvert:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img = image.NewGray16(imgRect)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img = image.NewGray(imgRect)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case mPaletted:
 | 
				
			||||||
 | 
							img = image.NewPaletted(imgRect, d.palette)
 | 
				
			||||||
 | 
						case mNRGBA:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img = image.NewNRGBA64(imgRect)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img = image.NewNRGBA(imgRect)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case mRGB, mRGBA:
 | 
				
			||||||
 | 
							if d.bpp == 16 {
 | 
				
			||||||
 | 
								img = image.NewRGBA64(imgRect)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								img = image.NewRGBA(imgRect)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < blocksAcross; i++ {
 | 
				
			||||||
 | 
							blkW := blockWidth
 | 
				
			||||||
 | 
							if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 {
 | 
				
			||||||
 | 
								blkW = d.config.Width % blockWidth
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for j := 0; j < blocksDown; j++ {
 | 
				
			||||||
 | 
								blkH := blockHeight
 | 
				
			||||||
 | 
								if !blockPadding && j == blocksDown-1 && d.config.Height%blockHeight != 0 {
 | 
				
			||||||
 | 
									blkH = d.config.Height % blockHeight
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								offset := int64(blockOffsets[j*blocksAcross+i])
 | 
				
			||||||
 | 
								n := int64(blockCounts[j*blocksAcross+i])
 | 
				
			||||||
 | 
								switch d.firstVal(tCompression) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// According to the spec, Compression does not have a default value,
 | 
				
			||||||
 | 
								// but some tools interpret a missing Compression value as none so we do
 | 
				
			||||||
 | 
								// the same.
 | 
				
			||||||
 | 
								case cNone, 0:
 | 
				
			||||||
 | 
									if b, ok := d.r.(*buffer); ok {
 | 
				
			||||||
 | 
										d.buf, err = b.Slice(int(offset), int(n))
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										d.buf = make([]byte, n)
 | 
				
			||||||
 | 
										_, err = d.r.ReadAt(d.buf, offset)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case cG3:
 | 
				
			||||||
 | 
									inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
 | 
				
			||||||
 | 
									order := ccittFillOrder(d.firstVal(tFillOrder))
 | 
				
			||||||
 | 
									r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group3, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
 | 
				
			||||||
 | 
									d.buf, err = ioutil.ReadAll(r)
 | 
				
			||||||
 | 
								case cG4:
 | 
				
			||||||
 | 
									inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
 | 
				
			||||||
 | 
									order := ccittFillOrder(d.firstVal(tFillOrder))
 | 
				
			||||||
 | 
									r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group4, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
 | 
				
			||||||
 | 
									d.buf, err = ioutil.ReadAll(r)
 | 
				
			||||||
 | 
								case cLZW:
 | 
				
			||||||
 | 
									r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
 | 
				
			||||||
 | 
									d.buf, err = ioutil.ReadAll(r)
 | 
				
			||||||
 | 
									r.Close()
 | 
				
			||||||
 | 
								case cDeflate, cDeflateOld:
 | 
				
			||||||
 | 
									var r io.ReadCloser
 | 
				
			||||||
 | 
									r, err = zlib.NewReader(io.NewSectionReader(d.r, offset, n))
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return nil, err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									d.buf, err = ioutil.ReadAll(r)
 | 
				
			||||||
 | 
									r.Close()
 | 
				
			||||||
 | 
								case cPackBits:
 | 
				
			||||||
 | 
									d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n))
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									err = UnsupportedError(fmt.Sprintf("compression value %d", d.firstVal(tCompression)))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								xmin := i * blockWidth
 | 
				
			||||||
 | 
								ymin := j * blockHeight
 | 
				
			||||||
 | 
								xmax := xmin + blkW
 | 
				
			||||||
 | 
								ymax := ymin + blkH
 | 
				
			||||||
 | 
								err = d.decode(img, xmin, ymin, xmax, ymax)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
 | 
				
			||||||
 | 
						image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										438
									
								
								vendor/golang.org/x/image/tiff/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										438
									
								
								vendor/golang.org/x/image/tiff/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,438 @@
 | 
				
			|||||||
 | 
					// Copyright 2012 The Go Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a BSD-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package tiff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"compress/zlib"
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"image"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The TIFF format allows to choose the order of the different elements freely.
 | 
				
			||||||
 | 
					// The basic structure of a TIFF file written by this package is:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//   1. Header (8 bytes).
 | 
				
			||||||
 | 
					//   2. Image data.
 | 
				
			||||||
 | 
					//   3. Image File Directory (IFD).
 | 
				
			||||||
 | 
					//   4. "Pointer area" for larger entries in the IFD.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// We only write little-endian TIFF files.
 | 
				
			||||||
 | 
					var enc = binary.LittleEndian
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// An ifdEntry is a single entry in an Image File Directory.
 | 
				
			||||||
 | 
					// A value of type dtRational is composed of two 32-bit values,
 | 
				
			||||||
 | 
					// thus data contains two uints (numerator and denominator) for a single number.
 | 
				
			||||||
 | 
					type ifdEntry struct {
 | 
				
			||||||
 | 
						tag      int
 | 
				
			||||||
 | 
						datatype int
 | 
				
			||||||
 | 
						data     []uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (e ifdEntry) putData(p []byte) {
 | 
				
			||||||
 | 
						for _, d := range e.data {
 | 
				
			||||||
 | 
							switch e.datatype {
 | 
				
			||||||
 | 
							case dtByte, dtASCII:
 | 
				
			||||||
 | 
								p[0] = byte(d)
 | 
				
			||||||
 | 
								p = p[1:]
 | 
				
			||||||
 | 
							case dtShort:
 | 
				
			||||||
 | 
								enc.PutUint16(p, uint16(d))
 | 
				
			||||||
 | 
								p = p[2:]
 | 
				
			||||||
 | 
							case dtLong, dtRational:
 | 
				
			||||||
 | 
								enc.PutUint32(p, uint32(d))
 | 
				
			||||||
 | 
								p = p[4:]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type byTag []ifdEntry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d byTag) Len() int           { return len(d) }
 | 
				
			||||||
 | 
					func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag }
 | 
				
			||||||
 | 
					func (d byTag) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
				
			||||||
 | 
						if !predictor {
 | 
				
			||||||
 | 
							return writePix(w, pix, dy, dx, stride)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf := make([]byte, dx)
 | 
				
			||||||
 | 
						for y := 0; y < dy; y++ {
 | 
				
			||||||
 | 
							min := y*stride + 0
 | 
				
			||||||
 | 
							max := y*stride + dx
 | 
				
			||||||
 | 
							off := 0
 | 
				
			||||||
 | 
							var v0 uint8
 | 
				
			||||||
 | 
							for i := min; i < max; i++ {
 | 
				
			||||||
 | 
								v1 := pix[i]
 | 
				
			||||||
 | 
								buf[off] = v1 - v0
 | 
				
			||||||
 | 
								v0 = v1
 | 
				
			||||||
 | 
								off++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
				
			||||||
 | 
						buf := make([]byte, dx*2)
 | 
				
			||||||
 | 
						for y := 0; y < dy; y++ {
 | 
				
			||||||
 | 
							min := y*stride + 0
 | 
				
			||||||
 | 
							max := y*stride + dx*2
 | 
				
			||||||
 | 
							off := 0
 | 
				
			||||||
 | 
							var v0 uint16
 | 
				
			||||||
 | 
							for i := min; i < max; i += 2 {
 | 
				
			||||||
 | 
								// An image.Gray16's Pix is in big-endian order.
 | 
				
			||||||
 | 
								v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
 | 
				
			||||||
 | 
								if predictor {
 | 
				
			||||||
 | 
									v0, v1 = v1, v1-v0
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// We only write little-endian TIFF files.
 | 
				
			||||||
 | 
								buf[off+0] = byte(v1)
 | 
				
			||||||
 | 
								buf[off+1] = byte(v1 >> 8)
 | 
				
			||||||
 | 
								off += 2
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
				
			||||||
 | 
						if !predictor {
 | 
				
			||||||
 | 
							return writePix(w, pix, dy, dx*4, stride)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf := make([]byte, dx*4)
 | 
				
			||||||
 | 
						for y := 0; y < dy; y++ {
 | 
				
			||||||
 | 
							min := y*stride + 0
 | 
				
			||||||
 | 
							max := y*stride + dx*4
 | 
				
			||||||
 | 
							off := 0
 | 
				
			||||||
 | 
							var r0, g0, b0, a0 uint8
 | 
				
			||||||
 | 
							for i := min; i < max; i += 4 {
 | 
				
			||||||
 | 
								r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3]
 | 
				
			||||||
 | 
								buf[off+0] = r1 - r0
 | 
				
			||||||
 | 
								buf[off+1] = g1 - g0
 | 
				
			||||||
 | 
								buf[off+2] = b1 - b0
 | 
				
			||||||
 | 
								buf[off+3] = a1 - a0
 | 
				
			||||||
 | 
								off += 4
 | 
				
			||||||
 | 
								r0, g0, b0, a0 = r1, g1, b1, a1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
 | 
				
			||||||
 | 
						buf := make([]byte, dx*8)
 | 
				
			||||||
 | 
						for y := 0; y < dy; y++ {
 | 
				
			||||||
 | 
							min := y*stride + 0
 | 
				
			||||||
 | 
							max := y*stride + dx*8
 | 
				
			||||||
 | 
							off := 0
 | 
				
			||||||
 | 
							var r0, g0, b0, a0 uint16
 | 
				
			||||||
 | 
							for i := min; i < max; i += 8 {
 | 
				
			||||||
 | 
								// An image.RGBA64's Pix is in big-endian order.
 | 
				
			||||||
 | 
								r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1])
 | 
				
			||||||
 | 
								g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3])
 | 
				
			||||||
 | 
								b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5])
 | 
				
			||||||
 | 
								a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7])
 | 
				
			||||||
 | 
								if predictor {
 | 
				
			||||||
 | 
									r0, r1 = r1, r1-r0
 | 
				
			||||||
 | 
									g0, g1 = g1, g1-g0
 | 
				
			||||||
 | 
									b0, b1 = b1, b1-b0
 | 
				
			||||||
 | 
									a0, a1 = a1, a1-a0
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// We only write little-endian TIFF files.
 | 
				
			||||||
 | 
								buf[off+0] = byte(r1)
 | 
				
			||||||
 | 
								buf[off+1] = byte(r1 >> 8)
 | 
				
			||||||
 | 
								buf[off+2] = byte(g1)
 | 
				
			||||||
 | 
								buf[off+3] = byte(g1 >> 8)
 | 
				
			||||||
 | 
								buf[off+4] = byte(b1)
 | 
				
			||||||
 | 
								buf[off+5] = byte(b1 >> 8)
 | 
				
			||||||
 | 
								buf[off+6] = byte(a1)
 | 
				
			||||||
 | 
								buf[off+7] = byte(a1 >> 8)
 | 
				
			||||||
 | 
								off += 8
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encode(w io.Writer, m image.Image, predictor bool) error {
 | 
				
			||||||
 | 
						bounds := m.Bounds()
 | 
				
			||||||
 | 
						buf := make([]byte, 4*bounds.Dx())
 | 
				
			||||||
 | 
						for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
 | 
				
			||||||
 | 
							off := 0
 | 
				
			||||||
 | 
							if predictor {
 | 
				
			||||||
 | 
								var r0, g0, b0, a0 uint8
 | 
				
			||||||
 | 
								for x := bounds.Min.X; x < bounds.Max.X; x++ {
 | 
				
			||||||
 | 
									r, g, b, a := m.At(x, y).RGBA()
 | 
				
			||||||
 | 
									r1 := uint8(r >> 8)
 | 
				
			||||||
 | 
									g1 := uint8(g >> 8)
 | 
				
			||||||
 | 
									b1 := uint8(b >> 8)
 | 
				
			||||||
 | 
									a1 := uint8(a >> 8)
 | 
				
			||||||
 | 
									buf[off+0] = r1 - r0
 | 
				
			||||||
 | 
									buf[off+1] = g1 - g0
 | 
				
			||||||
 | 
									buf[off+2] = b1 - b0
 | 
				
			||||||
 | 
									buf[off+3] = a1 - a0
 | 
				
			||||||
 | 
									off += 4
 | 
				
			||||||
 | 
									r0, g0, b0, a0 = r1, g1, b1, a1
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								for x := bounds.Min.X; x < bounds.Max.X; x++ {
 | 
				
			||||||
 | 
									r, g, b, a := m.At(x, y).RGBA()
 | 
				
			||||||
 | 
									buf[off+0] = uint8(r >> 8)
 | 
				
			||||||
 | 
									buf[off+1] = uint8(g >> 8)
 | 
				
			||||||
 | 
									buf[off+2] = uint8(b >> 8)
 | 
				
			||||||
 | 
									buf[off+3] = uint8(a >> 8)
 | 
				
			||||||
 | 
									off += 4
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// writePix writes the internal byte array of an image to w. It is less general
 | 
				
			||||||
 | 
					// but much faster then encode. writePix is used when pix directly
 | 
				
			||||||
 | 
					// corresponds to one of the TIFF image types.
 | 
				
			||||||
 | 
					func writePix(w io.Writer, pix []byte, nrows, length, stride int) error {
 | 
				
			||||||
 | 
						if length == stride {
 | 
				
			||||||
 | 
							_, err := w.Write(pix[:nrows*length])
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for ; nrows > 0; nrows-- {
 | 
				
			||||||
 | 
							if _, err := w.Write(pix[:length]); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pix = pix[stride:]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error {
 | 
				
			||||||
 | 
						var buf [ifdLen]byte
 | 
				
			||||||
 | 
						// Make space for "pointer area" containing IFD entry data
 | 
				
			||||||
 | 
						// longer than 4 bytes.
 | 
				
			||||||
 | 
						parea := make([]byte, 1024)
 | 
				
			||||||
 | 
						pstart := ifdOffset + ifdLen*len(d) + 6
 | 
				
			||||||
 | 
						var o int // Current offset in parea.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The IFD has to be written with the tags in ascending order.
 | 
				
			||||||
 | 
						sort.Sort(byTag(d))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Write the number of entries in this IFD.
 | 
				
			||||||
 | 
						if err := binary.Write(w, enc, uint16(len(d))); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, ent := range d {
 | 
				
			||||||
 | 
							enc.PutUint16(buf[0:2], uint16(ent.tag))
 | 
				
			||||||
 | 
							enc.PutUint16(buf[2:4], uint16(ent.datatype))
 | 
				
			||||||
 | 
							count := uint32(len(ent.data))
 | 
				
			||||||
 | 
							if ent.datatype == dtRational {
 | 
				
			||||||
 | 
								count /= 2
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							enc.PutUint32(buf[4:8], count)
 | 
				
			||||||
 | 
							datalen := int(count * lengths[ent.datatype])
 | 
				
			||||||
 | 
							if datalen <= 4 {
 | 
				
			||||||
 | 
								ent.putData(buf[8:12])
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (o + datalen) > len(parea) {
 | 
				
			||||||
 | 
									newlen := len(parea) + 1024
 | 
				
			||||||
 | 
									for (o + datalen) > newlen {
 | 
				
			||||||
 | 
										newlen += 1024
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									newarea := make([]byte, newlen)
 | 
				
			||||||
 | 
									copy(newarea, parea)
 | 
				
			||||||
 | 
									parea = newarea
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								ent.putData(parea[o : o+datalen])
 | 
				
			||||||
 | 
								enc.PutUint32(buf[8:12], uint32(pstart+o))
 | 
				
			||||||
 | 
								o += datalen
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err := w.Write(buf[:]); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// The IFD ends with the offset of the next IFD in the file,
 | 
				
			||||||
 | 
						// or zero if it is the last one (page 14).
 | 
				
			||||||
 | 
						if err := binary.Write(w, enc, uint32(0)); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := w.Write(parea[:o])
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Options are the encoding parameters.
 | 
				
			||||||
 | 
					type Options struct {
 | 
				
			||||||
 | 
						// Compression is the type of compression used.
 | 
				
			||||||
 | 
						Compression CompressionType
 | 
				
			||||||
 | 
						// Predictor determines whether a differencing predictor is used;
 | 
				
			||||||
 | 
						// if true, instead of each pixel's color, the color difference to the
 | 
				
			||||||
 | 
						// preceding one is saved.  This improves the compression for certain
 | 
				
			||||||
 | 
						// types of images and compressors. For example, it works well for
 | 
				
			||||||
 | 
						// photos with Deflate compression.
 | 
				
			||||||
 | 
						Predictor bool
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Encode writes the image m to w. opt determines the options used for
 | 
				
			||||||
 | 
					// encoding, such as the compression type. If opt is nil, an uncompressed
 | 
				
			||||||
 | 
					// image is written.
 | 
				
			||||||
 | 
					func Encode(w io.Writer, m image.Image, opt *Options) error {
 | 
				
			||||||
 | 
						d := m.Bounds().Size()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						compression := uint32(cNone)
 | 
				
			||||||
 | 
						predictor := false
 | 
				
			||||||
 | 
						if opt != nil {
 | 
				
			||||||
 | 
							compression = opt.Compression.specValue()
 | 
				
			||||||
 | 
							// The predictor field is only used with LZW. See page 64 of the spec.
 | 
				
			||||||
 | 
							predictor = opt.Predictor && compression == cLZW
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := io.WriteString(w, leHeader)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Compressed data is written into a buffer first, so that we
 | 
				
			||||||
 | 
						// know the compressed size.
 | 
				
			||||||
 | 
						var buf bytes.Buffer
 | 
				
			||||||
 | 
						// dst holds the destination for the pixel data of the image --
 | 
				
			||||||
 | 
						// either w or a writer to buf.
 | 
				
			||||||
 | 
						var dst io.Writer
 | 
				
			||||||
 | 
						// imageLen is the length of the pixel data in bytes.
 | 
				
			||||||
 | 
						// The offset of the IFD is imageLen + 8 header bytes.
 | 
				
			||||||
 | 
						var imageLen int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch compression {
 | 
				
			||||||
 | 
						case cNone:
 | 
				
			||||||
 | 
							dst = w
 | 
				
			||||||
 | 
							// Write IFD offset before outputting pixel data.
 | 
				
			||||||
 | 
							switch m.(type) {
 | 
				
			||||||
 | 
							case *image.Paletted:
 | 
				
			||||||
 | 
								imageLen = d.X * d.Y * 1
 | 
				
			||||||
 | 
							case *image.Gray:
 | 
				
			||||||
 | 
								imageLen = d.X * d.Y * 1
 | 
				
			||||||
 | 
							case *image.Gray16:
 | 
				
			||||||
 | 
								imageLen = d.X * d.Y * 2
 | 
				
			||||||
 | 
							case *image.RGBA64:
 | 
				
			||||||
 | 
								imageLen = d.X * d.Y * 8
 | 
				
			||||||
 | 
							case *image.NRGBA64:
 | 
				
			||||||
 | 
								imageLen = d.X * d.Y * 8
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								imageLen = d.X * d.Y * 4
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = binary.Write(w, enc, uint32(imageLen+8))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case cDeflate:
 | 
				
			||||||
 | 
							dst = zlib.NewWriter(&buf)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pr := uint32(prNone)
 | 
				
			||||||
 | 
						photometricInterpretation := uint32(pRGB)
 | 
				
			||||||
 | 
						samplesPerPixel := uint32(4)
 | 
				
			||||||
 | 
						bitsPerSample := []uint32{8, 8, 8, 8}
 | 
				
			||||||
 | 
						extraSamples := uint32(0)
 | 
				
			||||||
 | 
						colorMap := []uint32{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if predictor {
 | 
				
			||||||
 | 
							pr = prHorizontal
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch m := m.(type) {
 | 
				
			||||||
 | 
						case *image.Paletted:
 | 
				
			||||||
 | 
							photometricInterpretation = pPaletted
 | 
				
			||||||
 | 
							samplesPerPixel = 1
 | 
				
			||||||
 | 
							bitsPerSample = []uint32{8}
 | 
				
			||||||
 | 
							colorMap = make([]uint32, 256*3)
 | 
				
			||||||
 | 
							for i := 0; i < 256 && i < len(m.Palette); i++ {
 | 
				
			||||||
 | 
								r, g, b, _ := m.Palette[i].RGBA()
 | 
				
			||||||
 | 
								colorMap[i+0*256] = uint32(r)
 | 
				
			||||||
 | 
								colorMap[i+1*256] = uint32(g)
 | 
				
			||||||
 | 
								colorMap[i+2*256] = uint32(b)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						case *image.Gray:
 | 
				
			||||||
 | 
							photometricInterpretation = pBlackIsZero
 | 
				
			||||||
 | 
							samplesPerPixel = 1
 | 
				
			||||||
 | 
							bitsPerSample = []uint32{8}
 | 
				
			||||||
 | 
							err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						case *image.Gray16:
 | 
				
			||||||
 | 
							photometricInterpretation = pBlackIsZero
 | 
				
			||||||
 | 
							samplesPerPixel = 1
 | 
				
			||||||
 | 
							bitsPerSample = []uint32{16}
 | 
				
			||||||
 | 
							err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						case *image.NRGBA:
 | 
				
			||||||
 | 
							extraSamples = 2 // Unassociated alpha.
 | 
				
			||||||
 | 
							err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						case *image.NRGBA64:
 | 
				
			||||||
 | 
							extraSamples = 2 // Unassociated alpha.
 | 
				
			||||||
 | 
							bitsPerSample = []uint32{16, 16, 16, 16}
 | 
				
			||||||
 | 
							err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						case *image.RGBA:
 | 
				
			||||||
 | 
							extraSamples = 1 // Associated alpha.
 | 
				
			||||||
 | 
							err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						case *image.RGBA64:
 | 
				
			||||||
 | 
							extraSamples = 1 // Associated alpha.
 | 
				
			||||||
 | 
							bitsPerSample = []uint32{16, 16, 16, 16}
 | 
				
			||||||
 | 
							err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							extraSamples = 1 // Associated alpha.
 | 
				
			||||||
 | 
							err = encode(dst, m, predictor)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if compression != cNone {
 | 
				
			||||||
 | 
							if err = dst.(io.Closer).Close(); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							imageLen = buf.Len()
 | 
				
			||||||
 | 
							if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if _, err = buf.WriteTo(w); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ifd := []ifdEntry{
 | 
				
			||||||
 | 
							{tImageWidth, dtShort, []uint32{uint32(d.X)}},
 | 
				
			||||||
 | 
							{tImageLength, dtShort, []uint32{uint32(d.Y)}},
 | 
				
			||||||
 | 
							{tBitsPerSample, dtShort, bitsPerSample},
 | 
				
			||||||
 | 
							{tCompression, dtShort, []uint32{compression}},
 | 
				
			||||||
 | 
							{tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}},
 | 
				
			||||||
 | 
							{tStripOffsets, dtLong, []uint32{8}},
 | 
				
			||||||
 | 
							{tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}},
 | 
				
			||||||
 | 
							{tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}},
 | 
				
			||||||
 | 
							{tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
 | 
				
			||||||
 | 
							// There is currently no support for storing the image
 | 
				
			||||||
 | 
							// resolution, so give a bogus value of 72x72 dpi.
 | 
				
			||||||
 | 
							{tXResolution, dtRational, []uint32{72, 1}},
 | 
				
			||||||
 | 
							{tYResolution, dtRational, []uint32{72, 1}},
 | 
				
			||||||
 | 
							{tResolutionUnit, dtShort, []uint32{resPerInch}},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if pr != prNone {
 | 
				
			||||||
 | 
							ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(colorMap) != 0 {
 | 
				
			||||||
 | 
							ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if extraSamples > 0 {
 | 
				
			||||||
 | 
							ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return writeIFD(w, imageLen+8, ifd)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -8,6 +8,9 @@ github.com/cyrilix/robocar-base/service
 | 
				
			|||||||
# github.com/cyrilix/robocar-protobuf/go v1.0.3
 | 
					# github.com/cyrilix/robocar-protobuf/go v1.0.3
 | 
				
			||||||
## explicit; go 1.17
 | 
					## explicit; go 1.17
 | 
				
			||||||
github.com/cyrilix/robocar-protobuf/go/events
 | 
					github.com/cyrilix/robocar-protobuf/go/events
 | 
				
			||||||
 | 
					# github.com/disintegration/imaging v1.6.2
 | 
				
			||||||
 | 
					## explicit
 | 
				
			||||||
 | 
					github.com/disintegration/imaging
 | 
				
			||||||
# github.com/eclipse/paho.mqtt.golang v1.3.5
 | 
					# github.com/eclipse/paho.mqtt.golang v1.3.5
 | 
				
			||||||
## explicit; go 1.14
 | 
					## explicit; go 1.14
 | 
				
			||||||
github.com/eclipse/paho.mqtt.golang
 | 
					github.com/eclipse/paho.mqtt.golang
 | 
				
			||||||
@@ -33,6 +36,12 @@ go.uber.org/zap/internal/bufferpool
 | 
				
			|||||||
go.uber.org/zap/internal/color
 | 
					go.uber.org/zap/internal/color
 | 
				
			||||||
go.uber.org/zap/internal/exit
 | 
					go.uber.org/zap/internal/exit
 | 
				
			||||||
go.uber.org/zap/zapcore
 | 
					go.uber.org/zap/zapcore
 | 
				
			||||||
 | 
					# golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
 | 
				
			||||||
 | 
					## explicit; go 1.12
 | 
				
			||||||
 | 
					golang.org/x/image/bmp
 | 
				
			||||||
 | 
					golang.org/x/image/ccitt
 | 
				
			||||||
 | 
					golang.org/x/image/tiff
 | 
				
			||||||
 | 
					golang.org/x/image/tiff/lzw
 | 
				
			||||||
# golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
 | 
					# golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
 | 
				
			||||||
## explicit; go 1.11
 | 
					## explicit; go 1.11
 | 
				
			||||||
golang.org/x/net/internal/socks
 | 
					golang.org/x/net/internal/socks
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user