├── .gitignore ├── LICENSE ├── README.md ├── icondata.png ├── new.ico ├── writer.go └── writer_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | golang-image-ico 2 | ================ 3 | 4 | golang support for windows .ico file format 5 | 6 | http://en.wikipedia.org/wiki/ICO_(file_format) -------------------------------------------------------------------------------- /icondata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kodeworks/golang-image-ico/73f0f4cfade9008b7c0938a8224ececaa7733883/icondata.png -------------------------------------------------------------------------------- /new.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kodeworks/golang-image-ico/73f0f4cfade9008b7c0938a8224ececaa7733883/new.ico -------------------------------------------------------------------------------- /writer.go: -------------------------------------------------------------------------------- 1 | package ico 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "encoding/binary" 7 | "image" 8 | "image/draw" 9 | "image/png" 10 | "io" 11 | ) 12 | 13 | type icondir struct { 14 | reserved uint16 15 | imageType uint16 16 | numImages uint16 17 | } 18 | 19 | type icondirentry struct { 20 | imageWidth uint8 21 | imageHeight uint8 22 | numColors uint8 23 | reserved uint8 24 | colorPlanes uint16 25 | bitsPerPixel uint16 26 | sizeInBytes uint32 27 | offset uint32 28 | } 29 | 30 | func newIcondir() icondir { 31 | var id icondir 32 | id.imageType = 1 33 | id.numImages = 1 34 | return id 35 | } 36 | 37 | func newIcondirentry() icondirentry { 38 | var ide icondirentry 39 | ide.colorPlanes = 1 // windows is supposed to not mind 0 or 1, but other icon files seem to have 1 here 40 | ide.bitsPerPixel = 32 // can be 24 for bitmap or 24/32 for png. Set to 32 for now 41 | ide.offset = 22 //6 icondir + 16 icondirentry, next image will be this image size + 16 icondirentry, etc 42 | return ide 43 | } 44 | 45 | func Encode(w io.Writer, im image.Image) error { 46 | b := im.Bounds() 47 | m := image.NewRGBA(b) 48 | draw.Draw(m, b, im, b.Min, draw.Src) 49 | 50 | id := newIcondir() 51 | ide := newIcondirentry() 52 | 53 | pngbb := new(bytes.Buffer) 54 | pngwriter := bufio.NewWriter(pngbb) 55 | png.Encode(pngwriter, m) 56 | pngwriter.Flush() 57 | ide.sizeInBytes = uint32(len(pngbb.Bytes())) 58 | 59 | bounds := m.Bounds() 60 | ide.imageWidth = uint8(bounds.Dx()) 61 | ide.imageHeight = uint8(bounds.Dy()) 62 | bb := new(bytes.Buffer) 63 | 64 | var e error 65 | binary.Write(bb, binary.LittleEndian, id) 66 | binary.Write(bb, binary.LittleEndian, ide) 67 | 68 | w.Write(bb.Bytes()) 69 | w.Write(pngbb.Bytes()) 70 | 71 | return e 72 | } 73 | -------------------------------------------------------------------------------- /writer_test.go: -------------------------------------------------------------------------------- 1 | package ico 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "image/png" 7 | "os" 8 | "testing" 9 | ) 10 | 11 | func readPng(filename string) (image.Image, error) { 12 | f, err := os.Open(filename) 13 | if err != nil { 14 | return nil, err 15 | } 16 | defer f.Close() 17 | return png.Decode(f) 18 | } 19 | 20 | func TestWriter(t *testing.T) { 21 | fn := "icondata.png" 22 | m0, err := readPng(fn) 23 | if err != nil { 24 | t.Error(fn, err) 25 | } 26 | icoimg, _ := os.Create("new.ico") 27 | defer icoimg.Close() 28 | icoerror := Encode(icoimg, m0) 29 | fmt.Printf("icoerror: %s\n", icoerror) 30 | 31 | } 32 | --------------------------------------------------------------------------------