Documentation ¶
Overview ¶
Package jpeg implements a low-level a JPEG scanner.
Index ¶
- Constants
- Variables
- func WriteChunk(w io.Writer, marker byte, chunkdata []byte) error
- type Scanner
- func (j *Scanner) Bytes() []byte
- func (j *Scanner) Err() error
- func (j *Scanner) IsChunk(marker byte, prefix []byte) bool
- func (j *Scanner) Len() int
- func (j *Scanner) Next() bool
- func (j *Scanner) NextChunk() bool
- func (j *Scanner) ReadChunk() (marker byte, payload []byte, err error)
- func (j *Scanner) ReadSegment() ([]byte, error)
- func (j *Scanner) Reader() io.Reader
- func (j *Scanner) StartChunk() bool
Examples ¶
Constants ¶
const MaxPrefixLen = 32
MaxPrefixLen is the number of max. bytes accepted by Scanner.IsChunk.
It should be long enough to recognise known APP segments.
JFIF: 'J' 'F' 'I' 'F' 00 (5 bytes) JFXX: 'J' 'F' 'X' 'X' 00 (5 bytes) EXIF: 'E' 'x' 'i' 'f' 00 00 (9 bytes) XMP: "http://ns.adobe.com/xap/1.0/" 00 (30 bytes)
Variables ¶
var ( // ErrNotJpeg is returned if the file is not a jpeg file. ErrNotJpeg = errors.New("jpeg: missing start of image marker") // ErrTooLong is returned if the a chunk is too long to be written in an jpeg file. ErrTooLong = errors.New("jpeg: encoded length too long") // ErrNoChunk is returned if the data at the current position is not a chunk. ErrNoChunk = errors.New("jpeg: not a chunk") )
Functions ¶
Types ¶
type Scanner ¶
type Scanner struct {
// contains filtered or unexported fields
}
Example ¶
Use Scanner to find the Exif in a JPEG file.
package main import ( "fmt" "os" "github.com/acls/metadata/jpeg" ) func main() { scanner, err := jpeg.NewScanner(os.Stdin) if err != nil { fmt.Printf("jpeg error: %v", err) return } for scanner.NextChunk() { const app1 = 0xe1 if scanner.IsChunk(app1, []byte("Exif\x00\x00")) { _, p, err := scanner.ReadChunk() if err != nil { break } // do something with exif fmt.Printf("% .32x", p) } } if err := scanner.Err(); err != nil { fmt.Printf("jpeg error: %v", err) } }
Output:
Example (Copy) ¶
package main import ( "fmt" "io" "os" "github.com/acls/metadata/jpeg" ) func main() { input, output := os.Stdin, os.Stdout scanner, err := jpeg.NewScanner(input) if err != nil { fmt.Fprintf(os.Stderr, "jpeg error: %v", err) return } var werr error for werr == nil && scanner.Next() { const app1 = 0xe1 if scanner.IsChunk(app1, []byte("Exif\x00\x00")) { // read the Exif _, exif, err := scanner.ReadChunk() if err != nil { break } // do something with the Exif // write new Exif werr = jpeg.WriteChunk(output, app1, exif) } else { // copy other data from source var n int n, werr = output.Write(scanner.Bytes()) if n != scanner.Len() { werr = io.ErrShortWrite } } } if err := scanner.Err(); err != nil { fmt.Fprintf(os.Stderr, "jpeg error: %v", err) } if werr != nil { fmt.Fprintf(os.Stderr, "write error: %v", werr) } }
Output:
func (*Scanner) Bytes ¶
Bytes returns the most recent byte slice scanned after calling Next. The returned slice must not be modified, and is valid until the next call to Next(Chunk) or Read(Chunk|Segment).
func (*Scanner) IsChunk ¶
IsChunk checks if the Scanner is at the start of a chunk having marker and prefix. IsChunk panics if prefix is longer than MaxPrefixLen.
func (*Scanner) ReadChunk ¶
ReadChunk reads the current chunk in a new byte slice, or returns ErrNoChunk if the data at the current position is not a segment with a (possibly empty) payload.
func (*Scanner) ReadSegment ¶
ReadSegment reads the current section the into a new byte slice after calling Next. The returned slice will always have a prefix of Bytes(). ReadSegment returns valid sections as a single byte slice.
ReadSegment returns a copy of Bytes() if the Next() found padding or data without payload.
func (*Scanner) StartChunk ¶
StartChunk returns true if the last call to Next() found chunked data in the stream.