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  }