9fans.net/go@v0.0.5/draw/memdraw/cread.go (about) 1 // #include <u.h> 2 // #include <libc.h> 3 // #include <draw.h> 4 // #include <memdraw.h> 5 6 package memdraw 7 8 import ( 9 "fmt" 10 "io" 11 "strconv" 12 "strings" 13 14 "9fans.net/go/draw" 15 ) 16 17 func atoi(s []byte) int { 18 i, _ := strconv.Atoi(strings.TrimSpace(string(s))) 19 return i 20 } 21 22 var ldepthToPix = []draw.Pix{ 23 draw.GREY1, 24 draw.GREY2, 25 draw.GREY4, 26 draw.CMAP8, 27 } 28 29 func creadmemimage(fd io.Reader) (*Image, error) { 30 hdr := make([]byte, 5*12) 31 if _, err := io.ReadFull(fd, hdr); err != nil { 32 return nil, err 33 } 34 35 /* 36 * distinguish new channel descriptor from old ldepth. 37 * channel descriptors have letters as well as numbers, 38 * while ldepths are a single digit formatted as %-11d. 39 */ 40 new := 0 41 for m := 0; m < 10; m++ { 42 if hdr[m] != ' ' { 43 new = 1 44 break 45 } 46 } 47 if hdr[11] != ' ' { 48 return nil, fmt.Errorf("creadimage: bad format") 49 } 50 var chan_ draw.Pix 51 if new != 0 { 52 s := strings.TrimSpace(string(hdr[:11])) 53 var err error 54 chan_, err = draw.ParsePix(s) 55 if err != nil { 56 return nil, fmt.Errorf("creadimage: bad channel string %s", s) 57 } 58 } else { 59 ldepth := (int(hdr[10])) - '0' 60 if ldepth < 0 || ldepth > 3 { 61 return nil, fmt.Errorf("creadimage: bad ldepth %d", ldepth) 62 } 63 chan_ = ldepthToPix[ldepth] 64 } 65 var r draw.Rectangle 66 r.Min.X = atoi(hdr[1*12 : 2*12]) 67 r.Min.Y = atoi(hdr[2*12 : 3*12]) 68 r.Max.X = atoi(hdr[3*12 : 4*12]) 69 r.Max.Y = atoi(hdr[4*12 : 5*12]) 70 if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y { 71 return nil, fmt.Errorf("creadimage: bad rectangle") 72 } 73 74 i, err := AllocImage(r, chan_) 75 if err != nil { 76 return nil, err 77 } 78 ncblock := compblocksize(r, i.Depth) 79 buf := make([]byte, ncblock) 80 miny := r.Min.Y 81 for miny != r.Max.Y { 82 if _, err := io.ReadFull(fd, hdr[:2*12]); err != nil { 83 Free(i) 84 return nil, err 85 } 86 maxy := atoi(hdr[0*12 : 1*12]) 87 nb := atoi(hdr[1*12 : 2*12]) 88 if maxy <= miny || r.Max.Y < maxy { 89 Free(i) 90 return nil, fmt.Errorf("readimage: bad maxy %d", maxy) 91 } 92 if nb <= 0 || ncblock < nb { 93 Free(i) 94 return nil, fmt.Errorf("readimage: bad count %d", nb) 95 } 96 if _, err := io.ReadFull(fd, buf[:nb]); err != nil { 97 Free(i) 98 return nil, err 99 } 100 if new == 0 { 101 twiddlecompressed(buf[:nb]) 102 } 103 cloadmemimage(i, draw.Rect(r.Min.X, miny, r.Max.X, maxy), buf[:nb]) 104 miny = maxy 105 } 106 return i, nil 107 } 108 109 func compblocksize(r draw.Rectangle, depth int) int { 110 bpl := draw.BytesPerLine(r, depth) 111 bpl = 2 * bpl /* add plenty extra for blocking, etc. */ 112 if bpl < _NCBLOCK { 113 return _NCBLOCK 114 } 115 return bpl 116 } 117 118 func twiddlecompressed(buf []byte) { 119 i := 0 120 for i < len(buf) { 121 c := buf[i] 122 i++ 123 if c >= 0x80 { 124 k := int(c) - 0x80 + 1 125 for j := 0; j < k && i < len(buf); j++ { 126 buf[i] ^= 0xFF 127 i++ 128 } 129 } else { 130 i++ 131 } 132 } 133 }