func lexAfterDataPrefix(l *lexer) stateFn {
	switch r := l.next(); {
	case r == paramSemicolon:
		l.backup()
		return lexParamSemicolon
	case r == dataComma:
		l.backup()
		return lexDataComma
	case r == eof:
		return l.errorf("missing comma before data")
	case r == 'x' || r == 'X':
		if l.next() == '-' {
			return lexXTokenMediaType
		}
		return lexInDiscreteMediaType
	case isTokenRune(r):
		return lexInDiscreteMediaType
	default:
		return l.errorf("invalid character after data prefix")
	}
}
lex what's after data prefix.
it can be the media type/subtype separator,
the base64 encoding, or the comma preceding the data
package dataurl
import (
	"fmt"
	"strings"
	"unicode"
	"unicode/utf8"
)
type item struct {
	t   itemType
	val string
}
func (i item) String() string {
	switch i.t {
	case itemEOF:
		return "EOF"
	case itemError:
		return i.val
	}
	if len(i.val) > 10 {
		return fmt.Sprintf("%.10q...", i.val)
	}
	return fmt.Sprintf("%q", i.val)
}
type itemType int
const (
	itemError itemType = iota
	itemEOF
	itemDataPrefix
	itemMediaType
	itemMediaSep
	itemMediaSubType
	itemParamSemicolon
	itemParamAttr
	itemParamEqual
	itemLeftStringQuote
	itemRightStringQuote
	itemParamVal
	itemBase64Enc
	itemDataComma
	itemData
)
const eof rune = -1
func isTokenRune(r rune) bool {
	return r <= unicode.MaxASCII &&
		!unicode.IsControl(r) &&
		!unicode.IsSpace(r) &&
		!isTSpecialRune(r)
}
func isTSpecialRune(r rune) bool {
	return r == '(' ||
		r == ')' ||
		r == '<' ||
		r == '>' ||
		r == '@' ||
		r == ',' ||
		r == ';' ||
		r == ':' ||
		r == '\\' ||
		r == '"' ||
		r == '/' ||
		r == '[' ||
		r == ']' ||
		r == '?' ||
		r == '='
}
func isDiscreteType(s string) bool {
	if strings.HasPrefix(s, "text") ||
		strings.HasPrefix(s, "image") ||
		strings.HasPrefix(s, "audio") ||
		strings.HasPrefix(s, "video") ||
		strings.HasPrefix(s, "application") {
		return true
	}
	return false
}
func isCompositeType(s string) bool {
	if strings.HasPrefix(s, "message") ||
		strings.HasPrefix(s, "multipart") {
		return true
	}
	return false
}
func isURLCharRune(r rune) bool {
	return r <= unicode.MaxASCII &&
		!(r >= 0x00 && r <= 0x1F) && r != 0x7F &&  
		r != ' ' &&
		r != '<' &&
		r != '>' &&
		r != '#' &&
		r != '"' &&
		r != '{' &&
		r != '}' &&
		r != '|' &&
		r != '\\' &&
		r != '^' &&
		r != '[' &&
		r != ']' &&
		r != '`'
}
func isBase64Rune(r rune) bool {
	return (r >= 'a' && r <= 'z') ||
		(r >= 'A' && r <= 'Z') ||
		(r >= '0' && r <= '9') ||
		r == '+' ||
		r == '/' ||
		r == '=' ||
		r == '\n'
}
type stateFn func(*lexer) stateFn
type lexer struct {
	input          string
	start          int
	pos            int
	width          int
	seenBase64Item bool
	items          chan item
}
func (l *lexer) run() {
	for state := lexBeforeDataPrefix; state != nil; {
		state = state(l)
	}
	close(l.items)
}
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.input[l.start:l.pos]}
	l.start = l.pos
}
func (l *lexer) next() (r rune) {
	if l.pos >= len(l.input) {
		l.width = 0
		return eof
	}
	r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	l.pos += l.width
	return r
}
func (l *lexer) backup() {
	l.pos -= l.width
}
func (l *lexer) ignore() {
	l.start = l.pos
}
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{itemError, fmt.Sprintf(format, args...)}
	return nil
}
func lex(input string) *lexer {
	l := &lexer{
		input: input,
		items: make(chan item),
	}
	go l.run()  
	return l
}
const (
	dataPrefix     = "data:"
	mediaSep       = '/'
	paramSemicolon = ';'
	paramEqual     = '='
	dataComma      = ','
)
func lexBeforeDataPrefix(l *lexer) stateFn {
	if strings.HasPrefix(l.input[l.pos:], dataPrefix) {
		return lexDataPrefix
	}
	return l.errorf("missing data prefix")
}
func lexDataPrefix(l *lexer) stateFn {
	l.pos += len(dataPrefix)
	l.emit(itemDataPrefix)
	return lexAfterDataPrefix
}