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/tajtiattila/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)
}
}
Example (Copy) ¶
package main
import (
"fmt"
"io"
"os"
"github.com/tajtiattila/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)
}
}
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.