1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package tga

import (
	"bytes"
	"encoding/binary"
	"image"
	"image/draw"
	//_ "image/gif"
	//_ "image/jpeg"
	//_ "image/png"
	//_ "code.google.com/p/webp"
	"io"
	"os"
)

/*	Image Data Types
	I = image, U = uncompressed, CM= ColorMap, RGB = RedGreenBlue BW = Black and White
	RL= Run Length Algo. D=Delta algo, H=Huffman algo, 4PQ = 4-pass quadtree*/
const (
	_NONE            = 0x0
	_U_CM_I          = 0x1
	_U_RGB_I         = 0x2
	_U_BW_I          = 0x3
	_RL_CM_I         = 0x9
	_RL_RGB_I        = 0xA
	_C_BW_I          = 0xB
	_C_CM_H_D_RL     = 0x20
	_C_CM_H_D_RL_4PQ = 0x21
)

/*	TGA Spec
	http://local.wasp.uwa.edu.au/~pbourke/dataformats/tga/

	Header :
	[0]: 		Length of file descriptor field
	[1]: 		color map mode
	[2]:  		image datatype, See Image_Datatype_Def for defintions.
	[3-4][5-6][7]:	colormap origin, colormap length, colormap depth	
	[8-9][10-11]:	x and y origins. 0 denotes lower left	 	
	[12-13][14-15]:	Image Width, Height in pixels	 			
	[16]:		bits per pixel. 32 for full color plus alpha.
	[17]:		b1-3 toggles # of attribute bits per pixel (alpha8), 
			b4 is reserved, 	
			b5 sets screen origin(must be 0 for tga).
			b6-7 data storage interleaving flag.

	Currently this is only configured to configure to encode an image into an uncompressed 
	32 bit rgba tga image.	As more features are added, alot of this code will be moved out to 
	allow setting an explicit case flags that  will encode the image interface into the different 
	image types the tga spec defines and the compression methods that can be used as part of 
	the standard.*/
func Encode(w io.Writer, m image.Image) error {
	b := m.Bounds()

	mw, mh := int64(b.Dx()), int64(b.Dy())
	if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
		return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mw, 10))
	}
	/*This next code block isnt necessary unless you want to to define a file descriptor field
	It can be up to 255 bytes long and in the past it was typically used for extending
	the tga format when businesses that specialized in GPUs would implement proprietary hardware
	extensions to there products. Also, this field is where you would store info like creation/mod date, ect.
	It is just here for educational purposes on how to implement this and for the purpose of golang,
	I think its unecessary bloat. Implementing this will be moved out to its own exported function.

		c := "go"
		idField := make([]byte, len(c))
		copy(idField, fn) 
		header[0] = byte(len(c)) 
	*/

	//tga bytes are stored as little endian when they represent 16 bit values. i.e [Lb, Hb][b][b][Lb,Hb]....
	width, height := make([]byte, 2), make([]byte, 2)

	binary.LittleEndian.PutUint16(width, uint16(b.Dx()))
	binary.LittleEndian.PutUint16(height, uint16(b.Dy()))

	header := [18]byte{
		0, 0, _URGBI,
		0, 0, 0, 0, 0,
		0, 0, 0, 0,
		width[0], width[1],
		height[0], height[1],
		0x20, 0x08}

	rgbaImg, ok := img.(*image.NRGBA)
	if !ok {
		println("Image must be NRGBA")
		return nil
	}

	tga := make([]byte)
	append(header)
	//append(data, idField)

	data := make([]byte, b.Dx()*b.Dy()*4)
	lineLen := b.Dx() * 4
	dest := len(data) - lineLen
	for src := 0; src < len(rgbaImg.Pix); {
		copy(data[dest:dest+lineLen], rgbaImg.Pix[src:src+rgbaImg.Stride])
		dest -= lineLen
		src += rgbaImg.Stride
	}
	for x := 0; x < len(data); {

		buf.WriteByte(data[x+2])
		buf.WriteByte(data[x+1])
		buf.WriteByte(data[x+0])
		buf.WriteByte(data[x+3])
		x += 4

	}
	return &buf

}

/*
func Create(fn string) (data *bytes.Buffer, err error) {
	f, err := os.Open(fn)
	if err != nil {
		return
	}
	defer f.Close()

	img, format, err := image.Decode(f)
	if err != nil {
		return
	}
	if format != "png" {
		b := img.Bounds()
		m := image.NewNRGBA(b)
		draw.Draw(m, b, img, b.Min, draw.Src)
		data = Encode(fn, m)
	} else {
		data = Encode(fn, img)
	}
	return
}
*/
/*func WriteToFile(tga []byte, fn string, overwrite bool) error {
	fp, _ := os.Getwd()
	err := os.Chdir(fp + "tga_img")
	if err != nil {
		NoDir := os.IsNotExist(err)
		println("tga_img doesnt exist: ", NoDir)
		if NoDir {
			err := os.Mkdir("tga_img", os.ModePerm)
			if err != nil {
				return err
			}
			err = os.Chdir(fp + "/tga_img")
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	file, err := os.Create(fn + ".tga")
	if err != nil {
		exists := os.IsExist(err)
		if exists {
			if !overwrite {
				err = os.Rename(fn+".tga", fn+time.Now().String()+".tga")
				if err != nil {
					return err
				}
			} else {
				err = os.Remove(fn + ".tga")
				if err != nil {
					return err
				}
			}
			file, err = os.Create(fn + ".tga")

		}
	}
	n, err := file.Write(tga)
	if err != nil {
		return err
	}
	println("tga written to disk: wrote: ", n, " bytes")
	return nil

}*/