9fans.net/go@v0.0.5/draw/readimage.go (about) 1 package draw 2 3 import ( 4 "fmt" 5 "io" 6 "strings" 7 ) 8 9 // ReadImage creates an image from data contained in r. 10 // (See the package documentation for the image file format.) 11 // The returned image is allocated using AllocImage. 12 func (d *Display) ReadImage(r io.Reader) (*Image, error) { 13 d.mu.Lock() 14 defer d.mu.Unlock() 15 return d.readImage(r) 16 } 17 18 func (d *Display) readImage(rd io.Reader) (*Image, error) { 19 fd := rd 20 hdr := make([]byte, 5*12) 21 22 _, err := io.ReadFull(fd, hdr[:11]) 23 if err != nil { 24 return nil, fmt.Errorf("reading image header: %v", err) 25 } 26 if string(hdr[:11]) == "compressed\n" { 27 return d.creadimage(rd) 28 } 29 30 _, err = io.ReadFull(fd, hdr[11:]) 31 if err != nil { 32 return nil, fmt.Errorf("reading image header: %v", err) 33 } 34 35 chunk := 8192 36 if d != nil { 37 chunk = d.bufsize - 32 // a little room for header 38 } 39 40 /* 41 * distinguish new channel descriptor from old ldepth. 42 * channel descriptors have letters as well as numbers, 43 * while ldepths are a single digit formatted as %-11d. 44 */ 45 new := false 46 for m := 0; m < 10; m++ { 47 if hdr[m] != ' ' { 48 new = true 49 break 50 } 51 } 52 if hdr[11] != ' ' { 53 return nil, fmt.Errorf("readimage: bad format") 54 } 55 var pix Pix 56 if new { 57 pix, err = ParsePix(strings.TrimSpace(string(hdr[:12]))) 58 if err != nil { 59 return nil, fmt.Errorf("readimage: %v", err) 60 } 61 } else { 62 ldepth := int(hdr[10]) - '0' 63 if ldepth < 0 || ldepth > 3 { 64 return nil, fmt.Errorf("readimage: bad ldepth %d", ldepth) 65 } 66 pix = ldepthToPix[ldepth] 67 } 68 r := ator(hdr[1*12:]) 69 if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y { 70 return nil, fmt.Errorf("readimage: bad rectangle") 71 } 72 73 miny := r.Min.Y 74 maxy := r.Max.Y 75 76 l := BytesPerLine(r, pix.Depth()) 77 var i *Image 78 if d != nil { 79 i, err = d.allocImage(r, pix, false, 0) 80 if err != nil { 81 return nil, err 82 } 83 } else { 84 i = &Image{R: r, Pix: pix, Depth: pix.Depth()} 85 } 86 87 tmp := make([]byte, chunk) 88 if tmp == nil { 89 goto Err 90 } 91 for maxy > miny { 92 dy := maxy - miny 93 if dy*l > chunk { 94 dy = chunk / l 95 } 96 if dy <= 0 { 97 err = fmt.Errorf("readimage: image too wide for buffer") 98 goto Err 99 } 100 n := dy * l 101 if _, err = io.ReadFull(fd, tmp[:n]); err != nil { 102 goto Err 103 } 104 if !new { /* an old image: must flip all the bits */ 105 for i, b := range tmp[:n] { 106 _, _ = i, b // tmp[i] = b ^ 0xFF 107 } 108 } 109 if d != nil { 110 if _, err = i.load(Rect(r.Min.X, miny, r.Max.X, miny+dy), tmp[:n]); err != nil { 111 goto Err 112 } 113 } 114 miny += dy 115 } 116 return i, nil 117 118 Err: 119 if d != nil { 120 i.free() 121 } 122 return nil, err 123 }