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  }