jpeg

package
v0.0.0-...-f9ed69e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 4, 2023 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package jpeg implements a low-level a JPEG scanner.

Index

Examples

Constants

View Source
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

View Source
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

func WriteChunk

func WriteChunk(w io.Writer, marker byte, chunkdata []byte) error

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)
	}
}
Output:

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)
	}
}
Output:

func NewScanner

func NewScanner(r io.Reader) (*Scanner, error)

func (*Scanner) Bytes

func (j *Scanner) Bytes() []byte

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) Err

func (j *Scanner) Err() error

Err() returns any error encountered during Next()

func (*Scanner) IsChunk

func (j *Scanner) IsChunk(marker byte, prefix []byte) bool

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) Len

func (j *Scanner) Len() int

Len returns the currently available Bytes in Scanner.

func (*Scanner) Next

func (j *Scanner) Next() bool

Next() reads the next block of logical units in Scanner.

func (*Scanner) NextChunk

func (j *Scanner) NextChunk() bool

NextChunk scans for the next chunk in the stream.

func (*Scanner) ReadChunk

func (j *Scanner) ReadChunk() (marker byte, payload []byte, err error)

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

func (j *Scanner) ReadSegment() ([]byte, error)

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) Reader

func (j *Scanner) Reader() io.Reader

Reader returns a reader for the data remaining in the underlying reader.

func (*Scanner) StartChunk

func (j *Scanner) StartChunk() bool

StartChunk returns true if the last call to Next() found chunked data in the stream.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL