func encodePBM(w io.Writer, img image.Image, opts *EncodeOptions) error {
	if opts.Plain {
		fmt.Fprintln(w, "P1")
	} else {
		fmt.Fprintln(w, "P4")
	}
	for _, cmt := range opts.Comments {
		cmt = strings.Replace(cmt, "\n", " ", -1)
		cmt = strings.Replace(cmt, "\r", " ", -1)
		fmt.Fprintf(w, "# %s\n", cmt)
	}
	rect := img.Bounds()
	width := rect.Max.X - rect.Min.X
	height := rect.Max.Y - rect.Min.Y
	fmt.Fprintf(w, "%d %d\n", width, height)
	return encodeBWData(w, img, opts)
}
encodePBM writes an arbitrary image in PBM format.
package netpbm
import (
	"bufio"
	"errors"
	"fmt"
	"image"
	"image/color"
	"io"
	"strings"
	"unicode"
)
type BW struct{ *image.Paletted }
func (p *BW) MaxValue() uint16 {
	return 1
}
func (p *BW) Format() Format {
	return PBM
}
func (p *BW) HasAlpha() bool {
	return false
}
func NewBW(r image.Rectangle) *BW {
	colorMap := make(color.Palette, 2)
	colorMap[0] = color.RGBA{255, 255, 255, 255}
	colorMap[1] = color.RGBA{0, 0, 0, 255}
	return &BW{image.NewPaletted(r, colorMap)}
}
func (p *BW) PromoteToGrayM(m uint8) *GrayM {
	gray := NewGrayM(p.Bounds(), m)
	for i, bw := range p.Pix {
		gray.Pix[i] = (1 - bw) * m  
	}
	return gray
}
func (p *BW) PromoteToGrayM32(m uint16) *GrayM32 {
	gray := NewGrayM32(p.Bounds(), m)
	for i, bw := range p.Pix {
		g := uint16(1-bw) * m  
		gray.Pix[i*2+0] = uint8(g >> 8)
		gray.Pix[i*2+1] = uint8(g)
	}
	return gray
}
func decodeConfigPBMWithComments(r io.Reader) (image.Config, []string, error) {
	br, ok := r.(*bufio.Reader)
	if !ok {
		br = bufio.NewReader(r)
	}
	nr := newNetpbmReader(br)
	header, ok := nr.GetNetpbmHeader()
	if !ok {
		err := nr.Err()
		if err == nil {
			err = errors.New("Invalid PBM header")
		}
		return image.Config{}, nil, err
	}
	var cfg image.Config
	cfg.Width = header.Width
	cfg.Height = header.Height
	colorMap := make(color.Palette, 2)
	colorMap[0] = color.RGBA{255, 255, 255, 255}
	colorMap[1] = color.RGBA{0, 0, 0, 255}
	cfg.ColorModel = colorMap
	return cfg, header.Comments, nil
}
func decodeConfigPBM(r io.Reader) (image.Config, error) {
	img, _, err := decodeConfigPBMWithComments(r)
	return img, err
}
func decodePBMWithComments(r io.Reader) (image.Image, []string, error) {
	br := bufio.NewReader(r)
	config, comments, err := decodeConfigPBMWithComments(br)
	if err != nil {
		return nil, nil, err
	}
	img := NewBW(image.Rect(0, 0, config.Width, config.Height))
	nr := newNetpbmReader(br)
	buf := make([]byte, 1<<20)  
	bitsRemaining := config.Width * config.Height
	bitNum := 0
ReadLoop:
	for {
		var nRead int
		nRead, err = nr.Read(buf)
		if nRead == 0 && err != nil {
			return nil, nil, err
		}
		for _, oneByte := range buf[:nRead] {
			for i := 7; i >= 0; i-- {
				img.Pix[bitNum] = uint8((oneByte >> uint8(i)) & 1)
				bitNum++
				bitsRemaining--
				if bitsRemaining == 0 {
					break ReadLoop
				}
				if bitNum%config.Width == 0 {
					break
				}
			}
		}
	}
	return img, comments, nil
}
func decodePBM(r io.Reader) (image.Image, error) {
	img, _, err := decodePBMWithComments(r)
	return img, err
}
func decodePBMPlainWithComments(r io.Reader) (image.Image, []string, error) {
	br := bufio.NewReader(r)
	config, comments, err := decodeConfigPBMWithComments(br)
	if err != nil {
		return nil, nil, err
	}
	img := NewBW(image.Rect(0, 0, config.Width, config.Height))
	nr := newNetpbmReader(br)
	badness := func() (image.Image, []string, error) {
		err := nr.Err()
		if err == nil {
			err = errors.New("Failed to parse ASCII PBM data")
		}
		return img, nil, err
	}
	totalBits := config.Width * config.Height
	for i := 0; i < totalBits; {
		ch := nr.GetNextByteAsRune()
		switch {
		case nr.Err() != nil:
			return badness()
		case unicode.IsSpace(ch):
			continue
		case ch == '0' || ch == '1':
			img.Pix[i] = uint8(ch - '0')
			i++
		default:
			return badness()
		}
	}
	return img, comments, nil
}
func decodePBMPlain(r io.Reader) (image.Image, error) {
	img, _, err := decodePBMPlainWithComments(r)
	return img, err
}
func init() {
	image.RegisterFormat("pbm", "P4", decodePBM, decodeConfigPBM)
	image.RegisterFormat("pbm", "P1", decodePBMPlain, decodeConfigPBM)
}