diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 6d14ecb..0000000 --- a/.appveyor.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: "{build}" - -clone_depth: 1 - -clone_folder: c:\gopath\src\github.com\gen2brain\go-fitz - -environment: - GOPATH: c:\gopath - MSYS_PATH: c:\msys64 - CGO_ENABLED: 1 - GOARCH: 386 - CC: i686-w64-mingw32-gcc - -install: - - echo %GOPATH% - - echo %MSYS_PATH% - - set PATH=%GOPATH%\bin;c:\go\bin;%MSYS_PATH%\usr\bin;%MSYS_PATH%\mingw32\bin;%PATH% - - go version - - go env - -build_script: - - bash -lc "cd /c/gopath/src/github.com/gen2brain/go-fitz && go build" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8a6e05c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# Enforce LF for Netpbm formats on Windows +testdata/test.pam text eol=lf +testdata/test.pbm text eol=lf +testdata/test.pfm text eol=lf +testdata/test.pgm text eol=lf +testdata/test.ppm text eol=lf diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..562493a --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,19 @@ +on: [push, pull_request] +name: Test +jobs: + test: + strategy: + fail-fast: false + matrix: + go-version: [1.22.x] + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + - name: Test + run: go test diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..7682b10 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + "lastFilter": { + "state": "OPEN", + "assignee": "landaiqing" + } +} + { + "selectedUrlAndAccountId": { + "url": "https://github.com/karmdip-mi/go-fitz.git", + "accountId": "73c6c393-67f6-46b4-913b-c2a816ed360b" + } +} + { + "associatedIndex": 0 +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1770690080445 + + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 88daebf..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go - -go: - - 1.12.x - -install: - - go get -tags nopie -t -v ./... - -script: - - go build -tags nopie diff --git a/README.md b/README.md index 632c5ff..1d99c31 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,26 @@ ## go-fitz -Go wrapper for [MuPDF](http://mupdf.com/) fitz library that can extract pages from PDF and EPUB documents as images, text, html or svg. +[![Build Status](https://github.com/gen2brain/go-fitz/actions/workflows/test.yml/badge.svg)](https://github.com/gen2brain/go-fitz/actions) +[![GoDoc](https://godoc.org/github.com/gen2brain/go-fitz?status.svg)](https://godoc.org/github.com/gen2brain/go-fitz) +[![Go Report Card](https://goreportcard.com/badge/github.com/gen2brain/go-fitz?branch=master)](https://goreportcard.com/report/github.com/gen2brain/go-fitz) -### Install - - go get -u github.com/karmdip-mi/go-fitz +Go wrapper for [MuPDF](http://mupdf.com/) fitz library that can extract pages from PDF, EPUB, MOBI, DOCX, XLSX and PPTX documents as IMG, TXT, HTML or SVG. ### Build tags * `extlib` - use external MuPDF library * `static` - build with static external MuPDF library (used with `extlib`) -* `nopie` - use this with GCC older then 7 +* `pkgconfig` - enable pkg-config (used with `extlib`) +* `musl` - use musl compiled library +* `nocgo` - experimental [purego](https://github.com/ebitengine/purego) implementation (can also be used with `CGO_ENABLED=0`) + +### Notes + +The bundled libraries are built without CJK fonts, if you need them you must use the external library. + +Calling e.g. Image() or Text() methods concurrently for the same document is not supported. + +Purego implementation requires `libffi` and `libmupdf` shared libraries on runtime. +You must set `fitz.FzVersion` in your code or set `FZ_VERSION` environment variable to exact version of the shared library. ### Example ```go @@ -18,11 +29,10 @@ package main import ( "fmt" "image/jpeg" - "io/ioutil" "os" "path/filepath" - "github.com/karmdip-mi/go-fitz" + "github.com/gen2brain/go-fitz" ) func main() { @@ -33,7 +43,7 @@ func main() { defer doc.Close() - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") if err != nil { panic(err) } @@ -57,45 +67,5 @@ func main() { f.Close() } - - // Extract pages as text - for n := 0; n < doc.NumPage(); n++ { - text, err := doc.Text(n) - if err != nil { - panic(err) - } - - f, err := os.Create(filepath.Join(tmpDir, fmt.Sprintf("test%03d.txt", n))) - if err != nil { - panic(err) - } - - _, err = f.WriteString(text) - if err != nil { - panic(err) - } - - f.Close() - } - - // Extract pages as html - for n := 0; n < doc.NumPage(); n++ { - html, err := doc.HTML(n, true) - if err != nil { - panic(err) - } - - f, err := os.Create(filepath.Join(tmpDir, fmt.Sprintf("test%03d.html", n))) - if err != nil { - panic(err) - } - - _, err = f.WriteString(html) - if err != nil { - panic(err) - } - - f.Close() - } } ``` diff --git a/example_test.go b/example_test.go index 603de48..3f69ef0 100644 --- a/example_test.go +++ b/example_test.go @@ -1,22 +1,23 @@ -package fitz +package fitz_test import ( "fmt" "image/jpeg" - "io/ioutil" "os" "path/filepath" + + "github.com/gen2brain/go-fitz" ) func ExampleNew() { - doc, err := New("test.pdf") + doc, err := fitz.New("test.pdf") if err != nil { panic(err) } defer doc.Close() - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") if err != nil { panic(err) } diff --git a/fitz.go b/fitz.go index 66de34d..25ff24b 100644 --- a/fitz.go +++ b/fitz.go @@ -1,45 +1,34 @@ // Package fitz provides wrapper for the [MuPDF](http://mupdf.com/) fitz library -// that can extract pages from PDF and EPUB documents as images, text, html or svg. +// that can extract pages from PDF, EPUB, MOBI, DOCX, XLSX and PPTX documents as IMG, TXT, HTML or SVG. package fitz -/* -#include -#include - -const char *fz_version = FZ_VERSION; -*/ -import "C" - import ( "errors" - "image" - "io" - "io/ioutil" - "os" - "path/filepath" - "sync" "unsafe" ) // Errors. var ( - ErrNoSuchFile = errors.New("fitz: no such file") - ErrCreateContext = errors.New("fitz: cannot create context") - ErrOpenDocument = errors.New("fitz: cannot open document") - ErrOpenMemory = errors.New("fitz: cannot open memory") - ErrPageMissing = errors.New("fitz: page missing") - ErrCreatePixmap = errors.New("fitz: cannot create pixmap") - ErrPixmapSamples = errors.New("fitz: cannot get pixmap samples") - ErrNeedsPassword = errors.New("fitz: document needs password") - ErrLoadOutline = errors.New("fitz: cannot load outline") + ErrNoSuchFile = errors.New("fitz: no such file") + ErrCreateContext = errors.New("fitz: cannot create context") + ErrOpenDocument = errors.New("fitz: cannot open document") + ErrEmptyBytes = errors.New("fitz: cannot send empty bytes") + ErrOpenMemory = errors.New("fitz: cannot open memory") + ErrLoadPage = errors.New("fitz: cannot load page") + ErrRunPageContents = errors.New("fitz: cannot run page contents") + ErrPageMissing = errors.New("fitz: page missing") + ErrCreatePixmap = errors.New("fitz: cannot create pixmap") + ErrPixmapSamples = errors.New("fitz: cannot get pixmap samples") + ErrNeedsPassword = errors.New("fitz: document needs password") + ErrLoadOutline = errors.New("fitz: cannot load outline") ) -// Document represents fitz document. -type Document struct { - ctx *C.struct_fz_context_s - doc *C.struct_fz_document_s - mtx sync.Mutex -} +// MaxStore is maximum size in bytes of the resource store, before it will start evicting cached resources such as fonts and images. +var MaxStore = 256 << 20 + +// FzVersion is used for experimental purego implementation, it must be exactly the same as libmupdf shared library version. +// It is also possible to set `FZ_VERSION` environment variable. +var FzVersion = "1.24.9" // Outline type. type Outline struct { @@ -55,425 +44,24 @@ type Outline struct { Top float64 } -// New returns new fitz document. -func New(filename string) (f *Document, err error) { - f = &Document{} - - filename, err = filepath.Abs(filename) - if err != nil { - return - } - - if _, e := os.Stat(filename); e != nil { - err = ErrNoSuchFile - return - } - - f.ctx = (*C.struct_fz_context_s)(unsafe.Pointer(C.fz_new_context_imp(nil, nil, C.FZ_STORE_UNLIMITED, C.fz_version))) - if f.ctx == nil { - err = ErrCreateContext - return - } - - C.fz_register_document_handlers(f.ctx) - - cfilename := C.CString(filename) - defer C.free(unsafe.Pointer(cfilename)) - - f.doc = C.fz_open_document(f.ctx, cfilename) - if f.doc == nil { - err = ErrOpenDocument - return - } - - ret := C.fz_needs_password(f.ctx, f.doc) - v := bool(int(ret) != 0) - if v { - err = ErrNeedsPassword - } - - return +// Link type. +type Link struct { + URI string } -// NewFromMemory returns new fitz document from byte slice. -func NewFromMemory(b []byte) (f *Document, err error) { - f = &Document{} - - f.ctx = (*C.struct_fz_context_s)(unsafe.Pointer(C.fz_new_context_imp(nil, nil, C.FZ_STORE_UNLIMITED, C.fz_version))) - if f.ctx == nil { - err = ErrCreateContext - return +func bytePtrToString(p *byte) string { + if p == nil { + return "" + } + if *p == 0 { + return "" } - C.fz_register_document_handlers(f.ctx) - - data := (*C.uchar)(C.CBytes(b)) - - stream := C.fz_open_memory(f.ctx, data, C.size_t(len(b))) - if stream == nil { - err = ErrOpenMemory - return + // Find NUL terminator. + n := 0 + for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ { + ptr = unsafe.Pointer(uintptr(ptr) + 1) } - magic := contentType(b) - if magic == "" { - err = ErrOpenMemory - return - } - - cmagic := C.CString(magic) - defer C.free(unsafe.Pointer(cmagic)) - - f.doc = C.fz_open_document_with_stream(f.ctx, cmagic, stream) - if f.doc == nil { - err = ErrOpenDocument - } - - C.fz_drop_stream(f.ctx, stream) - - ret := C.fz_needs_password(f.ctx, f.doc) - v := bool(int(ret) != 0) - if v { - err = ErrNeedsPassword - } - - return -} - -// NewFromReader returns new fitz document from io.Reader. -func NewFromReader(r io.Reader) (f *Document, err error) { - b, e := ioutil.ReadAll(r) - if e != nil { - err = e - return - } - - f, err = NewFromMemory(b) - - return -} - -// NumPage returns total number of pages in document. -func (f *Document) NumPage() int { - return int(C.fz_count_pages(f.ctx, f.doc)) -} - -// Image returns image for given page number. -func (f *Document) Image(pageNumber int) (image.Image, error) { - return f.ImageDPI(pageNumber, 300.0) -} - -// ImageDPI returns image for given page number and DPI. -func (f *Document) ImageDPI(pageNumber int, dpi float64) (image.Image, error) { - f.mtx.Lock() - defer f.mtx.Unlock() - - img := image.RGBA{} - - if pageNumber >= f.NumPage() { - return nil, ErrPageMissing - } - - page := C.fz_load_page(f.ctx, f.doc, C.int(pageNumber)) - defer C.fz_drop_page(f.ctx, page) - - var bounds C.fz_rect - C.fz_bound_page(f.ctx, page, &bounds) - - var ctm C.fz_matrix - C.fz_scale(&ctm, C.float(dpi/72), C.float(dpi/72)) - - var bbox C.fz_irect - C.fz_transform_rect(&bounds, &ctm) - C.fz_round_rect(&bbox, &bounds) - - pixmap := C.fz_new_pixmap_with_bbox(f.ctx, C.fz_device_rgb(f.ctx), &bbox, nil, 1) - if pixmap == nil { - return nil, ErrCreatePixmap - } - - C.fz_clear_pixmap_with_value(f.ctx, pixmap, C.int(0xff)) - defer C.fz_drop_pixmap(f.ctx, pixmap) - - device := C.fz_new_draw_device(f.ctx, &ctm, pixmap) - C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) - defer C.fz_drop_device(f.ctx, device) - - drawMatrix := C.fz_identity - C.fz_run_page(f.ctx, page, device, &drawMatrix, nil) - - C.fz_close_device(f.ctx, device) - - pixels := C.fz_pixmap_samples(f.ctx, pixmap) - if pixels == nil { - return nil, ErrPixmapSamples - } - - img.Pix = C.GoBytes(unsafe.Pointer(pixels), C.int(4*bbox.x1*bbox.y1)) - img.Rect = image.Rect(int(bbox.x0), int(bbox.y0), int(bbox.x1), int(bbox.y1)) - img.Stride = 4 * img.Rect.Max.X - - return &img, nil -} - -// ImagePNG returns image for given page number as PNG bytes. -func (f *Document) ImagePNG(pageNumber int, dpi float64) ([]byte, error) { - f.mtx.Lock() - defer f.mtx.Unlock() - - if pageNumber >= f.NumPage() { - return nil, ErrPageMissing - } - - page := C.fz_load_page(f.ctx, f.doc, C.int(pageNumber)) - defer C.fz_drop_page(f.ctx, page) - - var bounds C.fz_rect - C.fz_bound_page(f.ctx, page, &bounds) - - var ctm C.fz_matrix - C.fz_scale(&ctm, C.float(dpi/72), C.float(dpi/72)) - - var bbox C.fz_irect - C.fz_transform_rect(&bounds, &ctm) - C.fz_round_rect(&bbox, &bounds) - - pixmap := C.fz_new_pixmap_with_bbox(f.ctx, C.fz_device_rgb(f.ctx), &bbox, nil, 1) - if pixmap == nil { - return nil, ErrCreatePixmap - } - - C.fz_clear_pixmap_with_value(f.ctx, pixmap, C.int(0xff)) - defer C.fz_drop_pixmap(f.ctx, pixmap) - - device := C.fz_new_draw_device(f.ctx, &ctm, pixmap) - C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) - defer C.fz_drop_device(f.ctx, device) - - drawMatrix := C.fz_identity - C.fz_run_page(f.ctx, page, device, &drawMatrix, nil) - - C.fz_close_device(f.ctx, device) - - buf := C.fz_new_buffer_from_pixmap_as_png(f.ctx, pixmap, nil) - defer C.fz_drop_buffer(f.ctx, buf) - - size := C.fz_buffer_storage(f.ctx, buf, nil) - str := C.GoStringN(C.fz_string_from_buffer(f.ctx, buf), C.int(size)) - - return []byte(str), nil -} - -// Text returns text for given page number. -func (f *Document) Text(pageNumber int) (string, error) { - f.mtx.Lock() - defer f.mtx.Unlock() - - if pageNumber >= f.NumPage() { - return "", ErrPageMissing - } - - page := C.fz_load_page(f.ctx, f.doc, C.int(pageNumber)) - defer C.fz_drop_page(f.ctx, page) - - var bounds C.fz_rect - C.fz_bound_page(f.ctx, page, &bounds) - - var ctm C.fz_matrix - C.fz_scale(&ctm, C.float(72.0/72), C.float(72.0/72)) - - text := C.fz_new_stext_page(f.ctx, &bounds) - defer C.fz_drop_stext_page(f.ctx, text) - - var opts C.fz_stext_options - opts.flags = 0 - - device := C.fz_new_stext_device(f.ctx, text, &opts) - C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) - defer C.fz_drop_device(f.ctx, device) - - var cookie C.fz_cookie - C.fz_run_page(f.ctx, page, device, &ctm, &cookie) - - C.fz_close_device(f.ctx, device) - - buf := C.fz_new_buffer_from_stext_page(f.ctx, text) - defer C.fz_drop_buffer(f.ctx, buf) - - str := C.GoString(C.fz_string_from_buffer(f.ctx, buf)) - - return str, nil -} - -// HTML returns html for given page number. -func (f *Document) HTML(pageNumber int, header bool) (string, error) { - f.mtx.Lock() - defer f.mtx.Unlock() - - if pageNumber >= f.NumPage() { - return "", ErrPageMissing - } - - page := C.fz_load_page(f.ctx, f.doc, C.int(pageNumber)) - defer C.fz_drop_page(f.ctx, page) - - var bounds C.fz_rect - C.fz_bound_page(f.ctx, page, &bounds) - - var ctm C.fz_matrix - C.fz_scale(&ctm, C.float(72.0/72), C.float(72.0/72)) - - text := C.fz_new_stext_page(f.ctx, &bounds) - defer C.fz_drop_stext_page(f.ctx, text) - - var opts C.fz_stext_options - opts.flags = C.FZ_STEXT_PRESERVE_IMAGES - - device := C.fz_new_stext_device(f.ctx, text, &opts) - C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) - defer C.fz_drop_device(f.ctx, device) - - var cookie C.fz_cookie - C.fz_run_page(f.ctx, page, device, &ctm, &cookie) - - C.fz_close_device(f.ctx, device) - - buf := C.fz_new_buffer(f.ctx, 1024) - defer C.fz_drop_buffer(f.ctx, buf) - - out := C.fz_new_output_with_buffer(f.ctx, buf) - defer C.fz_drop_output(f.ctx, out) - - if header { - C.fz_print_stext_header_as_html(f.ctx, out) - } - C.fz_print_stext_page_as_html(f.ctx, out, text) - if header { - C.fz_print_stext_trailer_as_html(f.ctx, out) - } - - str := C.GoString(C.fz_string_from_buffer(f.ctx, buf)) - - return str, nil -} - -// SVG returns svg document for given page number. -func (f *Document) SVG(pageNumber int) (string, error) { - f.mtx.Lock() - defer f.mtx.Unlock() - - if pageNumber >= f.NumPage() { - return "", ErrPageMissing - } - - page := C.fz_load_page(f.ctx, f.doc, C.int(pageNumber)) - defer C.fz_drop_page(f.ctx, page) - - var bounds C.fz_rect - C.fz_bound_page(f.ctx, page, &bounds) - - var ctm C.fz_matrix - C.fz_scale(&ctm, C.float(72.0/72), C.float(72.0/72)) - C.fz_transform_rect(&bounds, &ctm) - - buf := C.fz_new_buffer(f.ctx, 1024) - defer C.fz_drop_buffer(f.ctx, buf) - - out := C.fz_new_output_with_buffer(f.ctx, buf) - defer C.fz_drop_output(f.ctx, out) - - device := C.fz_new_svg_device(f.ctx, out, bounds.x1-bounds.x0, bounds.y1-bounds.y0, C.FZ_SVG_TEXT_AS_PATH, 1) - C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) - defer C.fz_drop_device(f.ctx, device) - - var cookie C.fz_cookie - C.fz_run_page(f.ctx, page, device, &ctm, &cookie) - - C.fz_close_device(f.ctx, device) - - str := C.GoString(C.fz_string_from_buffer(f.ctx, buf)) - - return str, nil -} - -// ToC returns the table of contents (also known as outline). -func (f *Document) ToC() ([]Outline, error) { - data := make([]Outline, 0) - - outline := C.fz_load_outline(f.ctx, f.doc) - if outline == nil { - return nil, ErrLoadOutline - } - defer C.fz_drop_outline(f.ctx, outline) - - var walk func(outline *C.fz_outline, level int) - - walk = func(outline *C.fz_outline, level int) { - for outline != nil { - res := Outline{} - res.Level = level - res.Title = C.GoString(outline.title) - res.URI = C.GoString(outline.uri) - res.Page = int(outline.page) - res.Top = float64(outline.y) - data = append(data, res) - - if outline.down != nil { - walk(outline.down, level+1) - } - outline = outline.next - } - } - - walk(outline, 1) - return data, nil -} - -// Metadata returns the map with standard metadata. -func (f *Document) Metadata() map[string]string { - data := make(map[string]string) - - lookup := func(key string) string { - ckey := C.CString(key) - defer C.free(unsafe.Pointer(ckey)) - - buf := make([]byte, 256) - C.fz_lookup_metadata(f.ctx, f.doc, ckey, (*C.char)(unsafe.Pointer(&buf[0])), C.int(len(buf))) - - return string(buf) - } - - data["format"] = lookup("format") - data["encryption"] = lookup("encryption") - data["title"] = lookup("info:Title") - data["author"] = lookup("info:Author") - data["subject"] = lookup("info:Subject") - data["keywords"] = lookup("info:Keywords") - data["creator"] = lookup("info:Creator") - data["producer"] = lookup("info:Producer") - data["creationDate"] = lookup("info:CreationDate") - data["modDate"] = lookup("info:modDate") - - return data -} - -// Close closes the underlying fitz document. -func (f *Document) Close() error { - C.fz_drop_document(f.ctx, f.doc) - C.fz_drop_context(f.ctx) - return nil -} - -// contentType returns document MIME type. -func contentType(b []byte) string { - var mtype string - if len(b) > 3 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46 { - mtype = "application/pdf" - } else if len(b) > 57 && b[0] == 0x50 && b[1] == 0x4B && b[2] == 0x3 && b[3] == 0x4 && b[30] == 0x6D && b[31] == 0x69 && b[32] == 0x6D && b[33] == 0x65 && - b[34] == 0x74 && b[35] == 0x79 && b[36] == 0x70 && b[37] == 0x65 && b[38] == 0x61 && b[39] == 0x70 && b[40] == 0x70 && b[41] == 0x6C && - b[42] == 0x69 && b[43] == 0x63 && b[44] == 0x61 && b[45] == 0x74 && b[46] == 0x69 && b[47] == 0x6F && b[48] == 0x6E && b[49] == 0x2F && - b[50] == 0x65 && b[51] == 0x70 && b[52] == 0x75 && b[53] == 0x62 && b[54] == 0x2B && b[55] == 0x7A && b[56] == 0x69 && b[57] == 0x70 { - mtype = "application/epub+zip" - } - return mtype + return string(unsafe.Slice(p, n)) } diff --git a/fitz_cgo.go b/fitz_cgo.go index 011a86f..5cbafa5 100644 --- a/fitz_cgo.go +++ b/fitz_cgo.go @@ -1,19 +1,599 @@ -// +build !extlib +//go:build cgo && !nocgo package fitz /* -#cgo CFLAGS: -Iinclude +#include +#include -#cgo linux,386 LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_386 -lmupdfthird_linux_386 -lm -#cgo linux,!nopie,amd64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_amd64 -lmupdfthird_linux_amd64 -lm -#cgo linux,nopie,amd64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_amd64_nopie -lmupdfthird_linux_amd64_nopie -lm -#cgo linux,!android,arm LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_arm -lmupdfthird_linux_arm -lm -#cgo linux,!android,arm64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_arm64 -lmupdfthird_linux_arm64 -lm -#cgo android,arm LDFLAGS: -L${SRCDIR}/libs -lmupdf_android_arm -lmupdfthird_android_arm -lm -llog -#cgo android,arm64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_android_arm64 -lmupdfthird_android_arm64 -lm -llog -#cgo windows,386 LDFLAGS: -L${SRCDIR}/libs -lmupdf_windows_386 -lmupdfthird_windows_386 -lm -lcomdlg32 -lgdi32 -lmsvcr90 -#cgo windows,amd64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_windows_amd64 -lmupdfthird_windows_amd64 -lm -lcomdlg32 -lgdi32 -#cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_darwin_amd64 -lmupdfthird_darwin_amd64 -lm +const char *fz_version = FZ_VERSION; +#if defined(_WIN32) + typedef unsigned long long store; +#else + typedef unsigned long store; +#endif + +fz_document *open_document(fz_context *ctx, const char *filename) { + fz_document *doc; + + fz_try(ctx) { + doc = fz_open_document(ctx, filename); + } + fz_catch(ctx) { + return NULL; + } + + return doc; +} + +fz_document *open_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stream) { + fz_document *doc; + + fz_try(ctx) { + doc = fz_open_document_with_stream(ctx, magic, stream); + } + fz_catch(ctx) { + return NULL; + } + + return doc; +} + +fz_page *load_page(fz_context *ctx, fz_document *doc, int number) { + fz_page *page; + + fz_try(ctx) { + page = fz_load_page(ctx, doc, number); + } + fz_catch(ctx) { + return NULL; + } + + return page; +} + +int run_page_contents(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie) { + fz_try(ctx) { + fz_run_page_contents(ctx, page, dev, transform, cookie); + } + fz_catch(ctx) { + return 0; + } + + return 1; +} */ import "C" + +import ( + "image" + "io" + "os" + "path/filepath" + "sync" + "unsafe" +) + +// Document represents fitz document. +type Document struct { + ctx *C.struct_fz_context + data []byte // binds data to the Document lifecycle avoiding premature GC + doc *C.struct_fz_document + mtx sync.Mutex + stream *C.fz_stream +} + +// New returns new fitz document. +func New(filename string) (f *Document, err error) { + f = &Document{} + + filename, err = filepath.Abs(filename) + if err != nil { + return + } + + if _, e := os.Stat(filename); e != nil { + err = ErrNoSuchFile + return + } + + f.ctx = (*C.struct_fz_context)(unsafe.Pointer(C.fz_new_context_imp(nil, nil, C.store(MaxStore), C.fz_version))) + if f.ctx == nil { + err = ErrCreateContext + return + } + + C.fz_register_document_handlers(f.ctx) + + cfilename := C.CString(filename) + defer C.free(unsafe.Pointer(cfilename)) + + f.doc = C.open_document(f.ctx, cfilename) + if f.doc == nil { + err = ErrOpenDocument + return + } + + ret := C.fz_needs_password(f.ctx, f.doc) + v := int(ret) != 0 + if v { + err = ErrNeedsPassword + } + + return +} + +// NewFromMemory returns new fitz document from byte slice. +func NewFromMemory(b []byte) (f *Document, err error) { + if len(b) == 0 { + return nil, ErrEmptyBytes + } + f = &Document{} + + f.ctx = (*C.struct_fz_context)(unsafe.Pointer(C.fz_new_context_imp(nil, nil, C.store(MaxStore), C.fz_version))) + if f.ctx == nil { + err = ErrCreateContext + return + } + + C.fz_register_document_handlers(f.ctx) + + f.stream = C.fz_open_memory(f.ctx, (*C.uchar)(&b[0]), C.size_t(len(b))) + if f.stream == nil { + err = ErrOpenMemory + return + } + + magic := contentType(b) + if magic == "" { + err = ErrOpenMemory + return + } + + f.data = b + + cmagic := C.CString(magic) + defer C.free(unsafe.Pointer(cmagic)) + + f.doc = C.open_document_with_stream(f.ctx, cmagic, f.stream) + if f.doc == nil { + err = ErrOpenDocument + } + + ret := C.fz_needs_password(f.ctx, f.doc) + v := int(ret) != 0 + if v { + err = ErrNeedsPassword + } + + return +} + +// NewFromReader returns new fitz document from io.Reader. +func NewFromReader(r io.Reader) (f *Document, err error) { + b, e := io.ReadAll(r) + if e != nil { + err = e + return + } + + f, err = NewFromMemory(b) + + return +} + +// NumPage returns total number of pages in document. +func (f *Document) NumPage() int { + return int(C.fz_count_pages(f.ctx, f.doc)) +} + +// Image returns image for given page number. +func (f *Document) Image(pageNumber int) (*image.RGBA, error) { + return f.ImageDPI(pageNumber, 300.0) +} + +// ImageDPI returns image for given page number and DPI. +func (f *Document) ImageDPI(pageNumber int, dpi float64) (*image.RGBA, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return nil, ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return nil, ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + var bounds C.fz_rect + bounds = C.fz_bound_page(f.ctx, page) + + var ctm C.fz_matrix + ctm = C.fz_scale(C.float(dpi/72), C.float(dpi/72)) + + var bbox C.fz_irect + bounds = C.fz_transform_rect(bounds, ctm) + bbox = C.fz_round_rect(bounds) + + pixmap := C.fz_new_pixmap_with_bbox(f.ctx, C.fz_device_rgb(f.ctx), bbox, nil, 1) + if pixmap == nil { + return nil, ErrCreatePixmap + } + + C.fz_clear_pixmap_with_value(f.ctx, pixmap, C.int(0xff)) + defer C.fz_drop_pixmap(f.ctx, pixmap) + + device := C.fz_new_draw_device(f.ctx, ctm, pixmap) + C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) + defer C.fz_drop_device(f.ctx, device) + + drawMatrix := C.fz_identity + ret := C.run_page_contents(f.ctx, page, device, drawMatrix, nil) + if ret == 0 { + return nil, ErrRunPageContents + } + + C.fz_close_device(f.ctx, device) + + pixels := C.fz_pixmap_samples(f.ctx, pixmap) + if pixels == nil { + return nil, ErrPixmapSamples + } + + img := image.NewRGBA(image.Rect(int(bbox.x0), int(bbox.y0), int(bbox.x1), int(bbox.y1))) + copy(img.Pix, C.GoBytes(unsafe.Pointer(pixels), C.int(4*bbox.x1*bbox.y1))) + + return img, nil +} + +// ImagePNG returns image for given page number as PNG bytes. +func (f *Document) ImagePNG(pageNumber int, dpi float64) ([]byte, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return nil, ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return nil, ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + var bounds C.fz_rect + bounds = C.fz_bound_page(f.ctx, page) + + var ctm C.fz_matrix + ctm = C.fz_scale(C.float(dpi/72), C.float(dpi/72)) + + var bbox C.fz_irect + bounds = C.fz_transform_rect(bounds, ctm) + bbox = C.fz_round_rect(bounds) + + pixmap := C.fz_new_pixmap_with_bbox(f.ctx, C.fz_device_rgb(f.ctx), bbox, nil, 1) + if pixmap == nil { + return nil, ErrCreatePixmap + } + + C.fz_clear_pixmap_with_value(f.ctx, pixmap, C.int(0xff)) + defer C.fz_drop_pixmap(f.ctx, pixmap) + + device := C.fz_new_draw_device(f.ctx, ctm, pixmap) + C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) + defer C.fz_drop_device(f.ctx, device) + + drawMatrix := C.fz_identity + ret := C.run_page_contents(f.ctx, page, device, drawMatrix, nil) + if ret == 0 { + return nil, ErrRunPageContents + } + + C.fz_close_device(f.ctx, device) + + buf := C.fz_new_buffer_from_pixmap_as_png(f.ctx, pixmap, C.fz_default_color_params) + defer C.fz_drop_buffer(f.ctx, buf) + + size := C.fz_buffer_storage(f.ctx, buf, nil) + str := C.GoStringN(C.fz_string_from_buffer(f.ctx, buf), C.int(size)) + + return []byte(str), nil +} + +// Links returns slice of links for given page number. +func (f *Document) Links(pageNumber int) ([]Link, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return nil, ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return nil, ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + links := C.fz_load_links(f.ctx, page) + defer C.fz_drop_link(f.ctx, links) + + linkCount := 0 + for currLink := links; currLink != nil; currLink = currLink.next { + linkCount++ + } + + if linkCount == 0 { + return nil, nil + } + + gLinks := make([]Link, linkCount) + + currLink := links + for i := 0; i < linkCount; i++ { + gLinks[i] = Link{ + URI: C.GoString(currLink.uri), + } + currLink = currLink.next + } + + return gLinks, nil +} + +// Text returns text for given page number. +func (f *Document) Text(pageNumber int) (string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return "", ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return "", ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + var bounds C.fz_rect + bounds = C.fz_bound_page(f.ctx, page) + + var ctm C.fz_matrix + ctm = C.fz_scale(C.float(72.0/72), C.float(72.0/72)) + + text := C.fz_new_stext_page(f.ctx, bounds) + defer C.fz_drop_stext_page(f.ctx, text) + + var opts C.fz_stext_options + opts.flags = 0 + + device := C.fz_new_stext_device(f.ctx, text, &opts) + C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) + defer C.fz_drop_device(f.ctx, device) + + var cookie C.fz_cookie + ret := C.run_page_contents(f.ctx, page, device, ctm, &cookie) + if ret == 0 { + return "", ErrRunPageContents + } + + C.fz_close_device(f.ctx, device) + + buf := C.fz_new_buffer_from_stext_page(f.ctx, text) + defer C.fz_drop_buffer(f.ctx, buf) + + str := C.GoString(C.fz_string_from_buffer(f.ctx, buf)) + + return str, nil +} + +// HTML returns html for given page number. +func (f *Document) HTML(pageNumber int, header bool) (string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return "", ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return "", ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + var bounds C.fz_rect + bounds = C.fz_bound_page(f.ctx, page) + + var ctm C.fz_matrix + ctm = C.fz_scale(C.float(72.0/72), C.float(72.0/72)) + + text := C.fz_new_stext_page(f.ctx, bounds) + defer C.fz_drop_stext_page(f.ctx, text) + + var opts C.fz_stext_options + opts.flags = C.FZ_STEXT_PRESERVE_IMAGES + + device := C.fz_new_stext_device(f.ctx, text, &opts) + C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) + defer C.fz_drop_device(f.ctx, device) + + var cookie C.fz_cookie + ret := C.run_page_contents(f.ctx, page, device, ctm, &cookie) + if ret == 0 { + return "", ErrRunPageContents + } + + C.fz_close_device(f.ctx, device) + + buf := C.fz_new_buffer(f.ctx, 1024) + defer C.fz_drop_buffer(f.ctx, buf) + + out := C.fz_new_output_with_buffer(f.ctx, buf) + defer C.fz_drop_output(f.ctx, out) + + if header { + C.fz_print_stext_header_as_html(f.ctx, out) + } + C.fz_print_stext_page_as_html(f.ctx, out, text, C.int(pageNumber)) + if header { + C.fz_print_stext_trailer_as_html(f.ctx, out) + } + + C.fz_close_output(f.ctx, out) + + str := C.GoString(C.fz_string_from_buffer(f.ctx, buf)) + + return str, nil +} + +// SVG returns svg document for given page number. +func (f *Document) SVG(pageNumber int) (string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return "", ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return "", ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + var bounds C.fz_rect + bounds = C.fz_bound_page(f.ctx, page) + + var ctm C.fz_matrix + ctm = C.fz_scale(C.float(72.0/72), C.float(72.0/72)) + bounds = C.fz_transform_rect(bounds, ctm) + + buf := C.fz_new_buffer(f.ctx, 1024) + defer C.fz_drop_buffer(f.ctx, buf) + + out := C.fz_new_output_with_buffer(f.ctx, buf) + defer C.fz_drop_output(f.ctx, out) + + device := C.fz_new_svg_device(f.ctx, out, bounds.x1-bounds.x0, bounds.y1-bounds.y0, C.FZ_SVG_TEXT_AS_PATH, 1) + C.fz_enable_device_hints(f.ctx, device, C.FZ_NO_CACHE) + defer C.fz_drop_device(f.ctx, device) + + var cookie C.fz_cookie + ret := C.run_page_contents(f.ctx, page, device, ctm, &cookie) + if ret == 0 { + return "", ErrRunPageContents + } + + C.fz_close_device(f.ctx, device) + C.fz_close_output(f.ctx, out) + + str := C.GoString(C.fz_string_from_buffer(f.ctx, buf)) + + return str, nil +} + +// ToC returns the table of contents (also known as outline). +func (f *Document) ToC() ([]Outline, error) { + data := make([]Outline, 0) + + outline := C.fz_load_outline(f.ctx, f.doc) + if outline == nil { + return nil, ErrLoadOutline + } + defer C.fz_drop_outline(f.ctx, outline) + + var walk func(outline *C.fz_outline, level int) + + walk = func(outline *C.fz_outline, level int) { + for outline != nil { + res := Outline{} + res.Level = level + res.Title = C.GoString(outline.title) + res.URI = C.GoString(outline.uri) + res.Page = int(outline.page.page) + res.Top = float64(outline.y) + data = append(data, res) + + if outline.down != nil { + walk(outline.down, level+1) + } + outline = outline.next + } + } + + walk(outline, 1) + return data, nil +} + +// Metadata returns the map with standard metadata. +func (f *Document) Metadata() map[string]string { + data := make(map[string]string) + + lookup := func(key string) string { + ckey := C.CString(key) + defer C.free(unsafe.Pointer(ckey)) + + buf := make([]byte, 256) + C.fz_lookup_metadata(f.ctx, f.doc, ckey, (*C.char)(unsafe.Pointer(&buf[0])), C.int(len(buf))) + + return string(buf) + } + + data["format"] = lookup("format") + data["encryption"] = lookup("encryption") + data["title"] = lookup("info:Title") + data["author"] = lookup("info:Author") + data["subject"] = lookup("info:Subject") + data["keywords"] = lookup("info:Keywords") + data["creator"] = lookup("info:Creator") + data["producer"] = lookup("info:Producer") + data["creationDate"] = lookup("info:CreationDate") + data["modDate"] = lookup("info:modDate") + + return data +} + +// Bound gives the Bounds of a given Page in the document. +func (f *Document) Bound(pageNumber int) (image.Rectangle, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return image.Rectangle{}, ErrPageMissing + } + + page := C.load_page(f.ctx, f.doc, C.int(pageNumber)) + if page == nil { + return image.Rectangle{}, ErrLoadPage + } + + defer C.fz_drop_page(f.ctx, page) + + var bounds C.fz_rect + bounds = C.fz_bound_page(f.ctx, page) + + return image.Rect(int(bounds.x0), int(bounds.y0), int(bounds.x1), int(bounds.y1)), nil +} + +// Close closes the underlying fitz document. +func (f *Document) Close() error { + if f.stream != nil { + C.fz_drop_stream(f.ctx, f.stream) + } + + C.fz_drop_document(f.ctx, f.doc) + C.fz_drop_context(f.ctx) + + f.data = nil + + return nil +} diff --git a/fitz_cgo_cgo.go b/fitz_cgo_cgo.go new file mode 100644 index 0000000..e99becb --- /dev/null +++ b/fitz_cgo_cgo.go @@ -0,0 +1,18 @@ +//go:build cgo && !nocgo && !extlib + +package fitz + +/* +#cgo CFLAGS: -Iinclude + +#cgo linux,amd64,!musl LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_amd64 -lmupdfthird_linux_amd64 -lm +#cgo linux,amd64,musl LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_amd64_musl -lmupdfthird_linux_amd64_musl -lm +#cgo linux,!android,arm64,!musl LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_arm64 -lmupdfthird_linux_arm64 -lm +#cgo linux,!android,arm64,musl LDFLAGS: -L${SRCDIR}/libs -lmupdf_linux_arm64_musl -lmupdfthird_linux_arm64_musl -lm +#cgo android,arm64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_android_arm64 -lmupdfthird_android_arm64 -lm -llog +#cgo windows,amd64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_windows_amd64 -lmupdfthird_windows_amd64 -lm -lcomdlg32 -lgdi32 +#cgo windows,arm64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_windows_arm64 -lmupdfthird_windows_arm64 -lm -lcomdlg32 -lgdi32 +#cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_darwin_amd64 -lmupdfthird_darwin_amd64 -lm +#cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/libs -lmupdf_darwin_arm64 -lmupdfthird_darwin_arm64 -lm +*/ +import "C" diff --git a/fitz_cgo_extlib.go b/fitz_cgo_extlib.go index 118b034..96a20ed 100644 --- a/fitz_cgo_extlib.go +++ b/fitz_cgo_extlib.go @@ -1,10 +1,10 @@ -// +build extlib +//go:build cgo && !nocgo && extlib && !pkgconfig package fitz /* #cgo !static LDFLAGS: -lmupdf -lm -#cgo static LDFLAGS: -lmupdf -lm -lmupdfthird +#cgo static LDFLAGS: -lmupdf -lm -lmupdf-third #cgo android LDFLAGS: -llog #cgo windows LDFLAGS: -lcomdlg32 -lgdi32 */ diff --git a/fitz_cgo_extlib_pkgconfig.go b/fitz_cgo_extlib_pkgconfig.go new file mode 100644 index 0000000..fa48212 --- /dev/null +++ b/fitz_cgo_extlib_pkgconfig.go @@ -0,0 +1,9 @@ +//go:build cgo && !nocgo && extlib && pkgconfig + +package fitz + +/* +#cgo !static pkg-config: mupdf +#cgo static pkg-config: --static mupdf +*/ +import "C" diff --git a/fitz_content_types.go b/fitz_content_types.go new file mode 100644 index 0000000..b7c599e --- /dev/null +++ b/fitz_content_types.go @@ -0,0 +1,383 @@ +package fitz + +import ( + "bytes" + "encoding/binary" +) + +// contentType returns document MIME type. +func contentType(b []byte) string { + l := len(b) + // for file length shortcuts see https://github.com/mathiasbynens/small + switch { + case l < 8: + return "" + case isPAM(b): + return "image/x-portable-arbitrarymap" + case isPBM(b): + return "image/x-portable-bitmap" + case isPFM(b): + return "image/x-portable-floatmap" + case isPGM(b): + return "image/x-portable-greymap" + case isPPM(b): + return "image/x-portable-pixmap" + case isGIF(b): + return "image/gif" + case l < 16: + return "" + case isBMP(b): + return "image/bmp" + case isJBIG2(b): + // file header + segment header = 24 bytes + return "image/x-jb2" + case l < 32: + return "" + case isTIFF(b): + return "image/tiff" + case isSVG(b): + // min of 41 bytes: + return "image/svg+xml" + case l < 64: + return "" + case isJPEG(b): + return "image/jpeg" + case isPNG(b): + return "image/png" + case isJPEG2000(b): + return "image/jp2" + case isJPEGXR(b): + return "image/vnd.ms-photo" + case isPDF(b): + return "application/pdf" + case isPSD(b): + return "image/vnd.adobe.photoshop" + case isZIP(b): + switch { + case isDOCX(b): + return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + case isXLSX(b): + return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + case isPPTX(b): + return "application/vnd.openxmlformats-officedocument.presentationml.presentation" + case isEPUB(b): + return "application/epub+zip" + case isXPS(b): + return "application/oxps" + default: + // fitz will consider it a Comic Book Archive + // must contain at least one image, i.e. >64 bytes + return "application/zip" + } + case isXML(b): + // fitz will consider it an FB2 + // minimal valid FB2 w/o content is >64 bytes + return "text/xml" + case isMOBI(b): + return "application/x-mobipocket-ebook" + default: + return "" + } +} + +func isBMP(b []byte) bool { + return b[0] == 0x42 && b[1] == 0x4D +} + +func isGIF(b []byte) bool { + return b[0] == 0x47 && b[1] == 0x49 && b[2] == 0x46 && b[3] == 0x38 +} + +func isJBIG2(b []byte) bool { + return b[0] == 0x97 && b[1] == 0x4A && b[2] == 0x42 && b[3] == 0x32 && + b[4] == 0x0D && b[5] == 0x0A && b[6] == 0x1A && b[7] == 0x0A +} + +func isJPEG(b []byte) bool { + return b[0] == 0xFF && b[1] == 0xD8 && b[2] == 0xFF +} + +func isJPEG2000(b []byte) bool { + switch { + case b[0] == 0xFF && b[1] == 0x4F && b[2] == 0xFF && b[3] == 0x51: + return true + default: + return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x00 && b[3] == 0x0C && + b[4] == 0x6A && b[5] == 0x50 && b[6] == 0x20 && b[7] == 0x20 && + b[8] == 0x0D && b[9] == 0x0A && b[10] == 0x87 && b[11] == 0x0A + } +} + +func isJPEGXR(b []byte) bool { + return b[0] == 0x49 && b[1] == 0x49 && b[2] == 0xBC +} + +func isPAM(b []byte) bool { + return b[0] == 0x50 && b[1] == 0x37 && b[2] == 0x0A +} + +func isPBM(b []byte) bool { + return b[0] == 0x50 && (b[1] == 0x31 || b[1] == 0x34) && b[2] == 0x0A +} + +func isPFM(b []byte) bool { + return b[0] == 0x50 && (b[1] == 0x46 || b[1] == 0x66) && b[2] == 0x0A +} + +func isPGM(b []byte) bool { + return b[0] == 0x50 && (b[1] == 0x32 || b[1] == 0x35) && b[2] == 0x0A +} + +func isPPM(b []byte) bool { + return b[0] == 0x50 && (b[1] == 0x33 || b[1] == 0x36) && b[2] == 0x0A +} + +func isPNG(b []byte) bool { + return b[0] == 0x89 && b[1] == 0x50 && b[2] == 0x4E && b[3] == 0x47 && + b[4] == 0x0D && b[5] == 0x0A && b[6] == 0x1A && b[7] == 0x0A +} + +func isTIFF(b []byte) bool { + return b[0] == 0x49 && b[1] == 0x49 && b[2] == 0x2A && b[3] == 0x00 || + b[0] == 0x4D && b[1] == 0x4D && b[2] == 0x00 && b[3] == 0x2A +} + +// PDF magic number 25 50 44 46 = "%PDF". +func isPDF(b []byte) bool { + return b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46 +} + +// PSD magic number 38 42 50 53 = "8BPS" +func isPSD(b []byte) bool { + return b[0] == 0x38 && b[1] == 0x42 && b[2] == 0x50 && b[3] == 0x53 +} + +// Non-empty ZIP archive magic number 50 4B 03 04. +func isZIP(b []byte) bool { + return b[0] == 0x50 && b[1] == 0x4B && b[2] == 0x03 && b[3] == 0x04 +} + +// Looks for a file named "mimetype" containing the ASCII string "application/epub+zip". +// The file must be uncompressed and be the first file within the archive. +func isEPUB(b []byte) bool { + return b[30] == 0x6D && b[31] == 0x69 && b[32] == 0x6D && b[33] == 0x65 && + b[34] == 0x74 && b[35] == 0x79 && b[36] == 0x70 && b[37] == 0x65 && + b[38] == 0x61 && b[39] == 0x70 && b[40] == 0x70 && b[41] == 0x6C && + b[42] == 0x69 && b[43] == 0x63 && b[44] == 0x61 && b[45] == 0x74 && + b[46] == 0x69 && b[47] == 0x6F && b[48] == 0x6E && b[49] == 0x2F && + b[50] == 0x65 && b[51] == 0x70 && b[52] == 0x75 && b[53] == 0x62 && + b[54] == 0x2B && b[55] == 0x7A && b[56] == 0x69 && b[57] == 0x70 +} + +// MOBI contains either BOOKMOBI or TEXtREAd string after a 60 bytes offset. +// The magic string is then followed by at least 10 bytes of information. +func isMOBI(b []byte) bool { + switch { + case len(b) < 78: + return false + case b[60] == 0x42 && b[61] == 0x4F && b[62] == 0x4F && b[63] == 0x4B && + b[64] == 0x4D && b[65] == 0x4F && b[66] == 0x42 && b[67] == 0x49: + return true + case b[60] == 0x54 && b[61] == 0x45 && b[62] == 0x58 && b[63] == 0x74 && + b[64] == 0x52 && b[65] == 0x45 && b[66] == 0x41 && b[67] == 0x64: + return true + default: + return false + } +} + +// Looks for a file named "[Content_Types].xml" at the root of a ZIP archive. +// MS Office apps put this file first within the archive enabling for fast detection. +func isXPS(b []byte) bool { + return b[30] == 0x5B && b[31] == 0x43 && b[32] == 0x6F && b[33] == 0x6E && + b[34] == 0x74 && b[35] == 0x65 && b[36] == 0x6E && b[37] == 0x74 && + b[38] == 0x5F && b[39] == 0x54 && b[40] == 0x79 && b[41] == 0x70 && + b[42] == 0x65 && b[43] == 0x73 && b[44] == 0x5D && b[45] == 0x2E && + b[46] == 0x78 && b[47] == 0x6D && b[48] == 0x6C +} + +// Checks for " + goto ParseSVGText + } + } +} + +// Checks for " len(slice) { + return false + } + + s := slice[startOffset : startOffset+sl] + for i := range s { + if subSlice[i] != s[i] { + return false + } + } + + return true +} + +func checkMSOoml(buf []byte, offset int) (typ docType, ok bool) { + ok = true + + switch { + case compareBytes(buf, []byte("word/"), offset): + typ = typeDocx + case compareBytes(buf, []byte("ppt/"), offset): + typ = typePptx + case compareBytes(buf, []byte("xl/"), offset): + typ = typeXlsx + default: + ok = false + } + + return +} + +func search(buf []byte, start, rangeNum int) int { + length := len(buf) + end := start + rangeNum + signature := []byte{'P', 'K', 0x03, 0x04} + + if end > length { + end = length + } + + if start >= end { + return -1 + } + + return bytes.Index(buf[start:end], signature) +} diff --git a/fitz_content_types_test.go b/fitz_content_types_test.go new file mode 100644 index 0000000..7400ea8 --- /dev/null +++ b/fitz_content_types_test.go @@ -0,0 +1,173 @@ +package fitz + +import ( + _ "embed" + "testing" +) + +func testContentType(want string, b []byte, t *testing.T) { + if got := contentType(b); got != want { + t.Errorf("contentType([]byte) = '%v'; want '%v'", got, want) + } +} + +//go:embed testdata/test.bmp +var bmp []byte + +func TestContentTypeBMP(t *testing.T) { + testContentType("image/bmp", bmp, t) +} + +//go:embed testdata/test.epub +var epub []byte + +func TestContentTypeEPUB(t *testing.T) { + testContentType("application/epub+zip", epub, t) +} + +//go:embed testdata/test.mobi +var mobi []byte + +func TestContentTypeMOBI(t *testing.T) { + testContentType("application/x-mobipocket-ebook", mobi, t) +} + +//go:embed testdata/test.cbz +var cbz []byte + +func TestContentTypeCBZ(t *testing.T) { + testContentType("application/zip", cbz, t) +} + +//go:embed testdata/test.fb2 +var fb2 []byte + +func TestContentTypeFB2(t *testing.T) { + testContentType("text/xml", fb2, t) +} + +//go:embed testdata/test.gif +var gif []byte + +func TestContentTypeGIF(t *testing.T) { + testContentType("image/gif", gif, t) +} + +//go:embed testdata/test.jb2 +var jb2 []byte + +func TestContentTypeJBIG2(t *testing.T) { + testContentType("image/x-jb2", jb2, t) +} + +//go:embed testdata/test.jpg +var jpg []byte + +func TestContentTypeJPEG(t *testing.T) { + testContentType("image/jpeg", jpg, t) +} + +//go:embed testdata/test.jp2 +var jp2 []byte + +func TestContentTypeJPEG2000(t *testing.T) { + testContentType("image/jp2", jp2, t) +} + +//go:embed testdata/test.jxr +var jxr []byte + +func TestContentTypeJPEGXR(t *testing.T) { + testContentType("image/vnd.ms-photo", jxr, t) +} + +//go:embed testdata/test.pam +var pam []byte + +func TestContentTypePAM(t *testing.T) { + testContentType("image/x-portable-arbitrarymap", pam, t) +} + +//go:embed testdata/test.pbm +var pbm []byte + +func TestContentTypePBM(t *testing.T) { + testContentType("image/x-portable-bitmap", pbm, t) +} + +//go:embed testdata/test.pdf +var pdf []byte + +func TestContentTypePDF(t *testing.T) { + testContentType("application/pdf", pdf, t) +} + +//go:embed testdata/test.psd +var psd []byte + +func TestContentTypePSD(t *testing.T) { + testContentType("image/vnd.adobe.photoshop", psd, t) +} + +//go:embed testdata/test.pfm +var pfm []byte + +func TestContentTypePFM(t *testing.T) { + testContentType("image/x-portable-floatmap", pfm, t) +} + +//go:embed testdata/test.pgm +var pgm []byte + +func TestContentTypePGM(t *testing.T) { + testContentType("image/x-portable-greymap", pgm, t) +} + +//go:embed testdata/test.ppm +var ppm []byte + +func TestContentTypePPM(t *testing.T) { + testContentType("image/x-portable-pixmap", ppm, t) +} + +//go:embed testdata/test.svg +var svg []byte + +func TestContentTypeSVG(t *testing.T) { + testContentType("image/svg+xml", svg, t) +} + +//go:embed testdata/test.tif +var tif []byte + +func TestContentTypeTIFF(t *testing.T) { + testContentType("image/tiff", tif, t) +} + +//go:embed testdata/test.xps +var xps []byte + +func TestContentTypeXPS(t *testing.T) { + testContentType("application/oxps", xps, t) +} + +//go:embed testdata/test.docx +var docx []byte + +func TestContentTypeDOCX(t *testing.T) { + testContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document", docx, t) +} + +//go:embed testdata/test.xlsx +var xlsx []byte + +func TestContentTypeXLSX(t *testing.T) { + testContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", xlsx, t) +} + +//go:embed testdata/test.pptx +var pptx []byte + +func TestContentTypePPTX(t *testing.T) { + testContentType("application/vnd.openxmlformats-officedocument.presentationml.presentation", pptx, t) +} diff --git a/fitz_nocgo.go b/fitz_nocgo.go new file mode 100644 index 0000000..bde2765 --- /dev/null +++ b/fitz_nocgo.go @@ -0,0 +1,1097 @@ +//go:build !cgo || nocgo + +package fitz + +import ( + "image" + "io" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "unsafe" + + "github.com/ebitengine/purego" + "github.com/jupiterrider/ffi" +) + +// Document represents fitz document. +type Document struct { + ctx *fzContext + data []byte // binds data to the Document lifecycle avoiding premature GC + doc *fzDocument + mtx sync.Mutex + stream *fzStream +} + +// New returns new fitz document. +func New(filename string) (f *Document, err error) { + f = &Document{} + + filename, err = filepath.Abs(filename) + if err != nil { + return + } + + if _, e := os.Stat(filename); e != nil { + err = ErrNoSuchFile + return + } + + f.ctx = fzNewContextImp(nil, nil, uint64(MaxStore), FzVersion) + if f.ctx == nil { + err = ErrCreateContext + return + } + + fzRegisterDocumentHandlers(f.ctx) + + f.doc = fzOpenDocument(f.ctx, filename) + if f.doc == nil { + err = ErrOpenDocument + return + } + + ret := fzNeedsPassword(f.ctx, f.doc) + v := int(ret) != 0 + if v { + err = ErrNeedsPassword + } + + return +} + +// NewFromMemory returns new fitz document from byte slice. +func NewFromMemory(b []byte) (f *Document, err error) { + if len(b) == 0 { + return nil, ErrEmptyBytes + } + f = &Document{} + + f.ctx = fzNewContextImp(nil, nil, uint64(MaxStore), FzVersion) + if f.ctx == nil { + err = ErrCreateContext + return + } + + fzRegisterDocumentHandlers(f.ctx) + + f.stream = fzOpenMemory(f.ctx, unsafe.SliceData(b), uint64(len(b))) + if f.stream == nil { + err = ErrOpenMemory + return + } + + magic := contentType(b) + if magic == "" { + err = ErrOpenMemory + return + } + + f.data = b + + f.doc = fzOpenDocumentWithStream(f.ctx, magic, f.stream) + if f.doc == nil { + err = ErrOpenDocument + } + + ret := fzNeedsPassword(f.ctx, f.doc) + v := int(ret) != 0 + if v { + err = ErrNeedsPassword + } + + return +} + +// NewFromReader returns new fitz document from io.Reader. +func NewFromReader(r io.Reader) (f *Document, err error) { + b, e := io.ReadAll(r) + if e != nil { + err = e + return + } + + f, err = NewFromMemory(b) + + return +} + +// NumPage returns total number of pages in document. +func (f *Document) NumPage() int { + return fzCountPages(f.ctx, f.doc) +} + +// Image returns image for given page number. +func (f *Document) Image(pageNumber int) (*image.RGBA, error) { + return f.ImageDPI(pageNumber, 300.0) +} + +// ImageDPI returns image for given page number and DPI. +func (f *Document) ImageDPI(pageNumber int, dpi float64) (*image.RGBA, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return nil, ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return nil, ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + var bounds fzRect + bounds = boundPage(f.ctx, page) + + var ctm fzMatrix + ctm = scale(float32(dpi/72), float32(dpi/72)) + + var bbox fzIRect + bounds = transformRect(bounds, ctm) + bbox = roundRect(bounds) + + pixmap := fzNewPixmap(f.ctx, fzDeviceRgb(f.ctx), int(bbox.X1), int(bbox.Y1), nil, 1) + if pixmap == nil { + return nil, ErrCreatePixmap + } + + fzClearPixmapWithValue(f.ctx, pixmap, 0xff) + defer fzDropPixmap(f.ctx, pixmap) + + device := newDrawDevice(f.ctx, ctm, pixmap) + fzEnableDeviceHints(f.ctx, device, fzNoCache) + defer fzDropDevice(f.ctx, device) + + runPageContents(f.ctx, page, device, fzIdentity) + + fzCloseDevice(f.ctx, device) + + pixels := fzPixmapSamples(f.ctx, pixmap) + if pixels == nil { + return nil, ErrPixmapSamples + } + + img := image.NewRGBA(image.Rect(int(bbox.X0), int(bbox.Y0), int(bbox.X1), int(bbox.Y1))) + copy(img.Pix, unsafe.Slice(pixels, 4*bbox.X1*bbox.Y1)) + + return img, nil +} + +// ImagePNG returns image for given page number as PNG bytes. +func (f *Document) ImagePNG(pageNumber int, dpi float64) ([]byte, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return nil, ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return nil, ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + var bounds fzRect + bounds = boundPage(f.ctx, page) + + var ctm fzMatrix + ctm = scale(float32(dpi/72), float32(dpi/72)) + + var bbox fzIRect + bounds = transformRect(bounds, ctm) + bbox = roundRect(bounds) + + pixmap := fzNewPixmap(f.ctx, fzDeviceRgb(f.ctx), int(bbox.X1), int(bbox.Y1), nil, 1) + if pixmap == nil { + return nil, ErrCreatePixmap + } + + fzClearPixmapWithValue(f.ctx, pixmap, 0xff) + defer fzDropPixmap(f.ctx, pixmap) + + device := newDrawDevice(f.ctx, ctm, pixmap) + fzEnableDeviceHints(f.ctx, device, fzNoCache) + defer fzDropDevice(f.ctx, device) + + runPageContents(f.ctx, page, device, fzIdentity) + + fzCloseDevice(f.ctx, device) + + params := fzColorParams{1, 1, 0, 0} + buf := newBufferFromPixmapAsPNG(f.ctx, pixmap, params) + defer fzDropBuffer(f.ctx, buf) + + size := fzBufferStorage(f.ctx, buf, nil) + + ret := make([]byte, size) + copy(ret, unsafe.Slice(fzStringFromBuffer(f.ctx, buf), size)) + + return ret, nil +} + +// Links returns slice of links for given page number. +func (f *Document) Links(pageNumber int) ([]Link, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return nil, ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return nil, ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + links := fzLoadLinks(f.ctx, page) + defer fzDropLink(f.ctx, links) + + linkCount := 0 + for currLink := links; currLink != nil; currLink = currLink.Next { + linkCount++ + } + + if linkCount == 0 { + return nil, nil + } + + gLinks := make([]Link, linkCount) + + currLink := links + for i := 0; i < linkCount; i++ { + gLinks[i] = Link{ + URI: bytePtrToString((*uint8)(unsafe.Pointer(currLink.Uri))), + } + currLink = currLink.Next + } + + return gLinks, nil +} + +// Text returns text for given page number. +func (f *Document) Text(pageNumber int) (string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return "", ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return "", ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + var bounds fzRect + bounds = boundPage(f.ctx, page) + + var ctm fzMatrix + ctm = scale(float32(72.0/72), float32(72.0/72)) + + text := newStextPage(f.ctx, bounds) + defer fzDropStextPage(f.ctx, text) + + var opts fzStextOptions + opts.Flags = 0 + + device := fzNewStextDevice(f.ctx, text, &opts) + fzEnableDeviceHints(f.ctx, device, fzNoCache) + defer fzDropDevice(f.ctx, device) + + runPageContents(f.ctx, page, device, ctm) + + fzCloseDevice(f.ctx, device) + + buf := fzNewBufferFromStextPage(f.ctx, text) + defer fzDropBuffer(f.ctx, buf) + + ret := fzStringFromBuffer(f.ctx, buf) + + return bytePtrToString(ret), nil +} + +// HTML returns html for given page number. +func (f *Document) HTML(pageNumber int, header bool) (string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return "", ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return "", ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + var bounds fzRect + bounds = boundPage(f.ctx, page) + + var ctm fzMatrix + ctm = scale(float32(72.0/72), float32(72.0/72)) + + text := newStextPage(f.ctx, bounds) + defer fzDropStextPage(f.ctx, text) + + var opts fzStextOptions + opts.Flags = fzStextPreserveImages + + device := fzNewStextDevice(f.ctx, text, &opts) + fzEnableDeviceHints(f.ctx, device, fzNoCache) + defer fzDropDevice(f.ctx, device) + + runPageContents(f.ctx, page, device, ctm) + + fzCloseDevice(f.ctx, device) + + buf := fzNewBuffer(f.ctx, 1024) + defer fzDropBuffer(f.ctx, buf) + + out := fzNewOutputWithBuffer(f.ctx, buf) + defer fzDropOutput(f.ctx, out) + + if header { + fzPrintStextHeaderAsHTML(f.ctx, out) + } + fzPrintStextPageAsHTML(f.ctx, out, text, pageNumber) + if header { + fzPrintStextTrailerAsHTML(f.ctx, out) + } + + fzCloseOutput(f.ctx, out) + + ret := fzStringFromBuffer(f.ctx, buf) + + return bytePtrToString(ret), nil +} + +// SVG returns svg document for given page number. +func (f *Document) SVG(pageNumber int) (string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return "", ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return "", ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + var bounds fzRect + bounds = boundPage(f.ctx, page) + + var ctm fzMatrix + ctm = scale(float32(72.0/72), float32(72.0/72)) + bounds = transformRect(bounds, ctm) + + buf := fzNewBuffer(f.ctx, 1024) + defer fzDropBuffer(f.ctx, buf) + + out := fzNewOutputWithBuffer(f.ctx, buf) + defer fzDropOutput(f.ctx, out) + + device := newSvgDevice(f.ctx, out, bounds.X1-bounds.X0, bounds.Y1-bounds.Y0, fzSvgTextAsPath, 1) + fzEnableDeviceHints(f.ctx, device, fzNoCache) + defer fzDropDevice(f.ctx, device) + + runPageContents(f.ctx, page, device, ctm) + + fzCloseDevice(f.ctx, device) + fzCloseOutput(f.ctx, out) + + ret := fzStringFromBuffer(f.ctx, buf) + + return bytePtrToString(ret), nil +} + +// ToC returns the table of contents (also known as outline). +func (f *Document) ToC() ([]Outline, error) { + data := make([]Outline, 0) + + outline := fzLoadOutline(f.ctx, f.doc) + if outline == nil { + return nil, ErrLoadOutline + } + + defer fzDropOutline(f.ctx, outline) + + var walk func(outline *fzOutline, level int) + + walk = func(outline *fzOutline, level int) { + for outline != nil { + res := Outline{} + res.Level = level + res.Title = bytePtrToString((*uint8)(unsafe.Pointer(outline.Title))) + res.URI = bytePtrToString((*uint8)(unsafe.Pointer(outline.Uri))) + res.Page = int(outline.Page.Page) + res.Top = float64(outline.Y) + data = append(data, res) + + if outline.Down != nil { + walk(outline.Down, level+1) + } + outline = outline.Next + } + } + + walk(outline, 1) + + return data, nil +} + +// Metadata returns the map with standard metadata. +func (f *Document) Metadata() map[string]string { + data := make(map[string]string) + + lookup := func(key string) string { + buf := make([]byte, 256) + fzLookupMetadata(f.ctx, f.doc, key, unsafe.SliceData(buf), len(buf)) + + return string(buf) + } + + data["format"] = lookup("format") + data["encryption"] = lookup("encryption") + data["title"] = lookup("info:Title") + data["author"] = lookup("info:Author") + data["subject"] = lookup("info:Subject") + data["keywords"] = lookup("info:Keywords") + data["creator"] = lookup("info:Creator") + data["producer"] = lookup("info:Producer") + data["creationDate"] = lookup("info:CreationDate") + data["modDate"] = lookup("info:modDate") + + return data +} + +// Bound gives the Bounds of a given Page in the document. +func (f *Document) Bound(pageNumber int) (image.Rectangle, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + if pageNumber >= f.NumPage() { + return image.Rectangle{}, ErrPageMissing + } + + page := fzLoadPage(f.ctx, f.doc, pageNumber) + if page == nil { + return image.Rectangle{}, ErrLoadPage + } + + defer fzDropPage(f.ctx, page) + + var bounds fzRect + bounds = boundPage(f.ctx, page) + + return image.Rect(int(bounds.X0), int(bounds.Y0), int(bounds.X1), int(bounds.Y1)), nil +} + +// Close closes the underlying fitz document. +func (f *Document) Close() error { + if f.stream != nil { + fzDropStream(f.ctx, f.stream) + } + + fzDropDocument(f.ctx, f.doc) + fzDropContext(f.ctx) + + f.data = nil + + return nil +} + +var ( + libmupdf uintptr + + fzBoundPage *bundle + fzTransformRect *bundle + fzRoundRect *bundle + fzScale *bundle + fzNewDrawDevice *bundle + fzRunPageContents *bundle + fzNewBufferFromPixmapAsPNG *bundle + fzNewStextPage *bundle + fzNewSvgDevice *bundle + + fzNewContextImp func(alloc *fzAllocContext, locks *fzLocksContext, maxStore uint64, version string) *fzContext + fzDropContext func(ctx *fzContext) + fzOpenDocument func(ctx *fzContext, filename string) *fzDocument + fzOpenDocumentWithStream func(ctx *fzContext, magic string, stream *fzStream) *fzDocument + fzOpenMemory func(ctx *fzContext, data *uint8, len uint64) *fzStream + fzDropStream func(ctx *fzContext, stm *fzStream) + fzRegisterDocumentHandlers func(ctx *fzContext) + fzNeedsPassword func(ctx *fzContext, doc *fzDocument) int + fzDropDocument func(ctx *fzContext, doc *fzDocument) + fzCountPages func(ctx *fzContext, doc *fzDocument) int + fzLoadPage func(ctx *fzContext, doc *fzDocument, number int) *fzPage + fzDropPage func(ctx *fzContext, page *fzPage) + fzNewPixmap func(ctx *fzContext, colorspace *fzColorspace, w, h int, seps *fzSeparations, alpha int) *fzPixmap + fzDropPixmap func(ctx *fzContext, pix *fzPixmap) + fzPixmapSamples func(ctx *fzContext, pix *fzPixmap) *uint8 + fzClearPixmapWithValue func(ctx *fzContext, pix *fzPixmap, value int) + fzEnableDeviceHints func(ctx *fzContext, dev *fzDevice, hints int) + fzDropDevice func(ctx *fzContext, dev *fzDevice) + fzCloseDevice func(ctx *fzContext, dev *fzDevice) + fzDeviceRgb func(ctx *fzContext) *fzColorspace + fzNewBuffer func(ctx *fzContext, size uint64) *fzBuffer + fzDropBuffer func(ctx *fzContext, buf *fzBuffer) + fzBufferStorage func(ctx *fzContext, buf *fzBuffer, data **uint8) uint64 + fzStringFromBuffer func(ctx *fzContext, buf *fzBuffer) *uint8 + fzLoadLinks func(ctx *fzContext, page *fzPage) *fzLink + fzDropLink func(ctx *fzContext, link *fzLink) + fzDropStextPage func(ctx *fzContext, page *fzStextPage) + fzNewStextDevice func(ctx *fzContext, page *fzStextPage, options *fzStextOptions) *fzDevice + fzNewBufferFromStextPage func(ctx *fzContext, page *fzStextPage) *fzBuffer + fzLookupMetadata func(ctx *fzContext, doc *fzDocument, key string, buf *uint8, size int) int + fzLoadOutline func(ctx *fzContext, doc *fzDocument) *fzOutline + fzDropOutline func(ctx *fzContext, outline *fzOutline) + fzNewOutputWithBuffer func(ctx *fzContext, buf *fzBuffer) *fzOutput + fzDropOutput func(ctx *fzContext, out *fzOutput) + fzCloseOutput func(ctx *fzContext, out *fzOutput) + fzPrintStextPageAsHTML func(ctx *fzContext, out *fzOutput, page *fzStextPage, id int) + fzPrintStextHeaderAsHTML func(ctx *fzContext, out *fzOutput) + fzPrintStextTrailerAsHTML func(ctx *fzContext, out *fzOutput) +) + +func init() { + libmupdf = loadLibrary() + + if os.Getenv("FZ_VERSION") != "" { + FzVersion = os.Getenv("FZ_VERSION") + } + + fzBoundPage = newBundle("fz_bound_page", &typeFzRect, &ffi.TypePointer, &ffi.TypePointer) + fzTransformRect = newBundle("fz_transform_rect", &typeFzRect, &typeFzRect, &typeFzMatrix) + fzRoundRect = newBundle("fz_round_rect", &typeFzIRect, &typeFzRect) + fzScale = newBundle("fz_scale", &typeFzMatrix, &ffi.TypeFloat, &ffi.TypeFloat) + fzNewDrawDevice = newBundle("fz_new_draw_device", &ffi.TypePointer, &ffi.TypePointer, &typeFzMatrix, &ffi.TypePointer) + fzRunPageContents = newBundle("fz_run_page_contents", &ffi.TypeVoid, &ffi.TypePointer, &ffi.TypePointer, &ffi.TypePointer, &typeFzMatrix, &ffi.TypePointer) + fzNewBufferFromPixmapAsPNG = newBundle("fz_new_buffer_from_pixmap_as_png", &ffi.TypePointer, &ffi.TypePointer, &ffi.TypePointer, &typeFzColorParams) + fzNewStextPage = newBundle("fz_new_stext_page", &ffi.TypePointer, &ffi.TypePointer, &typeFzRect) + fzNewSvgDevice = newBundle("fz_new_svg_device", &ffi.TypePointer, &ffi.TypePointer, &ffi.TypePointer, &ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeSint32, &ffi.TypeSint32) + + purego.RegisterLibFunc(&fzNewContextImp, libmupdf, "fz_new_context_imp") + purego.RegisterLibFunc(&fzDropContext, libmupdf, "fz_drop_context") + purego.RegisterLibFunc(&fzOpenDocument, libmupdf, "fz_open_document") + purego.RegisterLibFunc(&fzOpenDocumentWithStream, libmupdf, "fz_open_document_with_stream") + purego.RegisterLibFunc(&fzOpenMemory, libmupdf, "fz_open_memory") + purego.RegisterLibFunc(&fzDropStream, libmupdf, "fz_drop_stream") + purego.RegisterLibFunc(&fzRegisterDocumentHandlers, libmupdf, "fz_register_document_handlers") + purego.RegisterLibFunc(&fzNeedsPassword, libmupdf, "fz_needs_password") + purego.RegisterLibFunc(&fzDropDocument, libmupdf, "fz_drop_document") + purego.RegisterLibFunc(&fzCountPages, libmupdf, "fz_count_pages") + purego.RegisterLibFunc(&fzLoadPage, libmupdf, "fz_load_page") + purego.RegisterLibFunc(&fzDropPage, libmupdf, "fz_drop_page") + purego.RegisterLibFunc(&fzNewPixmap, libmupdf, "fz_new_pixmap") + purego.RegisterLibFunc(&fzDropPixmap, libmupdf, "fz_drop_pixmap") + purego.RegisterLibFunc(&fzPixmapSamples, libmupdf, "fz_pixmap_samples") + purego.RegisterLibFunc(&fzClearPixmapWithValue, libmupdf, "fz_clear_pixmap_with_value") + purego.RegisterLibFunc(&fzEnableDeviceHints, libmupdf, "fz_enable_device_hints") + purego.RegisterLibFunc(&fzDropDevice, libmupdf, "fz_drop_device") + purego.RegisterLibFunc(&fzCloseDevice, libmupdf, "fz_close_device") + purego.RegisterLibFunc(&fzDeviceRgb, libmupdf, "fz_device_rgb") + purego.RegisterLibFunc(&fzNewBuffer, libmupdf, "fz_new_buffer") + purego.RegisterLibFunc(&fzDropBuffer, libmupdf, "fz_drop_buffer") + purego.RegisterLibFunc(&fzBufferStorage, libmupdf, "fz_buffer_storage") + purego.RegisterLibFunc(&fzStringFromBuffer, libmupdf, "fz_string_from_buffer") + purego.RegisterLibFunc(&fzLoadLinks, libmupdf, "fz_load_links") + purego.RegisterLibFunc(&fzDropLink, libmupdf, "fz_drop_link") + purego.RegisterLibFunc(&fzDropStextPage, libmupdf, "fz_drop_stext_page") + purego.RegisterLibFunc(&fzNewStextDevice, libmupdf, "fz_new_stext_device") + purego.RegisterLibFunc(&fzNewBufferFromStextPage, libmupdf, "fz_new_buffer_from_stext_page") + purego.RegisterLibFunc(&fzLookupMetadata, libmupdf, "fz_lookup_metadata") + purego.RegisterLibFunc(&fzLoadOutline, libmupdf, "fz_load_outline") + purego.RegisterLibFunc(&fzDropOutline, libmupdf, "fz_drop_outline") + purego.RegisterLibFunc(&fzNewOutputWithBuffer, libmupdf, "fz_new_output_with_buffer") + purego.RegisterLibFunc(&fzDropOutput, libmupdf, "fz_drop_output") + purego.RegisterLibFunc(&fzCloseOutput, libmupdf, "fz_close_output") + purego.RegisterLibFunc(&fzPrintStextPageAsHTML, libmupdf, "fz_print_stext_page_as_html") + purego.RegisterLibFunc(&fzPrintStextHeaderAsHTML, libmupdf, "fz_print_stext_header_as_html") + purego.RegisterLibFunc(&fzPrintStextTrailerAsHTML, libmupdf, "fz_print_stext_trailer_as_html") + + ver := version() + if ver != "" { + FzVersion = ver + } +} + +func version() string { + if fzNewContextImp(nil, nil, uint64(MaxStore), FzVersion) != nil { + return FzVersion + } + + s := strings.Split(FzVersion, ".") + v := strings.Join(s[:len(s)-1], ".") + + for x := 10; x >= 0; x-- { + ver := v + "." + strconv.Itoa(x) + if ver == FzVersion { + continue + } + + if fzNewContextImp(nil, nil, uint64(MaxStore), ver) != nil { + return ver + } + } + + return "" +} + +type bundle struct { + sym uintptr + cif ffi.Cif +} + +func (b *bundle) call(rValue unsafe.Pointer, aValues ...unsafe.Pointer) { + ffi.Call(&b.cif, b.sym, rValue, aValues...) +} + +func newBundle(name string, rType *ffi.Type, aTypes ...*ffi.Type) *bundle { + b := new(bundle) + b.sym = procAddress(libmupdf, name) + + nArgs := uint32(len(aTypes)) + + if status := ffi.PrepCif(&b.cif, ffi.DefaultAbi, nArgs, rType, aTypes...); status != ffi.OK { + panic(status) + } + + return b +} + +var typeFzRect = ffi.Type{Type: ffi.Struct, Elements: &[]*ffi.Type{&ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeFloat, nil}[0]} +var typeFzIRect = ffi.Type{Type: ffi.Struct, Elements: &[]*ffi.Type{&ffi.TypeSint32, &ffi.TypeSint32, &ffi.TypeSint32, &ffi.TypeSint32, nil}[0]} +var typeFzMatrix = ffi.Type{Type: ffi.Struct, Elements: &[]*ffi.Type{&ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeFloat, &ffi.TypeFloat, nil}[0]} +var typeFzColorParams = ffi.Type{Type: ffi.Struct, Elements: &[]*ffi.Type{&ffi.TypeUint8, &ffi.TypeUint8, &ffi.TypeUint8, &ffi.TypeUint8, nil}[0]} + +func boundPage(ctx *fzContext, page *fzPage) fzRect { + var ret fzRect + fzBoundPage.call(unsafe.Pointer(&ret), unsafe.Pointer(&ctx), unsafe.Pointer(&page)) + + return ret +} + +func transformRect(rect fzRect, m fzMatrix) fzRect { + var ret fzRect + fzTransformRect.call(unsafe.Pointer(&ret), unsafe.Pointer(&rect), unsafe.Pointer(&m)) + + return ret +} + +func roundRect(rect fzRect) fzIRect { + var ret fzIRect + fzRoundRect.call(unsafe.Pointer(&ret), unsafe.Pointer(&rect)) + + return ret +} + +func scale(sx, sy float32) fzMatrix { + var ret fzMatrix + fzScale.call(unsafe.Pointer(&ret), unsafe.Pointer(&sx), unsafe.Pointer(&sy)) + + return ret +} + +func newDrawDevice(ctx *fzContext, transform fzMatrix, dest *fzPixmap) *fzDevice { + var ret *fzDevice + fzNewDrawDevice.call(unsafe.Pointer(&ret), unsafe.Pointer(&ctx), unsafe.Pointer(&transform), unsafe.Pointer(&dest)) + + return ret +} + +func runPageContents(ctx *fzContext, page *fzPage, dev *fzDevice, transform fzMatrix) { + var cookie fzCookie + fzRunPageContents.call(nil, unsafe.Pointer(&ctx), unsafe.Pointer(&page), unsafe.Pointer(&dev), unsafe.Pointer(&transform), unsafe.Pointer(&cookie)) +} + +func newBufferFromPixmapAsPNG(ctx *fzContext, pix *fzPixmap, params fzColorParams) *fzBuffer { + var ret *fzBuffer + fzNewBufferFromPixmapAsPNG.call(unsafe.Pointer(&ret), unsafe.Pointer(&ctx), unsafe.Pointer(&pix), unsafe.Pointer(¶ms)) + + return ret +} +func newStextPage(ctx *fzContext, mediabox fzRect) *fzStextPage { + var ret *fzStextPage + fzNewStextPage.call(unsafe.Pointer(&ret), unsafe.Pointer(&ctx), unsafe.Pointer(&mediabox)) + + return ret +} + +func newSvgDevice(ctx *fzContext, out *fzOutput, pageWidth, pageHeight float32, textFormat, reuseImages int) *fzDevice { + var ret *fzDevice + fzNewSvgDevice.call(unsafe.Pointer(&ret), unsafe.Pointer(&ctx), unsafe.Pointer(&out), unsafe.Pointer(&pageWidth), unsafe.Pointer(&pageHeight), unsafe.Pointer(&textFormat), unsafe.Pointer(&reuseImages)) + + return ret +} + +const ( + fzNoCache = 2 + fzStextPreserveImages = 4 + fzSvgTextAsPath = 0 +) + +var fzIdentity = fzMatrix{A: 1, B: 0, C: 0, D: 1, E: 0, F: 0} + +type fzContext struct { + User *byte + Alloc fzAllocContext + Locks fzLocksContext + Error fzErrorContext + Warn fzWarnContext + Aa fzAaContext + Seed48 [7]uint16 + IccEnabled int32 + ThrowOnRepair int32 + Handler *fzDocumentHandlerContext + Archive *fzArchiveHandlerContext + Style *fzStyleContext + Tuning *fzTuningContext + StdDbg *fzOutput + Font *fzFontContext + Colorspace *fzColorspaceContext + Store *fzStore + GlyphCache *fzGlyphCache +} + +type fzDocument struct { + Refs int32 + DropDocument *[0]byte + NeedsPassword *[0]byte + AuthenticatePassword *[0]byte + HasPermission *[0]byte + LoadOutline *[0]byte + OutlineIterator *[0]byte + Layout *[0]byte + MakeBookmark *[0]byte + LookupBookmark *[0]byte + ResolveLinkDest *[0]byte + FormatLinkUri *[0]byte + CountChapters *[0]byte + CountPages *[0]byte + LoadPage *[0]byte + PageLabel *[0]byte + LookupMetadata *[0]byte + SetMetadata *[0]byte + GetOutputIntent *[0]byte + OutputAccelerator *[0]byte + RunStructure *[0]byte + AsPdf *[0]byte + DidLayout int32 + IsReflowable int32 + Open *fzPage +} + +type fzOutline struct { + Refs int32 + Title *int8 + Uri *int8 + Page fzLocation + X float32 + Y float32 + Next *fzOutline + Down *fzOutline + Open int32 + _ [4]byte +} + +type fzPage struct { + Refs int32 + Doc *fzDocument + Chapter int32 + Number int32 + Incomplete int32 + DropPage *[0]byte + BoundPage *[0]byte + RunPageContents *[0]byte + RunPageAnnots *[0]byte + RunPageWidgets *[0]byte + LoadLinks *[0]byte + PagePresentation *[0]byte + ControlSeparation *[0]byte + SeparationDisabled *[0]byte + Separations *[0]byte + Overprint *[0]byte + CreateLink *[0]byte + DeleteLink *[0]byte + Prev **fzPage + Next *fzPage +} + +type fzOutput struct { + State *byte + Write *[0]byte + Seek *[0]byte + Tell *[0]byte + Close *[0]byte + Drop *[0]byte + Reset *[0]byte + Stream *[0]byte + Truncate *[0]byte + Closed int32 + Bp *int8 + Wp *int8 + Ep *int8 + Buffered int32 + Bits int32 +} + +type fzLocation struct { + Chapter int32 + Page int32 +} + +type fzStream struct { + Refs int32 + Error int32 + Eof int32 + Progressive int32 + Pos int64 + Avail int32 + Bits int32 + Rp *uint8 + Wp *uint8 + State *byte + Next *[0]byte + Drop *[0]byte + Seek *[0]byte +} + +type fzRect struct { + X0 float32 + Y0 float32 + X1 float32 + Y1 float32 +} + +type fzIRect struct { + X0 int32 + Y0 int32 + X1 int32 + Y1 int32 +} + +type fzMatrix struct { + A float32 + B float32 + C float32 + D float32 + E float32 + F float32 +} + +type fzCookie struct { + Abort int32 + Progress int32 + Max uint64 + Errors int32 + Incomplete int32 +} + +type fzDevice struct { + Refs int32 + Hints int32 + Flags int32 + CloseDevice *[0]byte + DropDevice *[0]byte + FillPath *[0]byte + StrokePath *[0]byte + ClipPath *[0]byte + ClipStrokePath *[0]byte + FillText *[0]byte + StrokeText *[0]byte + ClipText *[0]byte + ClipStrokeText *[0]byte + IgnoreText *[0]byte + FillShade *[0]byte + FillImage *[0]byte + FillImageMask *[0]byte + ClipImageMask *[0]byte + PopClip *[0]byte + BeginMask *[0]byte + EndMask *[0]byte + BeginGroup *[0]byte + EndGroup *[0]byte + BeginTile *[0]byte + EndTile *[0]byte + RenderFlags *[0]byte + SetDefaultColorspaces *[0]byte + BeginLayer *[0]byte + EndLayer *[0]byte + BeginStructure *[0]byte + EndStructure *[0]byte + BeginMetatext *[0]byte + EndMetatext *[0]byte + D1Rect fzRect + ContainerLen int32 + ContainerCap int32 + Container *fzDeviceContainerStack +} + +type fzColorspace struct { + Storable fzKeyStorable + Type uint32 + Flags int32 + N int32 + Name *int8 + U [288]byte +} + +type fzStorable struct { + Refs int32 + Drop *[0]byte + Droppable *[0]byte +} + +type fzKeyStorable struct { + Storable fzStorable + KeyRefs int16 + _ [6]byte +} + +type fzPixmap struct { + Storable fzStorable + X int32 + Y int32 + W int32 + H int32 + N uint8 + S uint8 + Alpha uint8 + Flags uint8 + Stride int64 + Seps *fzSeparations + Xres int32 + Yres int32 + Colorspace *fzColorspace + Samples *uint8 + Underlying *fzPixmap +} + +type fzColorParams struct { + Ri uint8 + Bp uint8 + Op uint8 + Opm uint8 +} + +type fzBuffer struct { + Refs int32 + Data *uint8 + Cap uint64 + Len uint64 + Bits int32 + Shared int32 +} + +type fzLink struct { + Refs int32 + Next *fzLink + Rect fzRect + Uri *int8 + RectFn *[0]byte + UriFn *[0]byte + Drop *[0]byte +} + +type fzStextPage struct { + Pool *fzPool + Mediabox fzRect + FirstBlock *fzStextBlock + LastBlock *fzStextBlock +} + +type fzStextOptions struct { + Flags int32 + Scale float32 +} + +type fzStextBlock struct { + Type int32 + Bbox fzRect + _ [4]byte + U [32]byte + Prev *fzStextBlock + Next *fzStextBlock +} + +type fzDeviceContainerStack struct { + Scissor fzRect + Type int32 + User int32 +} + +type fzAllocContext struct { + User *byte + Malloc *[0]byte + Realloc *[0]byte + Free *[0]byte +} + +type fzLocksContext struct { + User *byte + Lock *[0]byte + Unlock *[0]byte +} + +type fzErrorContext struct { + Top *fzErrorStackSlot + Stack [256]fzErrorStackSlot + Padding fzErrorStackSlot + StackBase *fzErrorStackSlot + ErrCode int32 + ErrNum int32 + PrintUser *byte + Print *[0]byte + Message [256]int8 +} + +type fzWarnContext struct { + User *byte + Print *[0]byte + Count int32 + Message [256]int8 + _ [4]byte +} + +type fzAaContext struct { + Hscale int32 + Vscale int32 + Scale int32 + Bits int32 + TextBits int32 + MinLineWidth float32 +} + +type fzErrorStackSlot struct { + Buffer [1]int32 + State int32 + Code int32 + Padding [24]int8 +} + +type fzFontContext struct{} +type fzColorspaceContext struct{} +type fzTuningContext struct{} +type fzStyleContext struct{} +type fzDocumentHandlerContext struct{} +type fzArchiveHandlerContext struct{} +type fzStore struct{} +type fzGlyphCache struct{} +type fzSeparations struct{} +type fzPool struct{} diff --git a/fitz_test.go b/fitz_test.go index 5c3c7bd..dc86c4f 100644 --- a/fitz_test.go +++ b/fitz_test.go @@ -1,61 +1,27 @@ -package fitz +package fitz_test import ( + "errors" "fmt" + "image" "image/jpeg" - "io/ioutil" + "io" "os" "path/filepath" "testing" + + "github.com/gen2brain/go-fitz" ) func TestImage(t *testing.T) { - doc, err := New(filepath.Join("testdata", "test.pdf")) + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) if err != nil { t.Error(err) } defer doc.Close() - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") - if err != nil { - t.Error(err) - } - - for n := 0; n < doc.NumPage(); n++ { - img, err := doc.Image(n) - if err != nil { - t.Error(err) - } - - f, err := os.Create(filepath.Join(tmpDir, fmt.Sprintf("test%03d.jpg", n))) - if err != nil { - t.Error(err) - } - - err = jpeg.Encode(f, img, &jpeg.Options{Quality: jpeg.DefaultQuality}) - if err != nil { - t.Error(err) - } - - f.Close() - } -} - -func TestImageFromMemory(t *testing.T) { - b, err := ioutil.ReadFile(filepath.Join("testdata", "test.pdf")) - if err != nil { - t.Error(err) - } - - doc, err := NewFromMemory(b) - if err != nil { - t.Error(err) - } - - defer doc.Close() - - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") if err != nil { t.Error(err) } @@ -82,19 +48,83 @@ func TestImageFromMemory(t *testing.T) { } } -func TestText(t *testing.T) { - doc, err := New(filepath.Join("testdata", "test.pdf")) +func TestImageFromMemory(t *testing.T) { + b, err := os.ReadFile(filepath.Join("testdata", "test.pdf")) + if err != nil { + t.Error(err) + } + + doc, err := fitz.NewFromMemory(b) if err != nil { t.Error(err) } defer doc.Close() - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") if err != nil { t.Error(err) } + defer os.RemoveAll(tmpDir) + + for n := 0; n < doc.NumPage(); n++ { + img, err := doc.Image(n) + if err != nil { + t.Error(err) + } + + f, err := os.Create(filepath.Join(tmpDir, fmt.Sprintf("test%03d.jpg", n))) + if err != nil { + t.Error(err) + } + + err = jpeg.Encode(f, img, &jpeg.Options{Quality: jpeg.DefaultQuality}) + if err != nil { + t.Error(err) + } + + f.Close() + } +} + +func TestLinks(t *testing.T) { + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) + if err != nil { + t.Error(err) + } + + defer doc.Close() + + links, err := doc.Links(2) + if err != nil { + t.Error(err) + } + + if len(links) != 1 { + t.Error("expected 1 link, got", len(links)) + } + + if links[0].URI != "https://creativecommons.org/licenses/by-nc-sa/4.0/" { + t.Error("expected empty URI, got", links[0].URI) + } +} + +func TestText(t *testing.T) { + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) + if err != nil { + t.Error(err) + } + + defer doc.Close() + + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") + if err != nil { + t.Error(err) + } + + defer os.RemoveAll(tmpDir) + for n := 0; n < doc.NumPage(); n++ { text, err := doc.Text(n) if err != nil { @@ -116,18 +146,20 @@ func TestText(t *testing.T) { } func TestHTML(t *testing.T) { - doc, err := New(filepath.Join("testdata", "test.pdf")) + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) if err != nil { t.Error(err) } defer doc.Close() - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") if err != nil { t.Error(err) } + defer os.RemoveAll(tmpDir) + for n := 0; n < doc.NumPage(); n++ { html, err := doc.HTML(n, true) if err != nil { @@ -148,19 +180,48 @@ func TestHTML(t *testing.T) { } } -func TestSVG(t *testing.T) { - doc, err := New(filepath.Join("testdata", "test.pdf")) +func TestPNG(t *testing.T) { + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) if err != nil { t.Error(err) } defer doc.Close() - tmpDir, err := ioutil.TempDir(os.TempDir(), "fitz") + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") if err != nil { t.Error(err) } + defer os.RemoveAll(tmpDir) + + for n := 0; n < doc.NumPage(); n++ { + png, err := doc.ImagePNG(n, 300.0) + if err != nil { + t.Error(err) + } + + if err = os.WriteFile(filepath.Join(tmpDir, fmt.Sprintf("test%03d.png", n)), png, 0644); err != nil { + t.Error(err) + } + } +} + +func TestSVG(t *testing.T) { + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) + if err != nil { + t.Error(err) + } + + defer doc.Close() + + tmpDir, err := os.MkdirTemp(os.TempDir(), "fitz") + if err != nil { + t.Error(err) + } + + defer os.RemoveAll(tmpDir) + for n := 0; n < doc.NumPage(); n++ { svg, err := doc.SVG(n) if err != nil { @@ -182,7 +243,7 @@ func TestSVG(t *testing.T) { } func TestToC(t *testing.T) { - doc, err := New(filepath.Join("testdata", "test.pdf")) + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) if err != nil { t.Error(err) } @@ -196,7 +257,7 @@ func TestToC(t *testing.T) { } func TestMetadata(t *testing.T) { - doc, err := New(filepath.Join("testdata", "test.pdf")) + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) if err != nil { t.Error(err) } @@ -208,3 +269,51 @@ func TestMetadata(t *testing.T) { t.Error(fmt.Errorf("metadata is empty")) } } + +func TestBound(t *testing.T) { + doc, err := fitz.New(filepath.Join("testdata", "test.pdf")) + if err != nil { + t.Error(err) + } + + defer doc.Close() + expected := image.Rect(0, 0, 612, 792) + + for i := 0; i < doc.NumPage(); i++ { + bound, err := doc.Bound(i) + if err != nil { + t.Error(err) + } + if bound != expected { + t.Error(fmt.Errorf("bounds didn't match go %v when expedient %v", bound, expected)) + } + } + + _, err = doc.Bound(doc.NumPage()) + if !errors.Is(err, fitz.ErrPageMissing) { + t.Error(fmt.Errorf("ErrPageMissing not returned got %v", err)) + } +} + +func TestEmptyBytes(t *testing.T) { + var err error + // empty reader + _, err = fitz.NewFromReader(emptyReader{}) + if !errors.Is(err, fitz.ErrEmptyBytes) { + t.Errorf("Expected ErrEmptyBytes, got %v", err) + } + // nil slice + _, err = fitz.NewFromMemory(nil) + if !errors.Is(err, fitz.ErrEmptyBytes) { + t.Errorf("Expected ErrEmptyBytes, got %v", err) + } + // empty slice + _, err = fitz.NewFromMemory(make([]byte, 0)) + if !errors.Is(err, fitz.ErrEmptyBytes) { + t.Errorf("Expected ErrEmptyBytes, got %v", err) + } +} + +type emptyReader struct{} + +func (emptyReader) Read([]byte) (int, error) { return 0, io.EOF } diff --git a/fitz_vendor.go b/fitz_vendor.go new file mode 100644 index 0000000..62c10f9 --- /dev/null +++ b/fitz_vendor.go @@ -0,0 +1,9 @@ +//go:build required + +package fitz + +import ( + _ "github.com/gen2brain/go-fitz/include/mupdf" + _ "github.com/gen2brain/go-fitz/include/mupdf/fitz" + _ "github.com/gen2brain/go-fitz/libs" +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cd253c7 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/gen2brain/go-fitz + +go 1.23.0 + +toolchain go1.24.3 + +require ( + github.com/ebitengine/purego v0.8.4 + github.com/jupiterrider/ffi v0.5.0 + golang.org/x/sys v0.33.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..33ecb80 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/jupiterrider/ffi v0.5.0 h1:j2nSgpabbV1JOwgP4Kn449sJUHq3cVLAZVBoOYn44V8= +github.com/jupiterrider/ffi v0.5.0/go.mod h1:x7xdNKo8h0AmLuXfswDUBxUsd2OqUP4ekC8sCnsmbvo= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= diff --git a/include/mupdf/fitz.h b/include/mupdf/fitz.h index 9f697c8..014bf6c 100644 --- a/include/mupdf/fitz.h +++ b/include/mupdf/fitz.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUDPF_FITZ_H #define MUDPF_FITZ_H @@ -9,6 +31,8 @@ extern "C" { #include "mupdf/fitz/config.h" #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" +#include "mupdf/fitz/output.h" +#include "mupdf/fitz/log.h" #include "mupdf/fitz/crypt.h" #include "mupdf/fitz/getopt.h" @@ -26,14 +50,14 @@ extern "C" { #include "mupdf/fitz/compress.h" #include "mupdf/fitz/compressed-buffer.h" #include "mupdf/fitz/filter.h" -#include "mupdf/fitz/output.h" #include "mupdf/fitz/archive.h" +#include "mupdf/fitz/heap.h" + /* Resources */ #include "mupdf/fitz/store.h" -#include "mupdf/fitz/colorspace.h" +#include "mupdf/fitz/color.h" #include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/glyph.h" #include "mupdf/fitz/bitmap.h" #include "mupdf/fitz/image.h" #include "mupdf/fitz/shade.h" @@ -41,7 +65,7 @@ extern "C" { #include "mupdf/fitz/path.h" #include "mupdf/fitz/text.h" #include "mupdf/fitz/separation.h" -#include "mupdf/fitz/color-management.h" +#include "mupdf/fitz/glyph.h" #include "mupdf/fitz/device.h" #include "mupdf/fitz/display-list.h" @@ -54,22 +78,17 @@ extern "C" { #include "mupdf/fitz/link.h" #include "mupdf/fitz/outline.h" #include "mupdf/fitz/document.h" -#include "mupdf/fitz/annotation.h" #include "mupdf/fitz/util.h" /* Output formats */ #include "mupdf/fitz/writer.h" #include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/output-pnm.h" -#include "mupdf/fitz/output-png.h" -#include "mupdf/fitz/output-pwg.h" -#include "mupdf/fitz/output-pcl.h" -#include "mupdf/fitz/output-pclm.h" -#include "mupdf/fitz/output-ps.h" -#include "mupdf/fitz/output-psd.h" +#include "mupdf/fitz/write-pixmap.h" #include "mupdf/fitz/output-svg.h" -#include "mupdf/fitz/output-tga.h" + +#include "mupdf/fitz/story.h" +#include "mupdf/fitz/story-writer.h" #ifdef __cplusplus } diff --git a/include/mupdf/fitz/annotation.h b/include/mupdf/fitz/annotation.h deleted file mode 100644 index 8f7385f..0000000 --- a/include/mupdf/fitz/annotation.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MUPDF_FITZ_ANNOTATION_H -#define MUPDF_FITZ_ANNOTATION_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/geometry.h" -#include "mupdf/fitz/document.h" - -/* - fz_new_annot_of_size: Create and initialize an annotation struct. -*/ -fz_annot *fz_new_annot_of_size(fz_context *ctx, int size); - -#define fz_new_derived_annot(CTX, TYPE) \ - ((TYPE *)Memento_label(fz_new_annot_of_size(CTX,sizeof(TYPE)),#TYPE)) - -/* - fz_keep_annot: Take a new reference to an annotation. -*/ -fz_annot *fz_keep_annot(fz_context *ctx, fz_annot *annot); - -/* - fz_drop_annot: Drop a reference to an annotation. If the - reference count reaches zero, annot will be destroyed. -*/ -void fz_drop_annot(fz_context *ctx, fz_annot *annot); - -/* - fz_first_annot: Return a pointer to the first annotation on a page. -*/ -fz_annot *fz_first_annot(fz_context *ctx, fz_page *page); - -/* - fz_next_annot: Return a pointer to the next annotation on a page. -*/ -fz_annot *fz_next_annot(fz_context *ctx, fz_annot *annot); - -/* - fz_bound_annot: Return the bounding rectangle of the annotation. -*/ -fz_rect *fz_bound_annot(fz_context *ctx, fz_annot *annot, fz_rect *rect); - -#endif diff --git a/include/mupdf/fitz/archive.h b/include/mupdf/fitz/archive.h index 317ab99..407eef4 100644 --- a/include/mupdf/fitz/archive.h +++ b/include/mupdf/fitz/archive.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_ARCHIVE_H #define MUPDF_FITZ_ARCHIVE_H @@ -5,32 +27,25 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/buffer.h" #include "mupdf/fitz/stream.h" +#include "mupdf/fitz/tree.h" -typedef struct fz_archive_s fz_archive; +/* PUBLIC API */ -struct fz_archive_s -{ - fz_stream *file; - const char *format; +/** + fz_archive: - void (*drop_archive)(fz_context *ctx, fz_archive *arch); - int (*count_entries)(fz_context *ctx, fz_archive *arch); - const char *(*list_entry)(fz_context *ctx, fz_archive *arch, int idx); - int (*has_entry)(fz_context *ctx, fz_archive *arch, const char *name); - fz_buffer *(*read_entry)(fz_context *ctx, fz_archive *arch, const char *name); - fz_stream *(*open_entry)(fz_context *ctx, fz_archive *arch, const char *name); -}; + fz_archive provides methods for accessing "archive" files. + An archive file is a conceptual entity that contains multiple + files, which can be counted, enumerated, and read. -/* - fz_new_archive: Create and initialize an archive struct. + Implementations of fz_archive based upon directories, zip + and tar files are included. */ -fz_archive *fz_new_archive_of_size(fz_context *ctx, fz_stream *file, int size); -#define fz_new_derived_archive(C,F,M) \ - ((M*)Memento_label(fz_new_archive_of_size(C, F, sizeof(M)), #M)) +typedef struct fz_archive fz_archive; -/* - fz_open_archive: Open a zip or tar archive +/** + Open a zip or tar archive Open a file and identify its archive type based on the archive signature contained inside. @@ -39,16 +54,25 @@ fz_archive *fz_new_archive_of_size(fz_context *ctx, fz_stream *file, int size); */ fz_archive *fz_open_archive(fz_context *ctx, const char *filename); -/* - fz_open_archive_with_stream: Open zip or tar archive stream. +/** + Open zip or tar archive stream. Open an archive using a seekable stream object rather than opening a file or directory on disk. */ fz_archive *fz_open_archive_with_stream(fz_context *ctx, fz_stream *file); -/* - fz_open_directory: Open a directory as if it was an archive. +/** + Open zip or tar archive stream. + + Does the same as fz_open_archive_with_stream, but will not throw + an error in the event of failing to recognise the format. Will + still throw errors in other cases though! +*/ +fz_archive *fz_try_open_archive_with_stream(fz_context *ctx, fz_stream *file); + +/** + Open a directory as if it was an archive. A special case where a directory is opened as if it was an archive. @@ -61,38 +85,63 @@ fz_archive *fz_open_archive_with_stream(fz_context *ctx, fz_stream *file); */ fz_archive *fz_open_directory(fz_context *ctx, const char *path); + +/** + Determine if a given path is a directory. + + In the case of the path not existing, or having no access + we will return 0. +*/ int fz_is_directory(fz_context *ctx, const char *path); -/* - fz_drop_archive: Release an open archive. +/** + Drop a reference to an archive. - Any allocations for the archive are freed. + When the last reference is dropped, this closes and releases + any memory or filehandles associated with the archive. */ void fz_drop_archive(fz_context *ctx, fz_archive *arch); -/* - fz_archive_format: Returns the name of the archive format. +/** + Keep a reference to an archive. +*/ +fz_archive * +fz_keep_archive(fz_context *ctx, fz_archive *arch); + +/** + Return a pointer to a string describing the format of the + archive. + + The lifetime of the string is unspecified (in current + implementations the string will persist until the archive + is closed, but this is not guaranteed). */ const char *fz_archive_format(fz_context *ctx, fz_archive *arch); -/* - fz_count_archive_entries: Number of entries in archive. +/** + Number of entries in archive. Will always return a value >= 0. + + May throw an exception if this type of archive cannot count the + entries (such as a directory). */ int fz_count_archive_entries(fz_context *ctx, fz_archive *arch); -/* - fz_list_archive_entry: Get listed name of entry position idx. +/** + Get listed name of entry position idx. idx: Must be a value >= 0 < return value from fz_count_archive_entries. If not in range NULL will be returned. + + May throw an exception if this type of archive cannot list the + entries (such as a directory). */ const char *fz_list_archive_entry(fz_context *ctx, fz_archive *arch, int idx); -/* - fz_has_archive_entry: Check if entry by given name exists. +/** + Check if entry by given name exists. If named entry does not exist 0 will be returned, if it does exist 1 is returned. @@ -102,35 +151,76 @@ const char *fz_list_archive_entry(fz_context *ctx, fz_archive *arch, int idx); */ int fz_has_archive_entry(fz_context *ctx, fz_archive *arch, const char *name); -/* - fz_open_archive_entry: Opens an archive entry as a stream. +/** + Opens an archive entry as a stream. name: Entry name to look for, this must be an exact match to the entry name in the archive. + + Throws an exception if a matching entry cannot be found. */ fz_stream *fz_open_archive_entry(fz_context *ctx, fz_archive *arch, const char *name); -/* - fz_read_archive_entry: Reads all bytes in an archive entry +/** + Opens an archive entry as a stream. + + Returns NULL if a matching entry cannot be found, otherwise + behaves exactly as fz_open_archive_entry. +*/ +fz_stream *fz_try_open_archive_entry(fz_context *ctx, fz_archive *arch, const char *name); + +/** + Reads all bytes in an archive entry into a buffer. name: Entry name to look for, this must be an exact match to the entry name in the archive. -*/ + Throws an exception if a matching entry cannot be found. +*/ fz_buffer *fz_read_archive_entry(fz_context *ctx, fz_archive *arch, const char *name); -/* - fz_is_tar_archive: Detect if stream object is a tar achieve. +/** + Reads all bytes in an archive entry + into a buffer. + + name: Entry name to look for, this must be an exact match to + the entry name in the archive. + + Returns NULL if a matching entry cannot be found. Otherwise behaves + the same as fz_read_archive_entry. Exceptions may be thrown. +*/ +fz_buffer *fz_try_read_archive_entry(fz_context *ctx, fz_archive *arch, const char *name); + +/** + fz_archive: tar implementation +*/ + +/** + Detect if stream object is a tar archive. Assumes that the stream object is seekable. */ int fz_is_tar_archive(fz_context *ctx, fz_stream *file); -/* - fz_open_tar_archive: Open a tar archive file. +/** + Detect if stream object is an archive supported by libarchive. - An exception is throw if the file is not a tar archive as + Assumes that the stream object is seekable. +*/ +int fz_is_libarchive_archive(fz_context *ctx, fz_stream *file); + +/** + Detect if stream object is a cfb archive. + + Assumes that the stream object is seekable. +*/ +int fz_is_cfb_archive(fz_context *ctx, fz_stream *file); + +/** + Open a tar archive file. + + An exception is thrown if the file is not a tar archive as indicated by the presence of a tar signature. filename: a path to a tar archive file as it would be given to @@ -138,29 +228,73 @@ int fz_is_tar_archive(fz_context *ctx, fz_stream *file); */ fz_archive *fz_open_tar_archive(fz_context *ctx, const char *filename); -/* - fz_open_tar_archive_with_stream: Open a tar archive stream. +/** + Open a tar archive stream. Open an archive using a seekable stream object rather than opening a file or directory on disk. - An exception is throw if the stream is not a tar archive as + An exception is thrown if the stream is not a tar archive as indicated by the presence of a tar signature. */ fz_archive *fz_open_tar_archive_with_stream(fz_context *ctx, fz_stream *file); -/* - fz_is_zip_archive: Detect if stream object is a zip archive. +/** + Open an archive using libarchive. + + An exception is thrown if the file is not supported by libarchive. + + filename: a path to an archive file as it would be given to + open(2). +*/ +fz_archive *fz_open_libarchive_archive(fz_context *ctx, const char *filename); + +/** + Open an archive using libarchive. + + Open an archive using a seekable stream object rather than + opening a file or directory on disk. + + An exception is thrown if the stream is not supported by libarchive. +*/ +fz_archive *fz_open_libarchive_archive_with_stream(fz_context *ctx, fz_stream *file); + +/** + Open a cfb file as an archive. + + An exception is thrown if the file is not recognised as a cfb. + + filename: a path to an archive file as it would be given to + open(2). +*/ +fz_archive *fz_open_cfb_archive(fz_context *ctx, const char *filename); + +/** + Open a cfb file as an archive. + + Open an archive using a seekable stream object rather than + opening a file or directory on disk. + + An exception is thrown if the file is not recognised as a chm. +*/ +fz_archive *fz_open_cfb_archive_with_stream(fz_context *ctx, fz_stream *file); + +/** + fz_archive: zip implementation +*/ + +/** + Detect if stream object is a zip archive. Assumes that the stream object is seekable. */ int fz_is_zip_archive(fz_context *ctx, fz_stream *file); -/* - fz_open_zip_archive: Open a zip archive file. +/** + Open a zip archive file. - An exception is throw if the file is not a zip archive as + An exception is thrown if the file is not a zip archive as indicated by the presence of a zip signature. filename: a path to a zip archive file as it would be given to @@ -168,23 +302,143 @@ int fz_is_zip_archive(fz_context *ctx, fz_stream *file); */ fz_archive *fz_open_zip_archive(fz_context *ctx, const char *path); -/* - fz_open_zip_archive: Open a zip archive stream. +/** + Open a zip archive stream. Open an archive using a seekable stream object rather than opening a file or directory on disk. - An exception is throw if the stream is not a zip archive as + An exception is thrown if the stream is not a zip archive as indicated by the presence of a zip signature. */ fz_archive *fz_open_zip_archive_with_stream(fz_context *ctx, fz_stream *file); -typedef struct fz_zip_writer_s fz_zip_writer; +/** + fz_zip_writer offers methods for creating and writing zip files. + It can be seen as the reverse of the fz_archive zip + implementation. +*/ +typedef struct fz_zip_writer fz_zip_writer; + +/** + Create a new zip writer that writes to a given file. + + Open an archive using a seekable stream object rather than + opening a file or directory on disk. +*/ fz_zip_writer *fz_new_zip_writer(fz_context *ctx, const char *filename); + +/** + Create a new zip writer that writes to a given output stream. + + Ownership of out passes in immediately upon calling this function. + The caller should never drop the fz_output, even if this function throws + an exception. +*/ +fz_zip_writer *fz_new_zip_writer_with_output(fz_context *ctx, fz_output *out); + + +/** + Given a buffer of data, (optionally) compress it, and add it to + the zip file with the given name. +*/ void fz_write_zip_entry(fz_context *ctx, fz_zip_writer *zip, const char *name, fz_buffer *buf, int compress); + +/** + Close the zip file for writing. + + This flushes any pending data to the file. This can throw + exceptions. +*/ void fz_close_zip_writer(fz_context *ctx, fz_zip_writer *zip); + +/** + Drop the reference to the zipfile. + + In common with other 'drop' methods, this will never throw an + exception. +*/ void fz_drop_zip_writer(fz_context *ctx, fz_zip_writer *zip); +/** + Create an archive that holds named buffers. + + tree can either be a preformed tree with fz_buffers as values, + or it can be NULL for an empty tree. +*/ +fz_archive *fz_new_tree_archive(fz_context *ctx, fz_tree *tree); + +/** + Add a named buffer to an existing tree archive. + + The tree will take a new reference to the buffer. Ownership + is not transferred. +*/ +void fz_tree_archive_add_buffer(fz_context *ctx, fz_archive *arch_, const char *name, fz_buffer *buf); + +/** + Add a named block of data to an existing tree archive. + + The data will be copied into a buffer, and so the caller + may free it as soon as this returns. +*/ +void fz_tree_archive_add_data(fz_context *ctx, fz_archive *arch_, const char *name, const void *data, size_t size); + +/** + Create a new multi archive (initially empty). +*/ +fz_archive *fz_new_multi_archive(fz_context *ctx); + +/** + Add an archive to the set of archives handled by a multi + archive. + + If path is NULL, then the archive contents will appear at the + top level, otherwise, the archives contents will appear prefixed + by path. +*/ +void fz_mount_multi_archive(fz_context *ctx, fz_archive *arch_, fz_archive *sub, const char *path); + +typedef int (fz_recognize_archive_fn)(fz_context *, fz_stream *); +typedef fz_archive *(fz_open_archive_fn)(fz_context *, fz_stream *); + +typedef struct +{ + fz_recognize_archive_fn *recognize; + fz_open_archive_fn *open; +} +fz_archive_handler; + +FZ_DATA extern const fz_archive_handler fz_libarchive_archive_handler; + +void fz_register_archive_handler(fz_context *ctx, const fz_archive_handler *handler); + +/** + Implementation details: Subject to change. +*/ + +struct fz_archive +{ + int refs; + fz_stream *file; + + const char *format; + + void (*drop_archive)(fz_context *ctx, fz_archive *arch); + int (*count_entries)(fz_context *ctx, fz_archive *arch); + const char *(*list_entry)(fz_context *ctx, fz_archive *arch, int idx); + int (*has_entry)(fz_context *ctx, fz_archive *arch, const char *name); + fz_buffer *(*read_entry)(fz_context *ctx, fz_archive *arch, const char *name); + fz_stream *(*open_entry)(fz_context *ctx, fz_archive *arch, const char *name); +}; + +fz_archive *fz_new_archive_of_size(fz_context *ctx, fz_stream *file, int size); + +#define fz_new_derived_archive(C,F,M) \ + ((M*)Memento_label(fz_new_archive_of_size(C, F, sizeof(M)), #M)) + + + #endif diff --git a/include/mupdf/fitz/band-writer.h b/include/mupdf/fitz/band-writer.h index fb06591..853307b 100644 --- a/include/mupdf/fitz/band-writer.h +++ b/include/mupdf/fitz/band-writer.h @@ -1,23 +1,99 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_BAND_WRITER_H #define MUPDF_FITZ_BAND_WRITER_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/output.h" +#include "mupdf/fitz/color.h" +#include "mupdf/fitz/separation.h" -/* +/** fz_band_writer */ -typedef struct fz_band_writer_s fz_band_writer; +typedef struct fz_band_writer fz_band_writer; -typedef void (fz_write_header_fn)(fz_context *ctx, fz_band_writer *writer, const fz_colorspace *cs); +/** + Cause a band writer to write the header for + a banded image with the given properties/dimensions etc. This + also configures the bandwriter for the format of the data to be + passed in future calls. + + w, h: Width and Height of the entire page. + + n: Number of components (including spots and alphas). + + alpha: Number of alpha components. + + xres, yres: X and Y resolutions in dpi. + + cs: Colorspace (NULL for bitmaps) + + seps: Separation details (or NULL). +*/ +void fz_write_header(fz_context *ctx, fz_band_writer *writer, int w, int h, int n, int alpha, int xres, int yres, int pagenum, fz_colorspace *cs, fz_separations *seps); + +/** + Cause a band writer to write the next band + of data for an image. + + stride: The byte offset from the first byte of the data + for a pixel to the first byte of the data for the same pixel + on the row below. + + band_height: The number of lines in this band. + + samples: Pointer to first byte of the data. +*/ +void fz_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_height, const unsigned char *samples); + +/** + Finishes up the output and closes the band writer. After this + call no more headers or bands may be written. +*/ +void fz_close_band_writer(fz_context *ctx, fz_band_writer *writer); + +/** + Drop the reference to the band writer, causing it to be + destroyed. + + Never throws an exception. +*/ +void fz_drop_band_writer(fz_context *ctx, fz_band_writer *writer); + +/* Implementation details: subject to change. */ + +typedef void (fz_write_header_fn)(fz_context *ctx, fz_band_writer *writer, fz_colorspace *cs); typedef void (fz_write_band_fn)(fz_context *ctx, fz_band_writer *writer, int stride, int band_start, int band_height, const unsigned char *samples); typedef void (fz_write_trailer_fn)(fz_context *ctx, fz_band_writer *writer); +typedef void (fz_close_band_writer_fn)(fz_context *ctx, fz_band_writer *writer); typedef void (fz_drop_band_writer_fn)(fz_context *ctx, fz_band_writer *writer); -struct fz_band_writer_s +struct fz_band_writer { fz_drop_band_writer_fn *drop; + fz_close_band_writer_fn *close; fz_write_header_fn *header; fz_write_band_fn *band; fz_write_trailer_fn *trailer; @@ -37,44 +113,5 @@ struct fz_band_writer_s fz_band_writer *fz_new_band_writer_of_size(fz_context *ctx, size_t size, fz_output *out); #define fz_new_band_writer(C,M,O) ((M *)Memento_label(fz_new_band_writer_of_size(ctx, sizeof(M), O), #M)) -/* - fz_write_header: Cause a band writer to write the header for - a banded image with the given properties/dimensions etc. This - also configures the bandwriter for the format of the data to be - passed in future calls. - - w, h: Width and Height of the entire page. - - n: Number of components (including spots and alphas). - - alpha: Number of alpha components. - - xres, yres: X and Y resolutions in dpi. - - pagenum: Page number - - cs: Colorspace (NULL for bitmaps) - - seps: Separation details (or NULL). - - Throws exception if incompatible data format. -*/ -void fz_write_header(fz_context *ctx, fz_band_writer *writer, int w, int h, int n, int alpha, int xres, int yres, int pagenum, const fz_colorspace *cs, fz_separations *seps); - -/* - fz_write_band: Cause a band writer to write the next band - of data for an image. - - stride: The byte offset from the first byte of the data - for a pixel to the first byte of the data for the same pixel - on the row below. - - band_height: The number of lines in this band. - - samples: Pointer to first byte of the data. -*/ -void fz_write_band(fz_context *ctx, fz_band_writer *writer, int stride, int band_height, const unsigned char *samples); - -void fz_drop_band_writer(fz_context *ctx, fz_band_writer *writer); #endif diff --git a/include/mupdf/fitz/bidi.h b/include/mupdf/fitz/bidi.h index 595f25b..3aa2dbb 100644 --- a/include/mupdf/fitz/bidi.h +++ b/include/mupdf/fitz/bidi.h @@ -1,4 +1,4 @@ -/* +/** Bidirectional text processing. Derived from the SmartOffice code, which is itself derived @@ -21,8 +21,11 @@ #define FITZ_BIDI_H #include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" -typedef enum fz_bidi_direction_e +/* Implementation details: subject to change. */ + +typedef enum { FZ_BIDI_LTR = 0, FZ_BIDI_RTL = 1, @@ -30,14 +33,14 @@ typedef enum fz_bidi_direction_e } fz_bidi_direction; -typedef enum fz_bidi_flags_e +typedef enum { FZ_BIDI_CLASSIFY_WHITE_SPACE = 1, FZ_BIDI_REPLACE_TAB = 2 } fz_bidi_flags; -/* +/** Prototype for callback function supplied to fz_bidi_fragment_text. @param fragment first character in fragment @@ -56,7 +59,7 @@ typedef void (fz_bidi_fragment_fn)(const uint32_t *fragment, int script, void *arg); -/* +/** Partitions the given Unicode sequence into one or more unidirectional fragments and invokes the given callback function for each fragment. diff --git a/include/mupdf/fitz/bitmap.h b/include/mupdf/fitz/bitmap.h index d340c29..bf41035 100644 --- a/include/mupdf/fitz/bitmap.h +++ b/include/mupdf/fitz/bitmap.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_BITMAP_H #define MUPDF_FITZ_BITMAP_H @@ -5,44 +27,60 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/pixmap.h" -/* - Bitmaps have 1 bit per component. Only used for creating halftoned - versions of contone buffers, and saving out. Samples are stored msb - first, akin to pbms. +/** + Bitmaps have 1 bit per component. Only used for creating + halftoned versions of contone buffers, and saving out. Samples + are stored msb first, akin to pbms. + + The internals of this struct are considered implementation + details and subject to change. Where possible, accessor + functions should be used in preference. */ -typedef struct fz_bitmap_s fz_bitmap; +typedef struct +{ + int refs; + int w, h, stride, n; + int xres, yres; + unsigned char *samples; +} fz_bitmap; -/* - fz_keep_bitmap: Take a reference to a bitmap. +/** + Take an additional reference to the bitmap. The same pointer + is returned. - bit: The bitmap to increment the reference for. - - Returns bit. + Never throws exceptions. */ fz_bitmap *fz_keep_bitmap(fz_context *ctx, fz_bitmap *bit); -/* - fz_drop_bitmap: Drop a reference and free a bitmap. +/** + Drop a reference to the bitmap. When the reference count reaches + zero, the bitmap will be destroyed. - Decrement the reference count for the bitmap. When no - references remain the pixmap will be freed. + Never throws exceptions. */ void fz_drop_bitmap(fz_context *ctx, fz_bitmap *bit); -/* - A halftone is a set of threshold tiles, one per component. Each - threshold tile is a pixmap, possibly of varying sizes and phases. - Currently, we only provide one 'default' halftone tile for operating - on 1 component plus alpha pixmaps (where the alpha is ignored). This - is signified by a fz_halftone pointer to NULL. +/** + Invert bitmap. + + Never throws exceptions. */ -typedef struct fz_halftone_s fz_halftone; +void fz_invert_bitmap(fz_context *ctx, fz_bitmap *bmp); -/* - fz_new_bitmap_from_pixmap: Make a bitmap from a pixmap and a halftone. +/** + A halftone is a set of threshold tiles, one per component. Each + threshold tile is a pixmap, possibly of varying sizes and + phases. Currently, we only provide one 'default' halftone tile + for operating on 1 component plus alpha pixmaps (where the alpha + is ignored). This is signified by a fz_halftone pointer to NULL. +*/ +typedef struct fz_halftone fz_halftone; - pix: The pixmap to generate from. Currently must be a single color - component with no alpha. +/** + Make a bitmap from a pixmap and a halftone. + + pix: The pixmap to generate from. Currently must be a single + color component with no alpha. ht: The halftone to use. NULL implies the default halftone. @@ -51,13 +89,13 @@ typedef struct fz_halftone_s fz_halftone; */ fz_bitmap *fz_new_bitmap_from_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht); -/* - fz_new_bitmap_from_pixmap_band: Make a bitmap from a pixmap and a +/** + Make a bitmap from a pixmap and a halftone, allowing for the position of the pixmap within an overall banded rendering. - pix: The pixmap to generate from. Currently must be a single color - component with no alpha. + pix: The pixmap to generate from. Currently must be a single + color component with no alpha. ht: The halftone to use. NULL implies the default halftone. @@ -69,16 +107,8 @@ fz_bitmap *fz_new_bitmap_from_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halfton */ fz_bitmap *fz_new_bitmap_from_pixmap_band(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht, int band_start); -struct fz_bitmap_s -{ - int refs; - int w, h, stride, n; - int xres, yres; - unsigned char *samples; -}; - -/* - fz_new_bitmap: Create a new bitmap. +/** + Create a new bitmap. w, h: Width and Height for the bitmap @@ -91,8 +121,8 @@ struct fz_bitmap_s */ fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n, int xres, int yres); -/* - fz_bitmap_details: Retrieve details of a given bitmap. +/** + Retrieve details of a given bitmap. bitmap: The bitmap to query. @@ -100,21 +130,22 @@ fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n, int xres, int yre h: Pointer to storage to retrieve height (or NULL). - n: Pointer to storage to retrieve number of color components (or NULL). + n: Pointer to storage to retrieve number of color components (or + NULL). stride: Pointer to storage to retrieve bitmap stride (or NULL). */ void fz_bitmap_details(fz_bitmap *bitmap, int *w, int *h, int *n, int *stride); -/* - fz_clear_bitmap: Clear a previously created bitmap. +/** + Set the entire bitmap to 0. - bit: The bitmap to clear. + Never throws exceptions. */ void fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit); -/* - fz_default_halftone: Create a 'default' halftone structure +/** + Create a 'default' halftone structure for the given number of components. num_comps: The number of components to use. @@ -125,15 +156,19 @@ void fz_clear_bitmap(fz_context *ctx, fz_bitmap *bit); */ fz_halftone *fz_default_halftone(fz_context *ctx, int num_comps); -/* - fz_keep_halftone: Take an additional reference to a - halftone. +/** + Take an additional reference to the halftone. The same pointer + is returned. + + Never throws exceptions. */ fz_halftone *fz_keep_halftone(fz_context *ctx, fz_halftone *half); -/* - fz_drop_halftone: Drop a reference to a halftone. If the - reference count reaches zero, ht will be destroyed. +/** + Drop a reference to the halftone. When the reference count + reaches zero, the halftone is destroyed. + + Never throws exceptions. */ void fz_drop_halftone(fz_context *ctx, fz_halftone *ht); diff --git a/include/mupdf/fitz/buffer.h b/include/mupdf/fitz/buffer.h index 251a594..5ac949c 100644 --- a/include/mupdf/fitz/buffer.h +++ b/include/mupdf/fitz/buffer.h @@ -1,31 +1,69 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_BUFFER_H #define MUPDF_FITZ_BUFFER_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" -/* - fz_buffer is a wrapper around a dynamically allocated array of bytes. +/** + fz_buffer is a wrapper around a dynamically allocated array of + bytes. Buffers have a capacity (the number of bytes storage immediately available) and a current size. + + The contents of the structure are considered implementation + details and are subject to change. Users should use the accessor + functions in preference. */ -typedef struct fz_buffer_s fz_buffer; +typedef struct +{ + int refs; + unsigned char *data; + size_t cap, len; + int unused_bits; + int shared; +} fz_buffer; -/* - fz_keep_buffer: Increment the reference count for a buffer. +/** + Take an additional reference to the buffer. The same pointer + is returned. - Returns a pointer to the buffer. + Never throws exceptions. */ fz_buffer *fz_keep_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_drop_buffer: Decrement the reference count for a buffer. +/** + Drop a reference to the buffer. When the reference count reaches + zero, the buffer is destroyed. + + Never throws exceptions. */ void fz_drop_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_buffer_storage: Retrieve internal memory of buffer. +/** + Retrieve internal memory of buffer. datap: Output parameter that will be pointed to the data. @@ -33,81 +71,110 @@ void fz_drop_buffer(fz_context *ctx, fz_buffer *buf); */ size_t fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap); -/* - fz_string_from_buffer: Ensure that a buffer's data ends in a +/** + Ensure that a buffer's data ends in a 0 byte, and return a pointer to it. */ const char *fz_string_from_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_new_buffer: Create a new buffer. - - capacity: Initial capacity. - - Returns pointer to new buffer. -*/ fz_buffer *fz_new_buffer(fz_context *ctx, size_t capacity); -/* - fz_new_buffer_from_data: Create a new buffer with existing data. +/** + Create a new buffer with existing data. data: Pointer to existing data. size: Size of existing data. - Takes ownership of data. Does not make a copy. Calls fz_free on the - data when the buffer is deallocated. Do not use 'data' after passing - to this function. + Takes ownership of data. Does not make a copy. Calls fz_free on + the data when the buffer is deallocated. Do not use 'data' after + passing to this function. Returns pointer to new buffer. Throws exception on allocation failure. */ fz_buffer *fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, size_t size); -/* - fz_new_buffer_from_shared_data: Like fz_new_buffer, but does not take ownership. +/** + Like fz_new_buffer, but does not take ownership. */ fz_buffer *fz_new_buffer_from_shared_data(fz_context *ctx, const unsigned char *data, size_t size); -/* - fz_new_buffer_from_copied_data: Create a new buffer containing a copy of the passed data. +/** + Create a new buffer containing a copy of the passed data. */ -fz_buffer * -fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size); +fz_buffer *fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size); -/* - fz_new_buffer_from_base64: Create a new buffer with data decoded from a base64 input string. +/** + Make a new buffer, containing a copy of the data used in + the original. +*/ +fz_buffer *fz_clone_buffer(fz_context *ctx, fz_buffer *buf); + +/** + Create a new buffer with data decoded from a base64 input string. */ fz_buffer *fz_new_buffer_from_base64(fz_context *ctx, const char *data, size_t size); -/* - fz_resize_buffer: Ensure that a buffer has a given capacity, +/** + Ensure that a buffer has a given capacity, truncating data if required. - capacity: The desired capacity for the buffer. If the current size - of the buffer contents is smaller than capacity, it is truncated. + capacity: The desired capacity for the buffer. If the current + size of the buffer contents is smaller than capacity, it is + truncated. */ void fz_resize_buffer(fz_context *ctx, fz_buffer *buf, size_t capacity); -/* - fz_grow_buffer: Make some space within a buffer (i.e. ensure that +/** + Make some space within a buffer (i.e. ensure that capacity > size). */ void fz_grow_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_trim_buffer: Trim wasted capacity from a buffer by resizing internal memory. +/** + Trim wasted capacity from a buffer by resizing internal memory. */ void fz_trim_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_append_buffer: Append the contents of source buffer to destination buffer. +/** + Empties the buffer. Storage is not freed, but is held ready + to be reused as the buffer is refilled. + + Never throws exceptions. +*/ +void fz_clear_buffer(fz_context *ctx, fz_buffer *buf); + +/** + Create a new buffer with a (subset of) the data from the buffer. + + start: if >= 0, offset from start of buffer, if < 0 offset from end of buffer. + + end: if >= 0, offset from start of buffer, if < 0 offset from end of buffer. + +*/ +fz_buffer *fz_slice_buffer(fz_context *ctx, fz_buffer *buf, int64_t start, int64_t end); + +/** + Append the contents of the source buffer onto the end of the + destination buffer, extending automatically as required. + + Ownership of buffers does not change. */ void fz_append_buffer(fz_context *ctx, fz_buffer *destination, fz_buffer *source); -/* +/** + Write a base64 encoded data block, optionally with periodic newlines. +*/ +void fz_append_base64(fz_context *ctx, fz_buffer *out, const unsigned char *data, size_t size, int newline); + +/** + Append a base64 encoded fz_buffer, optionally with periodic newlines. +*/ +void fz_append_base64_buffer(fz_context *ctx, fz_buffer *out, fz_buffer *data, int newline); + +/** fz_append_*: Append data to a buffer. - fz_append_printf: Format and append data to buffer using printf-like formatting (see fz_vsnprintf). - fz_append_pdf_string: Append a string with PDF syntax quotes and escapes. + The buffer will automatically grow as required. */ void fz_append_data(fz_context *ctx, fz_buffer *buf, const void *data, size_t len); @@ -120,25 +187,53 @@ void fz_append_int32_be(fz_context *ctx, fz_buffer *buf, int x); void fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int x); void fz_append_bits(fz_context *ctx, fz_buffer *buf, int value, int count); void fz_append_bits_pad(fz_context *ctx, fz_buffer *buf); -void fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...); -void fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args); + +/** + fz_append_pdf_string: Append a string with PDF syntax quotes and + escapes. + + The buffer will automatically grow as required. +*/ void fz_append_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text); -/* - fz_terminate_buffer: Zero-terminate buffer in order to use as a C string. +/** + fz_append_printf: Format and append data to buffer using + printf-like formatting (see fz_vsnprintf). - This byte is invisible and does not affect the length of the buffer as returned by fz_buffer_storage. - The zero byte is written *after* the data, and subsequent writes will overwrite the terminating byte. + The buffer will automatically grow as required. +*/ +void fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...); + +/** + fz_append_vprintf: Format and append data to buffer using + printf-like formatting with varargs (see fz_vsnprintf). +*/ +void fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args); + +/** + Zero-terminate buffer in order to use as a C string. + + This byte is invisible and does not affect the length of the + buffer as returned by fz_buffer_storage. The zero byte is + written *after* the data, and subsequent writes will overwrite + the terminating byte. + + Subsequent changes to the size of the buffer (such as by + fz_buffer_trim, fz_buffer_grow, fz_resize_buffer, etc) may + invalidate this. */ void fz_terminate_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_md5_buffer: Create MD5 digest of buffer contents. +/** + Create an MD5 digest from buffer contents. + + Never throws exceptions. */ void fz_md5_buffer(fz_context *ctx, fz_buffer *buffer, unsigned char digest[16]); -/* - fz_buffer_extract: Take ownership of buffer contents. +/** + Take ownership of buffer contents. + Performs the same task as fz_buffer_storage, but ownership of the data buffer returns with this call. The buffer is left empty. diff --git a/include/mupdf/fitz/color-management.h b/include/mupdf/fitz/color-management.h deleted file mode 100644 index a2f20e9..0000000 --- a/include/mupdf/fitz/color-management.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef MUPDF_FITZ_COLOR_MANAGEMENT_H -#define MUPDF_FITZ_COLOR_MANAGEMENT_H - -#include "mupdf/fitz/colorspace.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/pixmap.h" - -/* - MuPDF can either run with or without color management. By default - MuPDF runs without color management. To enable color management, - a color management engine must be given to the context. - - The context will then create one 'instance' of this engine per - cloned context. Every instance is tied to the particular context - in which it is created. - - Profiles and links can be shared between instances. -*/ - -/* - fz_cmm_new_instance_fn: Create a new instance of the color - management engine, tied to the given context. -*/ -typedef fz_cmm_instance *(fz_cmm_new_instance_fn)(fz_context *ctx); - -/* - fz_cmm_drop_instance_fn: Drop a given instance of the color - management engine. No further calls will be made to this - instance. -*/ -typedef void (fz_cmm_drop_instance_fn)(fz_cmm_instance *instance); - -/* - fz_cmm_transform_pixmap_fn: Transform a pixmap according - to a link. -*/ -typedef void (fz_cmm_transform_pixmap_fn)(fz_cmm_instance *ctx, fz_icclink *link, fz_pixmap *dst, fz_pixmap *src); - -/* - fz_cmm_transform_color_fn: Transform some color values according - to a link. -*/ -typedef void (fz_cmm_transform_color_fn)(fz_cmm_instance *ctx, fz_icclink *link, unsigned short *dst, const unsigned short *src); - -/* - fz_cmm_init_link_fn: Create a new link between icc profiles. -*/ -typedef void (fz_cmm_init_link_fn)(fz_cmm_instance *ctx, fz_icclink *link, const fz_iccprofile *dst, int dst_extras, const fz_iccprofile *src, int src_extras, const fz_iccprofile *prf, const fz_color_params *rend, int cmm_flags, int num_bytes, int copy_spots); - -/* - fz_cmm_fin_link_fn: Drop a link. -*/ -typedef void (fz_cmm_fin_link_fn)(fz_cmm_instance *ctx, fz_icclink *link); - -/* - fz_cmm_init_profile_fn: Create the cmm specific data for the given - profile. The cmm handle is stored to profile->cmm_handle. -*/ -typedef void (fz_cmm_init_profile_fn)(fz_cmm_instance *ctx, fz_iccprofile *profile); - -/* - fz_cmm_fin_profile_fn: Drop the cmm specific data for the given - profile. -*/ -typedef void (fz_cmm_fin_profile_fn)(fz_cmm_instance *ctx, fz_iccprofile *profile); - -/* - Encapsulate details for a given color management engine into a single - structure. -*/ -struct fz_cmm_engine_s { - fz_cmm_new_instance_fn *new_instance; - fz_cmm_drop_instance_fn *drop_instance; - fz_cmm_transform_pixmap_fn *transform_pixmap; - fz_cmm_transform_color_fn *transform_color; - fz_cmm_init_link_fn *init_link; - fz_cmm_fin_link_fn *fin_link; - fz_cmm_init_profile_fn *init_profile; - fz_cmm_fin_profile_fn *fin_profile; - int avoid_white_fix_flag; -}; - -/* - fz_get_cmm_engine: Read details of the current color - management engine. If NULL, we are working without - color management. -*/ -const fz_cmm_engine *fz_get_cmm_engine(fz_context *ctx); - -/* - fz_set_cmm_engine: Set the color management engine to - be used. This should only ever be called on the "base" - context before cloning it, and before opening any files. - - Attempting to change the engine in use once a file has - been opened, or to use different color management engine - for the same file in different threads will lead to - undefined behaviour, including crashing. - - Using different ICC engines for different files using - different sets of fz_contexts should theoretically be - possible. -*/ -void fz_set_cmm_engine(fz_context *ctx, const fz_cmm_engine *engine); - -/* - Currently we only provide a single color management - engine, based on a (modified) LCMS2. - - An unmodified LCMS2 should work too, but only when restricted - to a single thread. -*/ -extern fz_cmm_engine fz_cmm_engine_lcms; - -#endif diff --git a/include/mupdf/fitz/color.h b/include/mupdf/fitz/color.h new file mode 100644 index 0000000..0a7e985 --- /dev/null +++ b/include/mupdf/fitz/color.h @@ -0,0 +1,427 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_COLOR_H +#define MUPDF_FITZ_COLOR_H + +#include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/store.h" + +#if FZ_ENABLE_ICC +/** + Opaque type for an ICC Profile. +*/ +typedef struct fz_icc_profile fz_icc_profile; +#endif + +/** + Describes a given colorspace. +*/ +typedef struct fz_colorspace fz_colorspace; + +/** + Pixmaps represent a set of pixels for a 2 dimensional region of + a plane. Each pixel has n components per pixel. The components + are in the order process-components, spot-colors, alpha, where + there can be 0 of any of those types. The data is in + premultiplied alpha when rendering, but non-premultiplied for + colorspace conversions and rescaling. +*/ +typedef struct fz_pixmap fz_pixmap; + +/* Color handling parameters: rendering intent, overprint, etc. */ + +enum +{ + /* Same order as needed by lcms */ + FZ_RI_PERCEPTUAL, + FZ_RI_RELATIVE_COLORIMETRIC, + FZ_RI_SATURATION, + FZ_RI_ABSOLUTE_COLORIMETRIC, +}; + +typedef struct +{ + uint8_t ri; /* rendering intent */ + uint8_t bp; /* black point compensation */ + uint8_t op; /* overprinting */ + uint8_t opm; /* overprint mode */ +} fz_color_params; + +FZ_DATA extern const fz_color_params fz_default_color_params; + +/** + Map from (case sensitive) rendering intent string to enumeration + value. +*/ +int fz_lookup_rendering_intent(const char *name); + +/** + Map from enumerated rendering intent to string. + + The returned string is static and therefore must not be freed. +*/ +const char *fz_rendering_intent_name(int ri); + +/** + The maximum number of colorants available in any given + color/colorspace (not including alpha). + + Changing this value will alter the amount of memory being used + (both stack and heap space), but not hugely. Speed should + (largely) be determined by the number of colors actually used. +*/ +enum { FZ_MAX_COLORS = 32 }; + +enum fz_colorspace_type +{ + FZ_COLORSPACE_NONE, + FZ_COLORSPACE_GRAY, + FZ_COLORSPACE_RGB, + FZ_COLORSPACE_BGR, + FZ_COLORSPACE_CMYK, + FZ_COLORSPACE_LAB, + FZ_COLORSPACE_INDEXED, + FZ_COLORSPACE_SEPARATION, +}; + +enum +{ + FZ_COLORSPACE_IS_DEVICE = 1, + FZ_COLORSPACE_IS_ICC = 2, + FZ_COLORSPACE_HAS_CMYK = 4, + FZ_COLORSPACE_HAS_SPOTS = 8, + FZ_COLORSPACE_HAS_CMYK_AND_SPOTS = 4|8, +}; + +/** + Creates a new colorspace instance and returns a reference. + + No internal checking is done that the colorspace type (e.g. + CMYK) matches with the flags (e.g. FZ_COLORSPACE_HAS_CMYK) or + colorant count (n) or name. + + The reference should be dropped when it is finished with. + + Colorspaces are immutable once created (with the exception of + setting up colorant names for separation spaces). +*/ +fz_colorspace *fz_new_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, int n, const char *name); + +/** + Increment the reference count for the colorspace. + + Returns the same pointer. Never throws an exception. +*/ +fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace); + +/** + Drops a reference to the colorspace. + + When the reference count reaches zero, the colorspace is + destroyed. +*/ +void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace); + +/** + Create an indexed colorspace. + + The supplied lookup table is high palette entries long. Each + entry is n bytes long, where n is given by the number of + colorants in the base colorspace, one byte per colorant. + + Ownership of lookup is passed it; it will be freed on + destruction, so must be heap allocated. + + The colorspace will keep an additional reference to the base + colorspace that will be dropped on destruction. + + The returned reference should be dropped when it is finished + with. + + Colorspaces are immutable once created. +*/ +fz_colorspace *fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup); + +/** + Create a colorspace from an ICC profile supplied in buf. + + Limited checking is done to ensure that the colorspace type is + appropriate for the supplied ICC profile. + + An additional reference is taken to buf, which will be dropped + on destruction. Ownership is NOT passed in. + + The returned reference should be dropped when it is finished + with. + + Colorspaces are immutable once created. +*/ +fz_colorspace *fz_new_icc_colorspace(fz_context *ctx, enum fz_colorspace_type type, int flags, const char *name, fz_buffer *buf); + + +/** + Create a calibrated gray colorspace. + + The returned reference should be dropped when it is finished + with. + + Colorspaces are immutable once created. +*/ +fz_colorspace *fz_new_cal_gray_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma); + +/** + Create a calibrated rgb colorspace. + + The returned reference should be dropped when it is finished + with. + + Colorspaces are immutable once created. +*/ +fz_colorspace *fz_new_cal_rgb_colorspace(fz_context *ctx, float wp[3], float bp[3], float gamma[3], float matrix[9]); + +/** + Query the type of colorspace. +*/ +enum fz_colorspace_type fz_colorspace_type(fz_context *ctx, fz_colorspace *cs); + +/** + Query the name of a colorspace. + + The returned string has the same lifespan as the colorspace + does. Caller should not free it. +*/ +const char *fz_colorspace_name(fz_context *ctx, fz_colorspace *cs); + +/** + Query the number of colorants in a colorspace. +*/ +int fz_colorspace_n(fz_context *ctx, fz_colorspace *cs); + +/** + True for CMYK, Separation and DeviceN colorspaces. +*/ +int fz_colorspace_is_subtractive(fz_context *ctx, fz_colorspace *cs); + +/** + True if DeviceN color space has only colorants from the CMYK set. +*/ +int fz_colorspace_device_n_has_only_cmyk(fz_context *ctx, fz_colorspace *cs); + +/** + True if DeviceN color space has cyan magenta yellow or black as + one of its colorants. +*/ +int fz_colorspace_device_n_has_cmyk(fz_context *ctx, fz_colorspace *cs); + +/** + Tests for particular types of colorspaces +*/ +int fz_colorspace_is_gray(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_rgb(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_cmyk(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_lab(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_indexed(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_device_n(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_device(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_device_gray(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_device_cmyk(fz_context *ctx, fz_colorspace *cs); +int fz_colorspace_is_lab_icc(fz_context *ctx, fz_colorspace *cs); + +/** + Check to see that a colorspace is appropriate to be used as + a blending space (i.e. only grey, rgb or cmyk). +*/ +int fz_is_valid_blend_colorspace(fz_context *ctx, fz_colorspace *cs); + +/** + Get the 'base' colorspace for a colorspace. + + For indexed colorspaces, this is the colorspace the index + decodes into. For all other colorspaces, it is the colorspace + itself. + + The returned colorspace is 'borrowed' (i.e. no additional + references are taken or dropped). +*/ +fz_colorspace *fz_base_colorspace(fz_context *ctx, fz_colorspace *cs); + +/** + Retrieve global default colorspaces. + + These return borrowed references that should not be dropped, + unless they are kept first. +*/ +fz_colorspace *fz_device_gray(fz_context *ctx); +fz_colorspace *fz_device_rgb(fz_context *ctx); +fz_colorspace *fz_device_bgr(fz_context *ctx); +fz_colorspace *fz_device_cmyk(fz_context *ctx); +fz_colorspace *fz_device_lab(fz_context *ctx); + +/** + Assign a name for a given colorant in a colorspace. + + Used while initially setting up a colorspace. The string is + copied into local storage, so need not be retained by the + caller. +*/ +void fz_colorspace_name_colorant(fz_context *ctx, fz_colorspace *cs, int n, const char *name); + +/** + Retrieve a the name for a colorant. + + Returns a pointer with the same lifespan as the colorspace. +*/ +const char *fz_colorspace_colorant(fz_context *ctx, fz_colorspace *cs, int n); + +/* Color conversion */ + +/** + Clamp the samples in a color to the correct ranges for a + given colorspace. +*/ +void fz_clamp_color(fz_context *ctx, fz_colorspace *cs, const float *in, float *out); + +/** + Convert color values sv from colorspace ss into colorvalues dv + for colorspace ds, via an optional intervening space is, + respecting the given color_params. +*/ +void fz_convert_color(fz_context *ctx, fz_colorspace *ss, const float *sv, fz_colorspace *ds, float *dv, fz_colorspace *is, fz_color_params params); + +/* Default (fallback) colorspace handling */ + +/** + Structure to hold default colorspaces. +*/ +typedef struct +{ + int refs; + fz_colorspace *gray; + fz_colorspace *rgb; + fz_colorspace *cmyk; + fz_colorspace *oi; +} fz_default_colorspaces; + +/** + Create a new default colorspace structure with values inherited + from the context, and return a reference to it. + + These can be overridden using fz_set_default_xxxx. + + These should not be overridden while more than one caller has + the reference for fear of race conditions. + + The caller should drop this reference once finished with it. +*/ +fz_default_colorspaces *fz_new_default_colorspaces(fz_context *ctx); + +/** + Keep an additional reference to the default colorspaces + structure. + + Never throws exceptions. +*/ +fz_default_colorspaces* fz_keep_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs); + +/** + Drop a reference to the default colorspaces structure. When the + reference count reaches 0, the references it holds internally + to the underlying colorspaces will be dropped, and the structure + will be destroyed. + + Never throws exceptions. +*/ +void fz_drop_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs); + +/** + Returns a reference to a newly cloned default colorspaces + structure. + + The new clone may safely be altered without fear of race + conditions as the caller is the only reference holder. +*/ +fz_default_colorspaces *fz_clone_default_colorspaces(fz_context *ctx, fz_default_colorspaces *base); + +/** + Retrieve default colorspaces (typically page local). + + If default_cs is non NULL, the default is retrieved from there, + otherwise the global default is retrieved. + + These return borrowed references that should not be dropped, + unless they are kept first. +*/ +fz_colorspace *fz_default_gray(fz_context *ctx, const fz_default_colorspaces *default_cs); +fz_colorspace *fz_default_rgb(fz_context *ctx, const fz_default_colorspaces *default_cs); +fz_colorspace *fz_default_cmyk(fz_context *ctx, const fz_default_colorspaces *default_cs); +fz_colorspace *fz_default_output_intent(fz_context *ctx, const fz_default_colorspaces *default_cs); + +/** + Set new defaults within the default colorspace structure. + + New references are taken to the new default, and references to + the old defaults dropped. + + Never throws exceptions. +*/ +void fz_set_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); +void fz_set_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); +void fz_set_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); +void fz_set_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); + +/* Implementation details: subject to change. */ + +struct fz_colorspace +{ + fz_key_storable key_storable; + enum fz_colorspace_type type; + int flags; + int n; + char *name; + union { +#if FZ_ENABLE_ICC + struct { + fz_buffer *buffer; + unsigned char md5[16]; + fz_icc_profile *profile; + } icc; +#endif + struct { + fz_colorspace *base; + int high; + unsigned char *lookup; + } indexed; + struct { + fz_colorspace *base; + void (*eval)(fz_context *ctx, void *tint, const float *s, int sn, float *d, int dn); + void (*drop)(fz_context *ctx, void *tint); + void *tint; + char *colorant[FZ_MAX_COLORS]; + } separation; + } u; +}; + +void fz_drop_colorspace_imp(fz_context *ctx, fz_storable *cs_); + +#endif diff --git a/include/mupdf/fitz/colorspace.h b/include/mupdf/fitz/colorspace.h deleted file mode 100644 index d5d4e46..0000000 --- a/include/mupdf/fitz/colorspace.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef MUPDF_FITZ_COLORSPACE_H -#define MUPDF_FITZ_COLORSPACE_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/store.h" - -enum { FZ_MAX_COLORS = 32 }; - -enum -{ - /* Same order as needed by lcms */ - FZ_RI_PERCEPTUAL, - FZ_RI_RELATIVE_COLORIMETRIC, - FZ_RI_SATURATION, - FZ_RI_ABSOLUTE_COLORIMETRIC, -}; - -enum -{ - FZ_COLORSPACE_IS_DEVICE = 1, - FZ_COLORSPACE_IS_ICC = 2, - FZ_COLORSPACE_IS_CAL = 4, - FZ_COLORSPACE_LAST_PUBLIC_FLAG = 8, -}; - -typedef struct fz_color_params_s fz_color_params; - -struct fz_color_params_s -{ - uint8_t ri; - uint8_t bp; - uint8_t op; - uint8_t opm; -}; - -int fz_lookup_rendering_intent(const char *name); -char *fz_rendering_intent_name(int ri); - -/* - A fz_colorspace object represents an abstract colorspace. While - this should be treated as a black box by callers of the library at - this stage, know that it encapsulates knowledge of how to convert - colors to and from the colorspace, any lookup tables generated, the - number of components in the colorspace etc. -*/ -typedef struct fz_colorspace_s fz_colorspace; - -enum fz_colorspace_type -{ - FZ_COLORSPACE_NONE, - FZ_COLORSPACE_GRAY, - FZ_COLORSPACE_RGB, - FZ_COLORSPACE_BGR, - FZ_COLORSPACE_CMYK, - FZ_COLORSPACE_LAB, - FZ_COLORSPACE_INDEXED, - FZ_COLORSPACE_SEPARATION, -}; - -enum fz_colorspace_type fz_colorspace_type(fz_context *ctx, fz_colorspace *cs); - -/* - A fz_iccprofile object encapsulates details about the icc profile. It - also includes the profile handle provided by the cmm and as such is used - in the creation of links between color spaces. -*/ -typedef struct fz_iccprofile_s fz_iccprofile; - -/* - A fz_icclink object encapsulates details about the link between profiles. -*/ -typedef struct fz_icclink_s fz_icclink; - -/* - Used to communicate any document internal page specific default color spaces. -*/ -typedef struct fz_default_colorspaces_s fz_default_colorspaces; - -/* - fz_colorspace_is_subtractive: Return true if a colorspace is subtractive. - - True for CMYK, Separation and DeviceN colorspaces. -*/ -int fz_colorspace_is_subtractive(fz_context *ctx, const fz_colorspace *cs); - -/* - fz_colorspace_device_n_has_only_cmyk: Return true if devicen color space - has only colorants from the cmyk set. -*/ -int fz_colorspace_device_n_has_only_cmyk(fz_context *ctx, const fz_colorspace *cs); - -/* - fz_colorspace_device_n_has_cmyk: Return true if devicen color space has cyan - magenta yellow or black as one of its colorants. -*/ -int fz_colorspace_device_n_has_cmyk(fz_context *ctx, const fz_colorspace *cs); - -/* - Colorspace feature test functions. -*/ -int fz_colorspace_is_gray(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_rgb(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_bgr(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_cmyk(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_lab(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_indexed(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_device_n(fz_context *ctx, const fz_colorspace *cs); - -int fz_colorspace_is_device(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_icc(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_cal(fz_context *ctx, const fz_colorspace *cs); - -int fz_colorspace_is_device_gray(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_is_device_cmyk(fz_context *ctx, const fz_colorspace *cs); - -int fz_colorspace_is_lab_icc(fz_context *ctx, const fz_colorspace *cs); - -/* - fz_device_gray: Get colorspace representing device specific gray. -*/ -fz_colorspace *fz_device_gray(fz_context *ctx); - -/* - fz_device_rgb: Get colorspace representing device specific rgb. -*/ -fz_colorspace *fz_device_rgb(fz_context *ctx); - -/* - fz_device_bgr: Get colorspace representing device specific bgr. -*/ -fz_colorspace *fz_device_bgr(fz_context *ctx); - -/* - fz_device_cmyk: Get colorspace representing device specific CMYK. -*/ -fz_colorspace *fz_device_cmyk(fz_context *ctx); - -/* - fz_device_lab: Get colorspace representing device specific LAB. -*/ -fz_colorspace *fz_device_lab(fz_context *ctx); - -/* - fz_default_color_params: Get default color params for general color conversion. -*/ -const fz_color_params *fz_default_color_params(fz_context *ctx); - -typedef void (fz_colorspace_convert_fn)(fz_context *ctx, const fz_colorspace *cs, const float *src, float *dst); - -typedef void (fz_colorspace_destruct_fn)(fz_context *ctx, fz_colorspace *cs); - -typedef fz_colorspace *(fz_colorspace_base_fn)(const fz_colorspace *cs); - -typedef void (fz_colorspace_clamp_fn)(const fz_colorspace *cs, const float *src, float *dst); - -fz_colorspace *fz_new_colorspace(fz_context *ctx, const char *name, enum fz_colorspace_type type, int flags, int n, fz_colorspace_convert_fn *to_ccs, fz_colorspace_convert_fn *from_ccs, fz_colorspace_base_fn *base, fz_colorspace_clamp_fn *clamp, fz_colorspace_destruct_fn *destruct, void *data, size_t size); -void fz_colorspace_name_colorant(fz_context *ctx, fz_colorspace *cs, int n, const char *name); -const char *fz_colorspace_colorant(fz_context *ctx, const fz_colorspace *cs, int n); -fz_colorspace *fz_new_indexed_colorspace(fz_context *ctx, fz_colorspace *base, int high, unsigned char *lookup); -fz_colorspace *fz_keep_colorspace(fz_context *ctx, fz_colorspace *colorspace); -fz_colorspace *fz_keep_colorspace_store_key(fz_context *ctx, fz_colorspace *colorspace); -void fz_drop_colorspace_store_key(fz_context *ctx, fz_colorspace *colorspace); - -void fz_drop_colorspace(fz_context *ctx, fz_colorspace *colorspace); -void fz_drop_colorspace_imp(fz_context *ctx, fz_storable *colorspace); - -fz_colorspace *fz_colorspace_base(fz_context *ctx, const fz_colorspace *cs); -void fz_set_icc_bgr(fz_context *ctx, fz_colorspace *cs); -int fz_colorspace_n(fz_context *ctx, const fz_colorspace *cs); -int fz_colorspace_devicen_n(fz_context *ctx, const fz_colorspace *cs); -const char *fz_colorspace_name(fz_context *ctx, const fz_colorspace *cs); -void fz_clamp_color(fz_context *ctx, const fz_colorspace *cs, const float *in, float *out); -void fz_convert_color(fz_context *ctx, const fz_color_params *params, const fz_colorspace *intcs, const fz_colorspace *dscs, float *dstv, const fz_colorspace *srcs, const float *srcv); - -typedef struct fz_color_converter_s fz_color_converter; - -/* This structure is public because it allows us to avoid dynamic allocations. - * Callers should only rely on the convert entry - the rest of the structure - * is subject to change without notice. - */ -struct fz_color_converter_s -{ - void (*convert)(fz_context *, fz_color_converter *, float *, const float *); - const fz_colorspace *ds; - const fz_colorspace *ss; - const fz_colorspace *is; - void *opaque; - void *link; - int n; -}; - -void fz_find_color_converter(fz_context *ctx, fz_color_converter *cc, const fz_colorspace *is, const fz_colorspace *ds, const fz_colorspace *ss, const fz_color_params *params); -void fz_drop_color_converter(fz_context *ctx, fz_color_converter *cc); -void fz_init_cached_color_converter(fz_context *ctx, fz_color_converter *cc, fz_colorspace *is, fz_colorspace *ds, fz_colorspace *ss, const fz_color_params *params); -void fz_fin_cached_color_converter(fz_context *ctx, fz_color_converter *cc); - -/* Public to allow use in icc creation */ -typedef struct fz_cal_colorspace_s fz_cal_colorspace; - -struct fz_cal_colorspace_s { - float wp[3]; - float bp[3]; - float gamma[3]; - float matrix[9]; - int n; - fz_iccprofile *profile; -}; - -/* - icc methods -*/ -fz_colorspace *fz_new_icc_colorspace(fz_context *ctx, const char *name, int num, fz_buffer *buf); -fz_colorspace *fz_new_icc_colorspace_from_file(fz_context *ctx, const char *name, const char *path); -fz_colorspace *fz_new_icc_colorspace_from_stream(fz_context *ctx, const char *name, fz_stream *in); -fz_colorspace *fz_new_cal_colorspace(fz_context *ctx, const char *name, float *wp, float *bp, float *gamma, float *matrix); -fz_buffer *fz_new_icc_data_from_cal_colorspace(fz_context *ctx, fz_cal_colorspace *cal); -fz_buffer *fz_icc_data_from_icc_colorspace(fz_context *ctx, const fz_colorspace *cs); - -/* Default cs */ -fz_default_colorspaces *fz_new_default_colorspaces(fz_context *ctx); -fz_default_colorspaces* fz_keep_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs); -void fz_drop_default_colorspaces(fz_context *ctx, fz_default_colorspaces *default_cs); -fz_default_colorspaces *fz_clone_default_colorspaces(fz_context *ctx, fz_default_colorspaces *base); - -/* Do we want to make fz_default_colorspaces public and get rid of these? */ -void fz_set_default_gray(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); -void fz_set_default_rgb(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); -void fz_set_default_cmyk(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); -void fz_set_default_output_intent(fz_context *ctx, fz_default_colorspaces *default_cs, fz_colorspace *cs); - -fz_colorspace *fz_default_gray(fz_context *ctx, const fz_default_colorspaces *default_cs); -fz_colorspace *fz_default_rgb(fz_context *ctx, const fz_default_colorspaces *default_cs); -fz_colorspace *fz_default_cmyk(fz_context *ctx, const fz_default_colorspaces *default_cs); -fz_colorspace *fz_default_output_intent(fz_context *ctx, const fz_default_colorspaces *default_cs); - -#endif diff --git a/include/mupdf/fitz/compress.h b/include/mupdf/fitz/compress.h index cfd4ed1..9acf1cf 100644 --- a/include/mupdf/fitz/compress.h +++ b/include/mupdf/fitz/compress.h @@ -1,7 +1,31 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_COMPRESS_H #define MUPDF_FITZ_COMPRESS_H #include "mupdf/fitz/system.h" +#include "mupdf/fitz/buffer.h" +#include "mupdf/fitz/pixmap.h" typedef enum { @@ -11,22 +35,22 @@ typedef enum FZ_DEFLATE_DEFAULT = -1 } fz_deflate_level; -/* - fz_deflate_bound: Returns the upper bound on the +/** + Returns the upper bound on the size of flated data of length size. */ size_t fz_deflate_bound(fz_context *ctx, size_t size); -/* - fz_deflate: Compress source_length bytes of data starting +/** + Compress source_length bytes of data starting at source, into a buffer of length *destLen, starting at dest. *compressed_length will be updated on exit to contain the size actually used. */ void fz_deflate(fz_context *ctx, unsigned char *dest, size_t *compressed_length, const unsigned char *source, size_t source_length, fz_deflate_level level); -/* - fz_new_deflated_data: Compress source_length bytes of data starting +/** + Compress source_length bytes of data starting at source, into a new memory block malloced for that purpose. *compressed_length is updated on exit to contain the size used. Ownership of the block is returned from this function, and the @@ -36,15 +60,29 @@ void fz_deflate(fz_context *ctx, unsigned char *dest, size_t *compressed_length, */ unsigned char *fz_new_deflated_data(fz_context *ctx, size_t *compressed_length, const unsigned char *source, size_t source_length, fz_deflate_level level); -/* - fz_new_deflated_data_from_buffer: Compress the contents of a fz_buffer into a - new block malloced for that purpose. *compressed_length is updated - on exit to contain the size used. Ownership of the block is - returned from this function, and the caller is therefore responsible - for freeing it. The block may be considerably larger than is - actually required. The caller is free to fz_realloc it down if it - wants to. +/** + Compress the contents of a fz_buffer into a + new block malloced for that purpose. *compressed_length is + updated on exit to contain the size used. Ownership of the block + is returned from this function, and the caller is therefore + responsible for freeing it. The block may be considerably larger + than is actually required. The caller is free to fz_realloc it + down if it wants to. */ unsigned char *fz_new_deflated_data_from_buffer(fz_context *ctx, size_t *compressed_length, fz_buffer *buffer, fz_deflate_level level); +/** + Compress bitmap data as CCITT Group 3 1D fax image. + Creates a stream assuming the default PDF parameters, + except the number of columns. +*/ +fz_buffer *fz_compress_ccitt_fax_g3(fz_context *ctx, const unsigned char *data, int columns, int rows, ptrdiff_t stride); + +/** + Compress bitmap data as CCITT Group 4 2D fax image. + Creates a stream assuming the default PDF parameters, except + K=-1 and the number of columns. +*/ +fz_buffer *fz_compress_ccitt_fax_g4(fz_context *ctx, const unsigned char *data, int columns, int rows, ptrdiff_t stride); + #endif diff --git a/include/mupdf/fitz/compressed-buffer.h b/include/mupdf/fitz/compressed-buffer.h index 995f560..5f88649 100644 --- a/include/mupdf/fitz/compressed-buffer.h +++ b/include/mupdf/fitz/compressed-buffer.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_COMPRESSED_BUFFER_H #define MUPDF_FITZ_COMPRESSED_BUFFER_H @@ -5,52 +27,27 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/buffer.h" #include "mupdf/fitz/stream.h" +#include "mupdf/fitz/filter.h" -typedef struct fz_compression_params_s fz_compression_params; - -typedef struct fz_compressed_buffer_s fz_compressed_buffer; -size_t fz_compressed_buffer_size(fz_compressed_buffer *buffer); - -fz_stream *fz_open_compressed_buffer(fz_context *ctx, fz_compressed_buffer *); -fz_stream *fz_open_image_decomp_stream_from_buffer(fz_context *ctx, fz_compressed_buffer *, int *l2factor); -fz_stream *fz_open_image_decomp_stream(fz_context *ctx, fz_stream *, fz_compression_params *, int *l2factor); - -int fz_recognize_image_format(fz_context *ctx, unsigned char p[8]); - -enum -{ - FZ_IMAGE_UNKNOWN = 0, - - /* Uncompressed samples */ - FZ_IMAGE_RAW, - - /* Compressed samples */ - FZ_IMAGE_FAX, - FZ_IMAGE_FLATE, - FZ_IMAGE_LZW, - FZ_IMAGE_RLD, - - /* Full image formats */ - FZ_IMAGE_BMP, - FZ_IMAGE_GIF, - FZ_IMAGE_JPEG, - FZ_IMAGE_JPX, - FZ_IMAGE_JXR, - FZ_IMAGE_PNG, - FZ_IMAGE_PNM, - FZ_IMAGE_TIFF, -}; - -struct fz_compression_params_s +/** + Compression parameters used for buffers of compressed data; + typically for the source data for images. +*/ +typedef struct { int type; union { struct { int color_transform; /* Use -1 for unset */ + int invert_cmyk; /* Use 1 for standalone JPEG files */ } jpeg; struct { int smask_in_data; } jpx; + struct { + fz_jbig2_globals *globals; + int embedded; + } jbig2; struct { int columns; int rows; @@ -78,14 +75,111 @@ struct fz_compression_params_s int early_change; } lzw; } u; -}; +} fz_compression_params; -struct fz_compressed_buffer_s +/** + Buffers of compressed data; typically for the source data + for images. +*/ +typedef struct { + int refs; fz_compression_params params; fz_buffer *buffer; +} fz_compressed_buffer; + +/** + Take a reference to an fz_compressed_buffer. +*/ +fz_compressed_buffer *fz_keep_compressed_buffer(fz_context *ctx, fz_compressed_buffer *cbuf); + +/** + Return the storage size used for a buffer and its data. + Used in implementing store handling. + + Never throws exceptions. +*/ +size_t fz_compressed_buffer_size(fz_compressed_buffer *buffer); + +/** + Open a stream to read the decompressed version of a buffer. +*/ +fz_stream *fz_open_compressed_buffer(fz_context *ctx, fz_compressed_buffer *); + +/** + Open a stream to read the decompressed version of a buffer, + with optional log2 subsampling. + + l2factor = NULL for no subsampling, or a pointer to an integer + containing the maximum log2 subsample factor acceptable (0 = + none, 1 = halve dimensions, 2 = quarter dimensions etc). If + non-NULL, then *l2factor will be updated on exit with the actual + log2 subsample factor achieved. +*/ +fz_stream *fz_open_image_decomp_stream_from_buffer(fz_context *ctx, fz_compressed_buffer *, int *l2factor); + +/** + Open a stream to read the decompressed version of another stream + with optional log2 subsampling. +*/ +fz_stream *fz_open_image_decomp_stream(fz_context *ctx, fz_stream *, fz_compression_params *, int *l2factor); + +/** + Recognise image format strings in the first 8 bytes from image + data. +*/ +int fz_recognize_image_format(fz_context *ctx, unsigned char p[8]); + +/** + Map from FZ_IMAGE_* value to string. + + The returned string is static and therefore must not be freed. +*/ +const char *fz_image_type_name(int type); + +/** + Map from (case sensitive) image type string to FZ_IMAGE_* + type value. +*/ +int fz_lookup_image_type(const char *type); + +enum +{ + FZ_IMAGE_UNKNOWN = 0, + + /* Uncompressed samples */ + FZ_IMAGE_RAW, + + /* Compressed samples */ + FZ_IMAGE_FAX, + FZ_IMAGE_FLATE, + FZ_IMAGE_LZW, + FZ_IMAGE_RLD, + + /* Full image formats */ + FZ_IMAGE_BMP, + FZ_IMAGE_GIF, + FZ_IMAGE_JBIG2, + FZ_IMAGE_JPEG, + FZ_IMAGE_JPX, + FZ_IMAGE_JXR, + FZ_IMAGE_PNG, + FZ_IMAGE_PNM, + FZ_IMAGE_TIFF, + FZ_IMAGE_PSD, }; +/** + Drop a reference to a compressed buffer. Destroys the buffer + and frees any storage/other references held by it. + + Never throws exceptions. +*/ void fz_drop_compressed_buffer(fz_context *ctx, fz_compressed_buffer *buf); +/** + Create a new, UNKNOWN format, compressed_buffer. +*/ +fz_compressed_buffer *fz_new_compressed_buffer(fz_context *ctx); + #endif diff --git a/include/mupdf/fitz/config.h b/include/mupdf/fitz/config.h index 7fc38c8..f0c139e 100644 --- a/include/mupdf/fitz/config.h +++ b/include/mupdf/fitz/config.h @@ -1,14 +1,36 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef FZ_CONFIG_H #define FZ_CONFIG_H -/* +/** Enable the following for spot (and hence overprint/overprint simulation) capable rendering. This forces FZ_PLOTTERS_N on. */ -#define FZ_ENABLE_SPOT_RENDERING +/* #define FZ_ENABLE_SPOT_RENDERING 1 */ -/* +/** Choose which plotters we need. By default we build all the plotters in. To avoid building plotters in that aren't needed, define the unwanted @@ -19,9 +41,9 @@ /* #define FZ_PLOTTERS_CMYK 1 */ /* #define FZ_PLOTTERS_N 1 */ -/* +/** Choose which document agents to include. - By default all but GPRF are enabled. To avoid building unwanted + By default all are enabled. To avoid building unwanted ones, define FZ_ENABLE_... to 0. */ /* #define FZ_ENABLE_PDF 1 */ @@ -29,12 +51,24 @@ /* #define FZ_ENABLE_SVG 1 */ /* #define FZ_ENABLE_CBZ 1 */ /* #define FZ_ENABLE_IMG 1 */ -/* #define FZ_ENABLE_TIFF 1 */ /* #define FZ_ENABLE_HTML 1 */ /* #define FZ_ENABLE_EPUB 1 */ -/* #define FZ_ENABLE_GPRF 1 */ -/* +/** + Choose which document writers to include. + By default all are enabled. To avoid building unwanted + ones, define FZ_ENABLE_..._OUTPUT to 0. +*/ +/* #define FZ_ENABLE_OCR_OUTPUT 1 */ +/* #define FZ_ENABLE_DOCX_OUTPUT 1 */ +/* #define FZ_ENABLE_ODT_OUTPUT 1 */ + +/** + Choose whether to enable ICC color profiles. +*/ +/* #define FZ_ENABLE_ICC 1 */ + +/** Choose whether to enable JPEG2000 decoding. By default, it is enabled, but due to frequent security issues with the third party libraries we support disabling @@ -42,13 +76,14 @@ */ /* #define FZ_ENABLE_JPX 1 */ -/* +/** Choose whether to enable JavaScript. - By default JavaScript is enabled both for mutool and PDF interactivity. + By default JavaScript is enabled both for mutool and PDF + interactivity. */ /* #define FZ_ENABLE_JS 1 */ -/* +/** Choose which fonts to include. By default we include the base 14 PDF fonts, DroidSansFallback from Android for CJK, and @@ -57,12 +92,14 @@ unwanted fonts. */ /* To avoid all noto fonts except CJK, enable: */ -/* #define TOFU */ +#define TOFU -/* To skip the CJK font, enable: (this implicitly enables TOFU_CJK_EXT and TOFU_CJK_LANG) */ -/* #define TOFU_CJK */ +/* To skip the CJK font, enable: (this implicitly enables TOFU_CJK_EXT + * and TOFU_CJK_LANG) */ +#define TOFU_CJK -/* To skip CJK Extension A, enable: (this implicitly enables TOFU_CJK_LANG) */ +/* To skip CJK Extension A, enable: (this implicitly enables + * TOFU_CJK_LANG) */ /* #define TOFU_CJK_EXT */ /* To skip CJK language specific fonts, enable: */ @@ -80,16 +117,18 @@ /* To skip the SIL fonts, enable: */ /* #define TOFU_SIL */ -/* To skip the ICC profiles, enable: */ -/* #define NO_ICC */ - /* To skip the Base14 fonts, enable: */ /* #define TOFU_BASE14 */ -/* (You probably really don't want to do that except for measurement purposes!) */ +/* (You probably really don't want to do that except for measurement + * purposes!) */ /* ---------- DO NOT EDIT ANYTHING UNDER THIS LINE ---------- */ #ifndef FZ_ENABLE_SPOT_RENDERING +#define FZ_ENABLE_SPOT_RENDERING 1 +#endif + +#if FZ_ENABLE_SPOT_RENDERING #undef FZ_PLOTTERS_N #define FZ_PLOTTERS_N 1 #endif /* FZ_ENABLE_SPOT_RENDERING */ @@ -136,10 +175,6 @@ #define FZ_ENABLE_IMG 1 #endif /* FZ_ENABLE_IMG */ -#ifndef FZ_ENABLE_TIFF -#define FZ_ENABLE_TIFF 1 -#endif /* FZ_ENABLE_TIFF */ - #ifndef FZ_ENABLE_HTML #define FZ_ENABLE_HTML 1 #endif /* FZ_ENABLE_HTML */ @@ -148,9 +183,17 @@ #define FZ_ENABLE_EPUB 1 #endif /* FZ_ENABLE_EPUB */ -#ifndef FZ_ENABLE_GPRF -#define FZ_ENABLE_GPRF 0 -#endif /* FZ_ENABLE_GPRF */ +#ifndef FZ_ENABLE_OCR_OUTPUT +#define FZ_ENABLE_OCR_OUTPUT 1 +#endif /* FZ_ENABLE_OCR_OUTPUT */ + +#ifndef FZ_ENABLE_ODT_OUTPUT +#define FZ_ENABLE_ODT_OUTPUT 1 +#endif /* FZ_ENABLE_ODT_OUTPUT */ + +#ifndef FZ_ENABLE_DOCX_OUTPUT +#define FZ_ENABLE_DOCX_OUTPUT 1 +#endif /* FZ_ENABLE_DOCX_OUTPUT */ #ifndef FZ_ENABLE_JPX #define FZ_ENABLE_JPX 1 @@ -160,10 +203,20 @@ #define FZ_ENABLE_JS 1 #endif /* FZ_ENABLE_JS */ +#ifndef FZ_ENABLE_ICC +#define FZ_ENABLE_ICC 1 +#endif /* FZ_ENABLE_ICC */ + /* If Epub and HTML are both disabled, disable SIL fonts */ #if FZ_ENABLE_HTML == 0 && FZ_ENABLE_EPUB == 0 #undef TOFU_SIL #define TOFU_SIL #endif +#if !defined(HAVE_LEPTONICA) || !defined(HAVE_TESSERACT) +#ifndef OCR_DISABLED +#define OCR_DISABLED +#endif +#endif + #endif /* FZ_CONFIG_H */ diff --git a/include/mupdf/fitz/context.h b/include/mupdf/fitz/context.h index 5a05f94..8277c51 100644 --- a/include/mupdf/fitz/context.h +++ b/include/mupdf/fitz/context.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_CONTEXT_H #define MUPDF_FITZ_CONTEXT_H @@ -5,100 +27,217 @@ #include "mupdf/fitz/system.h" #include "mupdf/fitz/geometry.h" -/* - Contexts + +#ifndef FZ_VERBOSE_EXCEPTIONS +#define FZ_VERBOSE_EXCEPTIONS 0 +#endif + +typedef struct fz_font_context fz_font_context; +typedef struct fz_colorspace_context fz_colorspace_context; +typedef struct fz_style_context fz_style_context; +typedef struct fz_tuning_context fz_tuning_context; +typedef struct fz_store fz_store; +typedef struct fz_glyph_cache fz_glyph_cache; +typedef struct fz_document_handler_context fz_document_handler_context; +typedef struct fz_archive_handler_context fz_archive_handler_context; +typedef struct fz_output fz_output; +typedef struct fz_context fz_context; + +/** + Allocator structure; holds callbacks and private data pointer. */ - -typedef struct fz_alloc_context_s fz_alloc_context; -typedef struct fz_error_context_s fz_error_context; -typedef struct fz_error_stack_slot_s fz_error_stack_slot; -typedef struct fz_id_context_s fz_id_context; -typedef struct fz_warn_context_s fz_warn_context; -typedef struct fz_font_context_s fz_font_context; -typedef struct fz_colorspace_context_s fz_colorspace_context; -typedef struct fz_cmm_engine_s fz_cmm_engine; -typedef struct fz_cmm_instance_s fz_cmm_instance; -typedef struct fz_aa_context_s fz_aa_context; -typedef struct fz_style_context_s fz_style_context; -typedef struct fz_locks_context_s fz_locks_context; -typedef struct fz_tuning_context_s fz_tuning_context; -typedef struct fz_store_s fz_store; -typedef struct fz_glyph_cache_s fz_glyph_cache; -typedef struct fz_document_handler_context_s fz_document_handler_context; -typedef struct fz_output_context_s fz_output_context; -typedef struct fz_context_s fz_context; - -struct fz_alloc_context_s +typedef struct { void *user; void *(*malloc)(void *, size_t); void *(*realloc)(void *, void *, size_t); void (*free)(void *, void *); -}; +} fz_alloc_context; -struct fz_error_stack_slot_s -{ - int code; - fz_jmp_buf buffer; -}; - -struct fz_error_context_s -{ - fz_error_stack_slot *top; - fz_error_stack_slot stack[256]; - int errcode; - char message[256]; -}; - -void fz_var_imp(void *); +/** + Exception macro definitions. Just treat these as a black box - + pay no attention to the man behind the curtain. +*/ #define fz_var(var) fz_var_imp((void *)&(var)) +#define fz_try(ctx) if (!fz_setjmp(*fz_push_try(ctx))) if (fz_do_try(ctx)) do +#define fz_always(ctx) while (0); if (fz_do_always(ctx)) do +#define fz_catch(ctx) while (0); if (fz_do_catch(ctx)) -/* - Exception macro definitions. Just treat these as a black box - pay no - attention to the man behind the curtain. +/** + These macros provide a simple exception handling system. Use them as + follows: + + fz_try(ctx) + ... + fz_catch(ctx) + ... + + or as: + + fz_try(ctx) + ... + fz_always(ctx) + ... + fz_catch(ctx) + ... + + Code within the fz_try() section can then throw exceptions using fz_throw() + (or fz_vthrow()). + + They are implemented with setjmp/longjmp, which can have unfortunate + consequences for 'losing' local variable values on a throw. To avoid this + we recommend calling 'fz_var(variable)' before the fz_try() for any + local variable whose value may change within the fz_try() block and whose + value will be required afterwards. + + Do not call anything in the fz_always() section that can throw. + + Any exception can be rethrown from the fz_catch() section using fz_rethrow() + as long as there has been no intervening use of fz_try/fz_catch. */ -#define fz_try(ctx) \ - { \ - if (fz_push_try(ctx)) { \ - if (fz_setjmp((ctx)->error->top->buffer) == 0) do \ +/** + Throw an exception. -#define fz_always(ctx) \ - while (0); \ - } \ - if (ctx->error->top->code < 3) { \ - ctx->error->top->code++; \ - do \ - -#define fz_catch(ctx) \ - while (0); \ - } \ - } \ - if ((ctx->error->top--)->code > 1) - -int fz_push_try(fz_context *ctx); + This assumes an enclosing fz_try() block within the callstack. +*/ FZ_NORETURN void fz_vthrow(fz_context *ctx, int errcode, const char *, va_list ap); FZ_NORETURN void fz_throw(fz_context *ctx, int errcode, const char *, ...) FZ_PRINTFLIKE(3,4); FZ_NORETURN void fz_rethrow(fz_context *ctx); + +/** + Called within a catch block this modifies the current + exception's code. If it's of type 'fromcode' it is + modified to 'tocode'. Typically used for 'downgrading' + exception severity. +*/ +void fz_morph_error(fz_context *ctx, int fromcode, int tocode); + +/** + Log a warning. + + This goes to the registered warning stream (stderr by + default). +*/ void fz_vwarn(fz_context *ctx, const char *fmt, va_list ap); void fz_warn(fz_context *ctx, const char *fmt, ...) FZ_PRINTFLIKE(2,3); -const char *fz_caught_message(fz_context *ctx); -int fz_caught(fz_context *ctx); -void fz_rethrow_if(fz_context *ctx, int errcode); -enum -{ - FZ_ERROR_NONE = 0, - FZ_ERROR_MEMORY = 1, - FZ_ERROR_GENERIC = 2, - FZ_ERROR_SYNTAX = 3, - FZ_ERROR_TRYLATER = 4, - FZ_ERROR_ABORT = 5, - FZ_ERROR_COUNT -}; +/** + Within an fz_catch() block, retrieve the formatted message + string for the current exception. + + This assumes no intervening use of fz_try/fz_catch. +*/ +const char *fz_caught_message(fz_context *ctx); + +/** + Within an fz_catch() block, retrieve the error code for + the current exception. + + This assumes no intervening use of fz_try/fz_catch. +*/ +int fz_caught(fz_context *ctx); /* - fz_flush_warnings: Flush any repeated warnings. + Within an fz_catch() block, retrieve the errno code for + the current SYSTEM exception. + + Is undefined for non-SYSTEM errors. +*/ +int fz_caught_errno(fz_context *ctx); + +/** + Within an fz_catch() block, rethrow the current exception + if the errcode of the current exception matches. + + This assumes no intervening use of fz_try/fz_catch. +*/ +void fz_rethrow_if(fz_context *ctx, int errcode); +void fz_rethrow_unless(fz_context *ctx, int errcode); + +/** + Format an error message, and log it to the registered + error stream (stderr by default). +*/ +void fz_log_error_printf(fz_context *ctx, const char *fmt, ...) FZ_PRINTFLIKE(2,3); +void fz_vlog_error_printf(fz_context *ctx, const char *fmt, va_list ap); + +/** + Log a (preformatted) string to the registered + error stream (stderr by default). +*/ +void fz_log_error(fz_context *ctx, const char *str); + +void fz_start_throw_on_repair(fz_context *ctx); +void fz_end_throw_on_repair(fz_context *ctx); + +/** + Now, a debugging feature. If FZ_VERBOSE_EXCEPTIONS is 1 then + some of the above functions are replaced by versions that print + FILE and LINE information. +*/ +#if FZ_VERBOSE_EXCEPTIONS +#define fz_vthrow(CTX, ERRCODE, FMT, VA) fz_vthrowFL(CTX, __FILE__, __LINE__, ERRCODE, FMT, VA) +#define fz_throw(CTX, ERRCODE, ...) fz_throwFL(CTX, __FILE__, __LINE__, ERRCODE, __VA_ARGS__) +#define fz_rethrow(CTX) fz_rethrowFL(CTX, __FILE__, __LINE__) +#define fz_morph_error(CTX, FROM, TO) fz_morph_errorFL(CTX, __FILE__, __LINE__, FROM, TO) +#define fz_vwarn(CTX, FMT, VA) fz_vwarnFL(CTX, __FILE__, __LINE__, FMT, VA) +#define fz_warn(CTX, ...) fz_warnFL(CTX, __FILE__, __LINE__, __VA_ARGS__) +#define fz_rethrow_if(CTX, ERRCODE) fz_rethrow_ifFL(CTX, __FILE__, __LINE__, ERRCODE) +#define fz_rethrow_unless(CTX, ERRCODE) fz_rethrow_unlessFL(CTX, __FILE__, __LINE__, ERRCODE) +#define fz_log_error_printf(CTX, ...) fz_log_error_printfFL(CTX, __FILE__, __LINE__, __VA_ARGS__) +#define fz_vlog_error_printf(CTX, FMT, VA) fz_log_error_printfFL(CTX, __FILE__, __LINE__, FMT, VA) +#define fz_log_error(CTX, STR) fz_log_error_printfFL(CTX, __FILE__, __LINE__, STR) +#define fz_do_catch(CTX) fz_do_catchFL(CTX, __FILE__, __LINE__) +FZ_NORETURN void fz_vthrowFL(fz_context *ctx, const char *file, int line, int errcode, const char *fmt, va_list ap); +FZ_NORETURN void fz_throwFL(fz_context *ctx, const char *file, int line, int errcode, const char *fmt, ...) FZ_PRINTFLIKE(5,6); +FZ_NORETURN void fz_rethrowFL(fz_context *ctx, const char *file, int line); +void fz_morph_errorFL(fz_context *ctx, const char *file, int line, int fromcode, int tocode); +void fz_vwarnFL(fz_context *ctx, const char *file, int line, const char *fmt, va_list ap); +void fz_warnFL(fz_context *ctx, const char *file, int line, const char *fmt, ...) FZ_PRINTFLIKE(4,5); +void fz_rethrow_ifFL(fz_context *ctx, const char *file, int line, int errcode); +void fz_rethrow_unlessFL(fz_context *ctx, const char *file, int line, int errcode); +void fz_log_error_printfFL(fz_context *ctx, const char *file, int line, const char *fmt, ...) FZ_PRINTFLIKE(4,5); +void fz_vlog_error_printfFL(fz_context *ctx, const char *file, int line, const char *fmt, va_list ap); +void fz_log_errorFL(fz_context *ctx, const char *file, int line, const char *str); +int fz_do_catchFL(fz_context *ctx, const char *file, int line); +#endif + +/* Report an error to the registered error callback. */ +void fz_report_error(fz_context *ctx); + +/* + * Swallow an error and ignore it completely. + * This should only be called to signal that you've handled a TRYLATER or ABORT error, + */ +void fz_ignore_error(fz_context *ctx); + +/* Convert an error into another runtime exception. + * For use when converting an exception from Fitz to a language binding exception. + */ +const char *fz_convert_error(fz_context *ctx, int *code); + +enum fz_error_type +{ + FZ_ERROR_NONE, + FZ_ERROR_GENERIC, + + FZ_ERROR_SYSTEM, // fatal out of memory or syscall error + FZ_ERROR_LIBRARY, // unclassified error from third-party library + FZ_ERROR_ARGUMENT, // invalid or out-of-range arguments to functions + FZ_ERROR_LIMIT, // failed because of resource or other hard limits + FZ_ERROR_UNSUPPORTED, // tried to use an unsupported feature + FZ_ERROR_FORMAT, // syntax or format errors that are unrecoverable + FZ_ERROR_SYNTAX, // syntax errors that should be diagnosed and ignored + + // for internal use only + FZ_ERROR_TRYLATER, // try-later progressive loading signal + FZ_ERROR_ABORT, // user requested abort signal + FZ_ERROR_REPAIRED, // internal flag used when repairing a PDF to avoid cycles +}; + +/** + Flush any repeated warnings. Repeated warnings are buffered, counted and eventually printed along with the number of repetitions. Call fz_flush_warnings @@ -108,7 +247,7 @@ enum */ void fz_flush_warnings(fz_context *ctx); -/* +/** Locking functions MuPDF is kept deliberately free of any knowledge of particular @@ -129,12 +268,12 @@ void fz_flush_warnings(fz_context *ctx); enabled by defining FITZ_DEBUG_LOCKING. */ -struct fz_locks_context_s +typedef struct { void *user; void (*lock)(void *user, int lock); void (*unlock)(void *user, int lock); -}; +} fz_locks_context; enum { FZ_LOCK_ALLOC = 0, @@ -143,28 +282,27 @@ enum { FZ_LOCK_MAX }; -struct fz_context_s -{ - void *user; - const fz_alloc_context *alloc; - fz_locks_context locks; - fz_id_context *id; - fz_error_context *error; - fz_warn_context *warn; - fz_font_context *font; - fz_colorspace_context *colorspace; - fz_cmm_instance *cmm_instance; - fz_aa_context *aa; - fz_style_context *style; - fz_store *store; - fz_glyph_cache *glyph_cache; - fz_tuning_context *tuning; - fz_document_handler_context *handler; - fz_output_context *output; - uint16_t seed48[7]; -}; +#if defined(MEMENTO) || !defined(NDEBUG) +#define FITZ_DEBUG_LOCKING +#endif -/* +#ifdef FITZ_DEBUG_LOCKING + +void fz_assert_lock_held(fz_context *ctx, int lock); +void fz_assert_lock_not_held(fz_context *ctx, int lock); +void fz_lock_debug_lock(fz_context *ctx, int lock); +void fz_lock_debug_unlock(fz_context *ctx, int lock); + +#else + +#define fz_assert_lock_held(A,B) do { } while (0) +#define fz_assert_lock_not_held(A,B) do { } while (0) +#define fz_lock_debug_lock(A,B) do { } while (0) +#define fz_lock_debug_unlock(A,B) do { } while (0) + +#endif /* !FITZ_DEBUG_LOCKING */ + +/** Specifies the maximum size in bytes of the resource store in fz_context. Given as argument to fz_new_context. @@ -178,8 +316,8 @@ enum { FZ_STORE_DEFAULT = 256 << 20, }; -/* - fz_new_context: Allocate context containing global state. +/** + Allocate context containing global state. The global state contains an exception stack, resource store, etc. Most functions in MuPDF take a context argument to be @@ -206,12 +344,10 @@ enum { May return NULL. */ -fz_context *fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks, size_t max_store, const char *version); - #define fz_new_context(alloc, locks, max_store) fz_new_context_imp(alloc, locks, max_store, FZ_VERSION) -/* - fz_clone_context: Make a clone of an existing context. +/** + Make a clone of an existing context. This function is meant to be used in multi-threaded applications where each thread requires its own context, yet @@ -227,38 +363,110 @@ fz_context *fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_con */ fz_context *fz_clone_context(fz_context *ctx); -/* - fz_drop_context: Free a context and its global state. +/** + Free a context and its global state. The context and all of its global state is freed, and any buffered warnings are flushed (see fz_flush_warnings). If NULL is passed in nothing will happen. + + Must not be called for a context that is being used in an active + fz_try(), fz_always() or fz_catch() block. */ void fz_drop_context(fz_context *ctx); -/* - fz_set_user_context: Set the user field in the context. +/** + Set the user field in the context. NULL initially, this field can be set to any opaque value required by the user. It is copied on clones. */ void fz_set_user_context(fz_context *ctx, void *user); -/* - fz_user_context: Read the user field from the context. +/** + Read the user field from the context. */ void *fz_user_context(fz_context *ctx); -/* +/** + FIXME: Better not to expose fz_default_error_callback, and + fz_default_warning callback and to allow 'NULL' to be used + int fz_set_xxxx_callback to mean "defaults". + + FIXME: Do we need/want functions like + fz_error_callback(ctx, message) to allow callers to inject + stuff into the error/warning streams? +*/ +/** + The default error callback. Declared publicly just so that the + error callback can be set back to this after it has been + overridden. +*/ +void fz_default_error_callback(void *user, const char *message); + +/** + The default warning callback. Declared publicly just so that + the warning callback can be set back to this after it has been + overridden. +*/ +void fz_default_warning_callback(void *user, const char *message); + +/** + A callback called whenever an error message is generated. + The user pointer passed to fz_set_error_callback() is passed + along with the error message. +*/ +typedef void (fz_error_cb)(void *user, const char *message); + +/** + A callback called whenever a warning message is generated. + The user pointer passed to fz_set_warning_callback() is + passed along with the warning message. +*/ +typedef void (fz_warning_cb)(void *user, const char *message); + +/** + Set the error callback. This will be called as part of the + exception handling. + + The callback must not throw exceptions! +*/ +void fz_set_error_callback(fz_context *ctx, fz_error_cb *error_cb, void *user); + +/** + Retrieve the currently set error callback, or NULL if none + has been set. Optionally, if user is non-NULL, the user pointer + given when the warning callback was set is also passed back to + the caller. +*/ +fz_error_cb *fz_error_callback(fz_context *ctx, void **user); + +/** + Set the warning callback. This will be called as part of the + exception handling. + + The callback must not throw exceptions! +*/ +void fz_set_warning_callback(fz_context *ctx, fz_warning_cb *warning_cb, void *user); + +/** + Retrieve the currently set warning callback, or NULL if none + has been set. Optionally, if user is non-NULL, the user pointer + given when the warning callback was set is also passed back to + the caller. +*/ +fz_warning_cb *fz_warning_callback(fz_context *ctx, void **user); + +/** In order to tune MuPDF's behaviour, certain functions can (optionally) be provided by callers. */ -/* - fz_tune_image_decode_fn: Given the width and height of an image, +/** + Given the width and height of an image, the subsample factor, and the subarea of the image actually - required, the caller can decide whether to decode the whole image - or just a subarea. + required, the caller can decide whether to decode the whole + image or just a subarea. arg: The caller supplied opaque argument. @@ -268,28 +476,30 @@ void *fz_user_context(fz_context *ctx); decoded to (w>>l2factor, h>>l2factor)). subarea: The actual subarea required for the current operation. - The tuning function is allowed to increase this in size if required. + The tuning function is allowed to increase this in size if + required. */ typedef void (fz_tune_image_decode_fn)(void *arg, int w, int h, int l2factor, fz_irect *subarea); -/* - fz_tune_image_scale_fn: Given the source width and height of +/** + Given the source width and height of image, together with the actual required width and height, decide whether we should use mitchell scaling. arg: The caller supplied opaque argument. - dst_w, dst_h: The actual width/height required on the target device. + dst_w, dst_h: The actual width/height required on the target + device. src_w, src_h: The source width/height of the image. - Return 0 not to use the Mitchell scaler, 1 to use the Mitchell scaler. All - other values reserved. + Return 0 not to use the Mitchell scaler, 1 to use the Mitchell + scaler. All other values reserved. */ typedef int (fz_tune_image_scale_fn)(void *arg, int dst_w, int dst_h, int src_w, int src_h); -/* - fz_tune_image_decode: Set the tuning function to use for +/** + Set the tuning function to use for image decode. image_decode: Function to use. @@ -298,8 +508,8 @@ typedef int (fz_tune_image_scale_fn)(void *arg, int dst_w, int dst_h, int src_w, */ void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode, void *arg); -/* - fz_tune_image_scale: Set the tuning function to use for +/** + Set the tuning function to use for image scaling. image_scale: Function to use. @@ -308,279 +518,489 @@ void fz_tune_image_decode(fz_context *ctx, fz_tune_image_decode_fn *image_decode */ void fz_tune_image_scale(fz_context *ctx, fz_tune_image_scale_fn *image_scale, void *arg); -/* - fz_aa_level: Get the number of bits of antialiasing we are +/** + Get the number of bits of antialiasing we are using (for graphics). Between 0 and 8. */ int fz_aa_level(fz_context *ctx); -/* - fz_set_aa_level: Set the number of bits of antialiasing we should +/** + Set the number of bits of antialiasing we should use (for both text and graphics). - bits: The number of bits of antialiasing to use (values are clamped - to within the 0 to 8 range). + bits: The number of bits of antialiasing to use (values are + clamped to within the 0 to 8 range). */ void fz_set_aa_level(fz_context *ctx, int bits); -/* - fz_text_aa_level: Get the number of bits of antialiasing we are +/** + Get the number of bits of antialiasing we are using for text. Between 0 and 8. */ int fz_text_aa_level(fz_context *ctx); -/* - fz_set_text_aa_level: Set the number of bits of antialiasing we +/** + Set the number of bits of antialiasing we should use for text. - bits: The number of bits of antialiasing to use (values are clamped - to within the 0 to 8 range). + bits: The number of bits of antialiasing to use (values are + clamped to within the 0 to 8 range). */ void fz_set_text_aa_level(fz_context *ctx, int bits); -/* - fz_graphics_aa_level: Get the number of bits of antialiasing we are +/** + Get the number of bits of antialiasing we are using for graphics. Between 0 and 8. */ int fz_graphics_aa_level(fz_context *ctx); -/* - fz_set_graphics_aa_level: Set the number of bits of antialiasing we +/** + Set the number of bits of antialiasing we should use for graphics. - bits: The number of bits of antialiasing to use (values are clamped - to within the 0 to 8 range). + bits: The number of bits of antialiasing to use (values are + clamped to within the 0 to 8 range). */ void fz_set_graphics_aa_level(fz_context *ctx, int bits); -/* - fz_graphics_min_line_width: Get the minimum line width to be +/** + Get the minimum line width to be used for stroked lines. min_line_width: The minimum line width to use (in pixels). */ float fz_graphics_min_line_width(fz_context *ctx); -/* - fz_set_graphics_min_line_width: Set the minimum line width to be +/** + Set the minimum line width to be used for stroked lines. min_line_width: The minimum line width to use (in pixels). */ void fz_set_graphics_min_line_width(fz_context *ctx, float min_line_width); -/* - fz_user_css: Get the user stylesheet source text. +/** + Get the user stylesheet source text. */ const char *fz_user_css(fz_context *ctx); -/* - fz_set_user_css: Set the user stylesheet source text for use with HTML and EPUB. +/** + Set the user stylesheet source text for use with HTML and EPUB. */ void fz_set_user_css(fz_context *ctx, const char *text); -/* - fz_use_document_css: Return whether to respect document styles in HTML and EPUB. +/** + Return whether to respect document styles in HTML and EPUB. */ int fz_use_document_css(fz_context *ctx); -/* - fz_set_use_document_css: Toggle whether to respect document styles in HTML and EPUB. +/** + Toggle whether to respect document styles in HTML and EPUB. */ void fz_set_use_document_css(fz_context *ctx, int use); -/* +/** + Enable icc profile based operation. +*/ +void fz_enable_icc(fz_context *ctx); + +/** + Disable icc profile based operation. +*/ +void fz_disable_icc(fz_context *ctx); + +/** Memory Allocation and Scavenging: All calls to MuPDF's allocator functions pass through to the underlying allocators passed in when the initial context is - created, after locks are taken (using the supplied locking function) - to ensure that only one thread at a time calls through. + created, after locks are taken (using the supplied locking + function) to ensure that only one thread at a time calls + through. - If the underlying allocator fails, MuPDF attempts to make room for - the allocation by evicting elements from the store, then retrying. + If the underlying allocator fails, MuPDF attempts to make room + for the allocation by evicting elements from the store, then + retrying. - Any call to allocate may then result in several calls to the underlying - allocator, and result in elements that are only referred to by the - store being freed. + Any call to allocate may then result in several calls to the + underlying allocator, and result in elements that are only + referred to by the store being freed. */ -/* - fz_malloc: Allocate a block of memory (with scavenging) +/** + Allocate memory for a structure, clear it, and tag the pointer + for Memento. - size: The number of bytes to allocate. + Throws exception in the event of failure to allocate. +*/ +#define fz_malloc_struct(CTX, TYPE) \ + ((TYPE*)Memento_label(fz_calloc(CTX, 1, sizeof(TYPE)), #TYPE)) - Returns a pointer to the allocated block. May return NULL if size is - 0. Throws exception on failure to allocate. +/** + Allocate memory for an array of structures, clear it, and tag + the pointer for Memento. + + Throws exception in the event of failure to allocate. +*/ +#define fz_malloc_struct_array(CTX, N, TYPE) \ + ((TYPE*)Memento_label(fz_calloc(CTX, N, sizeof(TYPE)), #TYPE "[]")) + +/** + Allocate uninitialized memory for an array of structures, and + tag the pointer for Memento. Does NOT clear the memory! + + Throws exception in the event of failure to allocate. +*/ +#define fz_malloc_array(CTX, COUNT, TYPE) \ + ((TYPE*)Memento_label(fz_malloc(CTX, (COUNT) * sizeof(TYPE)), #TYPE "[]")) +#define fz_realloc_array(CTX, OLD, COUNT, TYPE) \ + ((TYPE*)Memento_label(fz_realloc(CTX, OLD, (COUNT) * sizeof(TYPE)), #TYPE "[]")) + +/** + Allocate uninitialized memory of a given size. + Does NOT clear the memory! + + May return NULL for size = 0. + + Throws exception in the event of failure to allocate. */ void *fz_malloc(fz_context *ctx, size_t size); -/* - fz_calloc: Allocate a zeroed block of memory (with scavenging) +/** + Allocate array of memory of count entries of size bytes. + Clears the memory to zero. - count: The number of objects to allocate space for. - - size: The size (in bytes) of each object. - - Returns a pointer to the allocated block. May return NULL if size - and/or count are 0. Throws exception on failure to allocate. + Throws exception in the event of failure to allocate. */ void *fz_calloc(fz_context *ctx, size_t count, size_t size); -/* - fz_malloc_struct: Allocate storage for a structure (with scavenging), - clear it, and (in Memento builds) tag the pointer as belonging to a - struct of this type. +/** + Reallocates a block of memory to given size. Existing contents + up to min(old_size,new_size) are maintained. The rest of the + block is uninitialised. - CTX: The context. + fz_realloc(ctx, NULL, size) behaves like fz_malloc(ctx, size). - STRUCT: The structure type. + fz_realloc(ctx, p, 0); behaves like fz_free(ctx, p). - Returns a pointer to allocated (and cleared) structure. Throws - exception on failure to allocate. + Throws exception in the event of failure to allocate. */ -#define fz_malloc_struct(CTX, STRUCT) \ - ((STRUCT *)Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT)) +void *fz_realloc(fz_context *ctx, void *p, size_t size); -/* - fz_malloc_array: Allocate a block of (non zeroed) memory (with - scavenging). Equivalent to fz_calloc without the memory clearing. +/** + Free a previously allocated block of memory. - count: The number of objects to allocate space for. + fz_free(ctx, NULL) does nothing. - size: The size (in bytes) of each object. - - Returns a pointer to the allocated block. May return NULL if size - and/or count are 0. Throws exception on failure to allocate. -*/ -void *fz_malloc_array(fz_context *ctx, size_t count, size_t size); - -/* - fz_resize_array: Resize a block of memory (with scavenging). - - p: The existing block to resize - - count: The number of objects to resize to. - - size: The size (in bytes) of each object. - - Returns a pointer to the resized block. May return NULL if size - and/or count are 0. Throws exception on failure to resize (original - block is left unchanged). -*/ -void *fz_resize_array(fz_context *ctx, void *p, size_t count, size_t size); - -/* - fz_strdup: Duplicate a C string (with scavenging) - - s: The string to duplicate. - - Returns a pointer to a duplicated string. Throws exception on failure - to allocate. -*/ -char *fz_strdup(fz_context *ctx, const char *s); - -/* - fz_free: Frees an allocation. + Never throws exceptions. */ void fz_free(fz_context *ctx, void *p); -/* - fz_malloc_no_throw: Allocate a block of memory (with scavenging) - - size: The number of bytes to allocate. - - Returns a pointer to the allocated block. May return NULL if size is - 0. Returns NULL on failure to allocate. +/** + fz_malloc equivalent that returns NULL rather than throwing + exceptions. */ void *fz_malloc_no_throw(fz_context *ctx, size_t size); -/* - fz_calloc_no_throw: Allocate a zeroed block of memory (with scavenging) - - count: The number of objects to allocate space for. - - size: The size (in bytes) of each object. - - Returns a pointer to the allocated block. May return NULL if size - and/or count are 0. Returns NULL on failure to allocate. +/** + fz_calloc equivalent that returns NULL rather than throwing + exceptions. */ void *fz_calloc_no_throw(fz_context *ctx, size_t count, size_t size); -/* - fz_malloc_array_no_throw: Allocate a block of (non zeroed) memory - (with scavenging). Equivalent to fz_calloc_no_throw without the - memory clearing. - - count: The number of objects to allocate space for. - - size: The size (in bytes) of each object. - - Returns a pointer to the allocated block. May return NULL if size - and/or count are 0. Returns NULL on failure to allocate. +/** + fz_realloc equivalent that returns NULL rather than throwing + exceptions. */ -void *fz_malloc_array_no_throw(fz_context *ctx, size_t count, size_t size); +void *fz_realloc_no_throw(fz_context *ctx, void *p, size_t size); -/* - fz_resize_array_no_throw: Resize a block of memory (with scavenging). - - p: The existing block to resize - - count: The number of objects to resize to. - - size: The size (in bytes) of each object. - - Returns a pointer to the resized block. May return NULL if size - and/or count are 0. Returns NULL on failure to resize (original - block is left unchanged). +/** + Portable strdup implementation, using fz allocators. */ -void *fz_resize_array_no_throw(fz_context *ctx, void *p, size_t count, size_t size); +char *fz_strdup(fz_context *ctx, const char *s); -/* - fz_strdup_no_throw: Duplicate a C string (with scavenging) - - s: The string to duplicate. - - Returns a pointer to a duplicated string. Returns NULL on failure - to allocate. -*/ -char *fz_strdup_no_throw(fz_context *ctx, const char *s); - -/* - fz_gen_id: Generate an id (guaranteed unique within this family of - contexts). -*/ -int fz_gen_id(fz_context *ctx); - -struct fz_warn_context_s -{ - char message[256]; - int count; -}; - -/* Default allocator */ -extern fz_alloc_context fz_alloc_default; - -/* Default locks */ -extern fz_locks_context fz_locks_default; - -/* - Pseudo-random numbers using a linear congruential algorithm and 48-bit - integer arithmetic. -*/ -double fz_drand48(fz_context *ctx); -int32_t fz_lrand48(fz_context *ctx); -int32_t fz_mrand48(fz_context *ctx); -double fz_erand48(fz_context *ctx, uint16_t xsubi[3]); -int32_t fz_jrand48(fz_context *ctx, uint16_t xsubi[3]); -int32_t fz_nrand48(fz_context *ctx, uint16_t xsubi[3]); -void fz_lcong48(fz_context *ctx, uint16_t param[7]); -uint16_t *fz_seed48(fz_context *ctx, uint16_t seed16v[3]); -void fz_srand48(fz_context *ctx, int32_t seedval); - -/* - fz_memrnd: Fill block with len bytes of pseudo-randomness. +/** + Fill block with len bytes of pseudo-randomness. */ void fz_memrnd(fz_context *ctx, uint8_t *block, int len); +/* + Reference counted malloced C strings. +*/ +typedef struct +{ + int refs; + char str[1]; +} fz_string; + +/* + Allocate a new string to hold a copy of str. + + Returns with a refcount of 1. +*/ +fz_string *fz_new_string(fz_context *ctx, const char *str); + +/* + Take another reference to a string. +*/ +fz_string *fz_keep_string(fz_context *ctx, fz_string *str); + +/* + Drop a reference to a string, freeing if the refcount + reaches 0. +*/ +void fz_drop_string(fz_context *ctx, fz_string *str); + +#define fz_cstring_from_string(A) ((A) == NULL ? NULL : (A)->str) + +/* Implementation details: subject to change. */ + +/* Implementations exposed for speed, but considered private. */ + +void fz_var_imp(void *); +fz_jmp_buf *fz_push_try(fz_context *ctx); +int fz_do_try(fz_context *ctx); +int fz_do_always(fz_context *ctx); +int (fz_do_catch)(fz_context *ctx); + +#ifndef FZ_JMPBUF_ALIGN +#define FZ_JMPBUF_ALIGN 32 +#endif + +typedef struct +{ + fz_jmp_buf buffer; + int state, code; + char padding[FZ_JMPBUF_ALIGN-sizeof(int)*2]; +} fz_error_stack_slot; + +typedef struct +{ + fz_error_stack_slot *top; + fz_error_stack_slot stack[256]; + fz_error_stack_slot padding; + fz_error_stack_slot *stack_base; + int errcode; + int errnum; /* errno for SYSTEM class errors */ + void *print_user; + void (*print)(void *user, const char *message); + char message[256]; +} fz_error_context; + +typedef struct +{ + void *print_user; + void (*print)(void *user, const char *message); + int count; + char message[256]; +} fz_warn_context; + +typedef struct +{ + int hscale; + int vscale; + int scale; + int bits; + int text_bits; + float min_line_width; +} fz_aa_context; + +struct fz_context +{ + void *user; + fz_alloc_context alloc; + fz_locks_context locks; + fz_error_context error; + fz_warn_context warn; + + /* unshared contexts */ + fz_aa_context aa; + uint16_t seed48[7]; +#if FZ_ENABLE_ICC + int icc_enabled; +#endif + int throw_on_repair; + + /* TODO: should these be unshared? */ + fz_document_handler_context *handler; + fz_archive_handler_context *archive; + fz_style_context *style; + fz_tuning_context *tuning; + + /* shared contexts */ + fz_output *stddbg; + fz_font_context *font; + fz_colorspace_context *colorspace; + fz_store *store; + fz_glyph_cache *glyph_cache; +}; + +fz_context *fz_new_context_imp(const fz_alloc_context *alloc, const fz_locks_context *locks, size_t max_store, const char *version); + +/** + Lock one of the user supplied mutexes. +*/ +static inline void +fz_lock(fz_context *ctx, int lock) +{ + fz_lock_debug_lock(ctx, lock); + ctx->locks.lock(ctx->locks.user, lock); +} + +/** + Unlock one of the user supplied mutexes. +*/ +static inline void +fz_unlock(fz_context *ctx, int lock) +{ + fz_lock_debug_unlock(ctx, lock); + ctx->locks.unlock(ctx->locks.user, lock); +} + +/* Lock-safe reference counting functions */ + +static inline void * +fz_keep_imp(fz_context *ctx, void *p, int *refs) +{ + if (p) + { + (void)Memento_checkIntPointerOrNull(refs); + fz_lock(ctx, FZ_LOCK_ALLOC); + if (*refs > 0) + { + (void)Memento_takeRef(p); + ++*refs; + } + fz_unlock(ctx, FZ_LOCK_ALLOC); + } + return p; +} + +static inline void * +fz_keep_imp_locked(fz_context *ctx FZ_UNUSED, void *p, int *refs) +{ + if (p) + { + (void)Memento_checkIntPointerOrNull(refs); + if (*refs > 0) + { + (void)Memento_takeRef(p); + ++*refs; + } + } + return p; +} + +static inline void * +fz_keep_imp8_locked(fz_context *ctx FZ_UNUSED, void *p, int8_t *refs) +{ + if (p) + { + (void)Memento_checkIntPointerOrNull(refs); + if (*refs > 0) + { + (void)Memento_takeRef(p); + ++*refs; + } + } + return p; +} + +static inline void * +fz_keep_imp8(fz_context *ctx, void *p, int8_t *refs) +{ + if (p) + { + (void)Memento_checkBytePointerOrNull(refs); + fz_lock(ctx, FZ_LOCK_ALLOC); + if (*refs > 0) + { + (void)Memento_takeRef(p); + ++*refs; + } + fz_unlock(ctx, FZ_LOCK_ALLOC); + } + return p; +} + +static inline void * +fz_keep_imp16(fz_context *ctx, void *p, int16_t *refs) +{ + if (p) + { + (void)Memento_checkShortPointerOrNull(refs); + fz_lock(ctx, FZ_LOCK_ALLOC); + if (*refs > 0) + { + (void)Memento_takeRef(p); + ++*refs; + } + fz_unlock(ctx, FZ_LOCK_ALLOC); + } + return p; +} + +static inline int +fz_drop_imp(fz_context *ctx, void *p, int *refs) +{ + if (p) + { + int drop; + (void)Memento_checkIntPointerOrNull(refs); + fz_lock(ctx, FZ_LOCK_ALLOC); + if (*refs > 0) + { + (void)Memento_dropIntRef(p); + drop = --*refs == 0; + } + else + drop = 0; + fz_unlock(ctx, FZ_LOCK_ALLOC); + return drop; + } + return 0; +} + +static inline int +fz_drop_imp8(fz_context *ctx, void *p, int8_t *refs) +{ + if (p) + { + int drop; + (void)Memento_checkBytePointerOrNull(refs); + fz_lock(ctx, FZ_LOCK_ALLOC); + if (*refs > 0) + { + (void)Memento_dropByteRef(p); + drop = --*refs == 0; + } + else + drop = 0; + fz_unlock(ctx, FZ_LOCK_ALLOC); + return drop; + } + return 0; +} + +static inline int +fz_drop_imp16(fz_context *ctx, void *p, int16_t *refs) +{ + if (p) + { + int drop; + (void)Memento_checkShortPointerOrNull(refs); + fz_lock(ctx, FZ_LOCK_ALLOC); + if (*refs > 0) + { + (void)Memento_dropShortRef(p); + drop = --*refs == 0; + } + else + drop = 0; + fz_unlock(ctx, FZ_LOCK_ALLOC); + return drop; + } + return 0; +} + #endif diff --git a/include/mupdf/fitz/crypt.h b/include/mupdf/fitz/crypt.h index 96be737..e556f3b 100644 --- a/include/mupdf/fitz/crypt.h +++ b/include/mupdf/fitz/crypt.h @@ -1,42 +1,83 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_CRYPT_H #define MUPDF_FITZ_CRYPT_H #include "mupdf/fitz/system.h" -/* - * Basic crypto functions. - * Independent of the rest of fitz. - * For further encapsulation in filters, or not. - */ - /* md5 digests */ -typedef struct fz_md5_s fz_md5; - -/* +/** Structure definition is public to enable stack based allocation. Do not access the members directly. */ -struct fz_md5_s +typedef struct { - unsigned int state[4]; - unsigned int count[2]; + uint32_t lo, hi; + uint32_t a, b, c, d; unsigned char buffer[64]; -}; +} fz_md5; +/** + MD5 initialization. Begins an MD5 operation, writing a new + context. + + Never throws an exception. +*/ void fz_md5_init(fz_md5 *state); + +/** + MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + + Never throws an exception. +*/ void fz_md5_update(fz_md5 *state, const unsigned char *input, size_t inlen); + +/** + MD5 block update operation. Continues an MD5 message-digest + operation, processing an int64, and updating the context. + + Never throws an exception. +*/ +void fz_md5_update_int64(fz_md5 *state, int64_t i); + +/** + MD5 finalization. Ends an MD5 message-digest operation, writing + the message digest and zeroizing the context. + + Never throws an exception. +*/ void fz_md5_final(fz_md5 *state, unsigned char digest[16]); /* sha-256 digests */ -typedef struct fz_sha256_s fz_sha256; - -/* +/** Structure definition is public to enable stack based allocation. Do not access the members directly. */ -struct fz_sha256_s +typedef struct { unsigned int state[8]; unsigned int count[2]; @@ -44,21 +85,40 @@ struct fz_sha256_s unsigned char u8[64]; unsigned int u32[16]; } buffer; -}; +} fz_sha256; +/** + SHA256 initialization. Begins an SHA256 operation, initialising + the supplied context. + + Never throws an exception. +*/ void fz_sha256_init(fz_sha256 *state); + +/** + SHA256 block update operation. Continues an SHA256 message- + digest operation, processing another message block, and updating + the context. + + Never throws an exception. +*/ void fz_sha256_update(fz_sha256 *state, const unsigned char *input, size_t inlen); + +/** + MD5 finalization. Ends an MD5 message-digest operation, writing + the message digest and zeroizing the context. + + Never throws an exception. +*/ void fz_sha256_final(fz_sha256 *state, unsigned char digest[32]); /* sha-512 digests */ -typedef struct fz_sha512_s fz_sha512; - -/* +/** Structure definition is public to enable stack based allocation. Do not access the members directly. */ -struct fz_sha512_s +typedef struct { uint64_t state[8]; unsigned int count[2]; @@ -66,59 +126,143 @@ struct fz_sha512_s unsigned char u8[128]; uint64_t u64[16]; } buffer; -}; +} fz_sha512; +/** + SHA512 initialization. Begins an SHA512 operation, initialising + the supplied context. + + Never throws an exception. +*/ void fz_sha512_init(fz_sha512 *state); + +/** + SHA512 block update operation. Continues an SHA512 message- + digest operation, processing another message block, and updating + the context. + + Never throws an exception. +*/ void fz_sha512_update(fz_sha512 *state, const unsigned char *input, size_t inlen); + +/** + SHA512 finalization. Ends an SHA512 message-digest operation, + writing the message digest and zeroizing the context. + + Never throws an exception. +*/ void fz_sha512_final(fz_sha512 *state, unsigned char digest[64]); /* sha-384 digests */ -typedef struct fz_sha512_s fz_sha384; +typedef fz_sha512 fz_sha384; +/** + SHA384 initialization. Begins an SHA384 operation, initialising + the supplied context. + + Never throws an exception. +*/ void fz_sha384_init(fz_sha384 *state); + +/** + SHA384 block update operation. Continues an SHA384 message- + digest operation, processing another message block, and updating + the context. + + Never throws an exception. +*/ void fz_sha384_update(fz_sha384 *state, const unsigned char *input, size_t inlen); + +/** + SHA384 finalization. Ends an SHA384 message-digest operation, + writing the message digest and zeroizing the context. + + Never throws an exception. +*/ void fz_sha384_final(fz_sha384 *state, unsigned char digest[64]); /* arc4 crypto */ -typedef struct fz_arc4_s fz_arc4; - -/* +/** Structure definition is public to enable stack based allocation. Do not access the members directly. */ -struct fz_arc4_s +typedef struct { unsigned x; unsigned y; unsigned char state[256]; -}; +} fz_arc4; +/** + RC4 initialization. Begins an RC4 operation, writing a new + context. + + Never throws an exception. +*/ void fz_arc4_init(fz_arc4 *state, const unsigned char *key, size_t len); + +/** + RC4 block encrypt operation; encrypt src into dst (both of + length len) updating the RC4 state as we go. + + Never throws an exception. +*/ void fz_arc4_encrypt(fz_arc4 *state, unsigned char *dest, const unsigned char *src, size_t len); +/** + RC4 finalization. Zero the context. + + Never throws an exception. +*/ +void fz_arc4_final(fz_arc4 *state); + /* AES block cipher implementation from XYSSL */ -typedef struct fz_aes_s fz_aes; +/** + Structure definitions are public to enable stack + based allocation. Do not access the members directly. +*/ +typedef struct +{ + int nr; /* number of rounds */ + uint32_t *rk; /* AES round keys */ + uint32_t buf[68]; /* unaligned data */ +} fz_aes; #define FZ_AES_DECRYPT 0 #define FZ_AES_ENCRYPT 1 -/* - Structure definition is public to enable stack - based allocation. Do not access the members directly. -*/ -struct fz_aes_s -{ - int nr; /* number of rounds */ - unsigned long *rk; /* AES round keys */ - unsigned long buf[68]; /* unaligned data */ -}; +/** + AES encryption intialisation. Fills in the supplied context + and prepares for encryption using the given key. -int fz_aes_setkey_enc( fz_aes *ctx, const unsigned char *key, int keysize ); -int fz_aes_setkey_dec( fz_aes *ctx, const unsigned char *key, int keysize ); -void fz_aes_crypt_cbc( fz_aes *ctx, int mode, size_t length, + Returns non-zero for error (key size other than 128/192/256). + + Never throws an exception. +*/ +int fz_aes_setkey_enc(fz_aes *ctx, const unsigned char *key, int keysize); + +/** + AES decryption intialisation. Fills in the supplied context + and prepares for decryption using the given key. + + Returns non-zero for error (key size other than 128/192/256). + + Never throws an exception. +*/ +int fz_aes_setkey_dec(fz_aes *ctx, const unsigned char *key, int keysize); + +/** + AES block processing. Encrypts or Decrypts (according to mode, + which must match what was initially set up) length bytes (which + must be a multiple of 16), using (and modifying) the insertion + vector iv, reading from input, and writing to output. + + Never throws an exception. +*/ +void fz_aes_crypt_cbc(fz_aes *ctx, int mode, size_t length, unsigned char iv[16], const unsigned char *input, unsigned char *output ); diff --git a/include/mupdf/fitz/device.h b/include/mupdf/fitz/device.h index 132668c..9f51c21 100644 --- a/include/mupdf/fitz/device.h +++ b/include/mupdf/fitz/device.h @@ -1,19 +1,40 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_DEVICE_H #define MUPDF_FITZ_DEVICE_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" -#include "mupdf/fitz/colorspace.h" #include "mupdf/fitz/image.h" #include "mupdf/fitz/shade.h" #include "mupdf/fitz/path.h" #include "mupdf/fitz/text.h" -/* - The different format handlers (pdf, xps etc) interpret pages to a - device. These devices can then process the stream of calls they - receive in various ways: +/** + The different format handlers (pdf, xps etc) interpret pages to + a device. These devices can then process the stream of calls + they receive in various ways: The trace device outputs debugging information for the calls. The draw device will render them. The list device stores them in a list to play back later. @@ -21,7 +42,7 @@ The bbox device calculates the bounding box for the page. Other devices can (and will) be written in the future. */ -typedef struct fz_device_s fz_device; +typedef struct fz_device fz_device; enum { @@ -37,9 +58,10 @@ enum FZ_DEVFLAG_LINEJOIN_UNDEFINED = 256, FZ_DEVFLAG_MITERLIMIT_UNDEFINED = 512, FZ_DEVFLAG_LINEWIDTH_UNDEFINED = 1024, - /* Arguably we should have a bit for the dash pattern itself being - * undefined, but that causes problems; do we assume that it should - * always be set to non-dashing at the start of every glyph? */ + /* Arguably we should have a bit for the dash pattern itself + * being undefined, but that causes problems; do we assume that + * it should always be set to non-dashing at the start of every + * glyph? */ FZ_DEVFLAG_BBOX_DEFINED = 2048, FZ_DEVFLAG_GRIDFIT_AS_TILED = 4096, }; @@ -72,12 +94,201 @@ enum FZ_BLEND_KNOCKOUT = 32 }; +/** + Map from (case sensitive) blend mode string to enumeration. +*/ int fz_lookup_blendmode(const char *name); -char *fz_blendmode_name(int blendmode); -typedef struct fz_device_container_stack_s fz_device_container_stack; +/** + Map from enumeration to blend mode string. -struct fz_device_s + The string is static, with arbitrary lifespan. +*/ +const char *fz_blendmode_name(int blendmode); + +/* + Generic function type. + + Different function implementations will derive from this. +*/ +typedef struct fz_function fz_function; + +typedef void (fz_function_eval_fn)(fz_context *, fz_function *, const float *, float *); + +enum +{ + FZ_FUNCTION_MAX_N = FZ_MAX_COLORS, + FZ_FUNCTION_MAX_M = FZ_MAX_COLORS +}; + +struct fz_function +{ + fz_storable storable; + size_t size; + int m; /* number of input values */ + int n; /* number of output values */ + + fz_function_eval_fn *eval; +}; + +fz_function *fz_new_function_of_size(fz_context *ctx, int size, size_t size2, int m, int n, fz_function_eval_fn *eval, fz_store_drop_fn *drop); + +#define fz_new_derived_function(CTX,TYPE,SIZE,M,N,EVAL,DROP) \ + ((TYPE*)Memento_label(fz_new_function_of_size(CTX,sizeof(TYPE),SIZE,M,N,EVAL,DROP), #TYPE)) + +/* + Evaluate a function. + + Input vector = (in[0], ..., in[inlen-1]) + Output vector = (out[0], ..., out[outlen-1]) + + If inlen or outlen do not match that expected by the function, this + routine will truncate or extend the input/output (with 0's) as + required. +*/ +void fz_eval_function(fz_context *ctx, fz_function *func, const float *in, int inlen, float *out, int outlen); + +/* + Keep a function reference. +*/ +fz_function *fz_keep_function(fz_context *ctx, fz_function *func); + +/* + Drop a function reference. +*/ +void fz_drop_function(fz_context *ctx, fz_function *func); + +/* + Function size +*/ +size_t fz_function_size(fz_context *ctx, fz_function *func); + +/** + The device structure is public to allow devices to be + implemented outside of fitz. + + Device methods should always be called using e.g. + fz_fill_path(ctx, dev, ...) rather than + dev->fill_path(ctx, dev, ...) +*/ + +/** + Devices can keep track of containers (clips/masks/groups/tiles) + as they go to save callers having to do it. +*/ +typedef struct +{ + fz_rect scissor; + int type; + int user; +} fz_device_container_stack; + +enum +{ + fz_device_container_stack_is_clip, + fz_device_container_stack_is_mask, + fz_device_container_stack_is_group, + fz_device_container_stack_is_tile, +}; + +/* Structure types */ +typedef enum +{ + FZ_STRUCTURE_INVALID = -1, + + /* Grouping elements (PDF 1.7 - Table 10.20) */ + FZ_STRUCTURE_DOCUMENT, + FZ_STRUCTURE_PART, + FZ_STRUCTURE_ART, + FZ_STRUCTURE_SECT, + FZ_STRUCTURE_DIV, + FZ_STRUCTURE_BLOCKQUOTE, + FZ_STRUCTURE_CAPTION, + FZ_STRUCTURE_TOC, + FZ_STRUCTURE_TOCI, + FZ_STRUCTURE_INDEX, + FZ_STRUCTURE_NONSTRUCT, + FZ_STRUCTURE_PRIVATE, + /* Grouping elements (PDF 2.0 - Table 364) */ + FZ_STRUCTURE_DOCUMENTFRAGMENT, + /* Grouping elements (PDF 2.0 - Table 365) */ + FZ_STRUCTURE_ASIDE, + /* Grouping elements (PDF 2.0 - Table 366) */ + FZ_STRUCTURE_TITLE, + FZ_STRUCTURE_FENOTE, + /* Grouping elements (PDF 2.0 - Table 367) */ + FZ_STRUCTURE_SUB, + + /* Paragraphlike elements (PDF 1.7 - Table 10.21) */ + FZ_STRUCTURE_P, + FZ_STRUCTURE_H, + FZ_STRUCTURE_H1, + FZ_STRUCTURE_H2, + FZ_STRUCTURE_H3, + FZ_STRUCTURE_H4, + FZ_STRUCTURE_H5, + FZ_STRUCTURE_H6, + + /* List elements (PDF 1.7 - Table 10.23) */ + FZ_STRUCTURE_LIST, + FZ_STRUCTURE_LISTITEM, + FZ_STRUCTURE_LABEL, + FZ_STRUCTURE_LISTBODY, + + /* Table elements (PDF 1.7 - Table 10.24) */ + FZ_STRUCTURE_TABLE, + FZ_STRUCTURE_TR, + FZ_STRUCTURE_TH, + FZ_STRUCTURE_TD, + FZ_STRUCTURE_THEAD, + FZ_STRUCTURE_TBODY, + FZ_STRUCTURE_TFOOT, + + /* Inline elements (PDF 1.7 - Table 10.25) */ + FZ_STRUCTURE_SPAN, + FZ_STRUCTURE_QUOTE, + FZ_STRUCTURE_NOTE, + FZ_STRUCTURE_REFERENCE, + FZ_STRUCTURE_BIBENTRY, + FZ_STRUCTURE_CODE, + FZ_STRUCTURE_LINK, + FZ_STRUCTURE_ANNOT, + /* Inline elements (PDF 2.0 - Table 368) */ + FZ_STRUCTURE_EM, + FZ_STRUCTURE_STRONG, + + /* Ruby inline element (PDF 1.7 - Table 10.26) */ + FZ_STRUCTURE_RUBY, + FZ_STRUCTURE_RB, + FZ_STRUCTURE_RT, + FZ_STRUCTURE_RP, + + /* Warichu inline element (PDF 1.7 - Table 10.26) */ + FZ_STRUCTURE_WARICHU, + FZ_STRUCTURE_WT, + FZ_STRUCTURE_WP, + + /* Illustration elements (PDF 1.7 - Table 10.27) */ + FZ_STRUCTURE_FIGURE, + FZ_STRUCTURE_FORMULA, + FZ_STRUCTURE_FORM, + + /* Artifact structure type (PDF 2.0 - Table 375) */ + FZ_STRUCTURE_ARTIFACT +} fz_structure; + +const char *fz_structure_to_string(fz_structure type); +fz_structure fz_structure_from_string(const char *str); + +typedef enum +{ + FZ_METATEXT_ACTUALTEXT, + FZ_METATEXT_ALT, + FZ_METATEXT_ABBREVIATION, + FZ_METATEXT_TITLE +} fz_metatext; + +struct fz_device { int refs; int hints; @@ -86,30 +297,30 @@ struct fz_device_s void (*close_device)(fz_context *, fz_device *); void (*drop_device)(fz_context *, fz_device *); - void (*fill_path)(fz_context *, fz_device *, const fz_path *, int even_odd, const fz_matrix *, fz_colorspace *, const float *color, float alpha, const fz_color_params *); - void (*stroke_path)(fz_context *, fz_device *, const fz_path *, const fz_stroke_state *, const fz_matrix *, fz_colorspace *, const float *color, float alpha, const fz_color_params *); - void (*clip_path)(fz_context *, fz_device *, const fz_path *, int even_odd, const fz_matrix *, const fz_rect *scissor); - void (*clip_stroke_path)(fz_context *, fz_device *, const fz_path *, const fz_stroke_state *, const fz_matrix *, const fz_rect *scissor); + void (*fill_path)(fz_context *, fz_device *, const fz_path *, int even_odd, fz_matrix, fz_colorspace *, const float *color, float alpha, fz_color_params ); + void (*stroke_path)(fz_context *, fz_device *, const fz_path *, const fz_stroke_state *, fz_matrix, fz_colorspace *, const float *color, float alpha, fz_color_params ); + void (*clip_path)(fz_context *, fz_device *, const fz_path *, int even_odd, fz_matrix, fz_rect scissor); + void (*clip_stroke_path)(fz_context *, fz_device *, const fz_path *, const fz_stroke_state *, fz_matrix, fz_rect scissor); - void (*fill_text)(fz_context *, fz_device *, const fz_text *, const fz_matrix *, fz_colorspace *, const float *color, float alpha, const fz_color_params *); - void (*stroke_text)(fz_context *, fz_device *, const fz_text *, const fz_stroke_state *, const fz_matrix *, fz_colorspace *, const float *color, float alpha, const fz_color_params *); - void (*clip_text)(fz_context *, fz_device *, const fz_text *, const fz_matrix *, const fz_rect *scissor); - void (*clip_stroke_text)(fz_context *, fz_device *, const fz_text *, const fz_stroke_state *, const fz_matrix *, const fz_rect *scissor); - void (*ignore_text)(fz_context *, fz_device *, const fz_text *, const fz_matrix *); + void (*fill_text)(fz_context *, fz_device *, const fz_text *, fz_matrix, fz_colorspace *, const float *color, float alpha, fz_color_params ); + void (*stroke_text)(fz_context *, fz_device *, const fz_text *, const fz_stroke_state *, fz_matrix, fz_colorspace *, const float *color, float alpha, fz_color_params ); + void (*clip_text)(fz_context *, fz_device *, const fz_text *, fz_matrix, fz_rect scissor); + void (*clip_stroke_text)(fz_context *, fz_device *, const fz_text *, const fz_stroke_state *, fz_matrix, fz_rect scissor); + void (*ignore_text)(fz_context *, fz_device *, const fz_text *, fz_matrix ); - void (*fill_shade)(fz_context *, fz_device *, fz_shade *shd, const fz_matrix *ctm, float alpha, const fz_color_params *color_params); - void (*fill_image)(fz_context *, fz_device *, fz_image *img, const fz_matrix *ctm, float alpha, const fz_color_params *color_params); - void (*fill_image_mask)(fz_context *, fz_device *, fz_image *img, const fz_matrix *ctm, fz_colorspace *, const float *color, float alpha, const fz_color_params *color_params); - void (*clip_image_mask)(fz_context *, fz_device *, fz_image *img, const fz_matrix *ctm, const fz_rect *scissor); + void (*fill_shade)(fz_context *, fz_device *, fz_shade *shd, fz_matrix ctm, float alpha, fz_color_params color_params); + void (*fill_image)(fz_context *, fz_device *, fz_image *img, fz_matrix ctm, float alpha, fz_color_params color_params); + void (*fill_image_mask)(fz_context *, fz_device *, fz_image *img, fz_matrix ctm, fz_colorspace *, const float *color, float alpha, fz_color_params color_params); + void (*clip_image_mask)(fz_context *, fz_device *, fz_image *img, fz_matrix ctm, fz_rect scissor); void (*pop_clip)(fz_context *, fz_device *); - void (*begin_mask)(fz_context *, fz_device *, const fz_rect *, int luminosity, fz_colorspace *, const float *bc, const fz_color_params *); - void (*end_mask)(fz_context *, fz_device *); - void (*begin_group)(fz_context *, fz_device *, const fz_rect *, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha); + void (*begin_mask)(fz_context *, fz_device *, fz_rect area, int luminosity, fz_colorspace *, const float *bc, fz_color_params ); + void (*end_mask)(fz_context *, fz_device *, fz_function *fn); + void (*begin_group)(fz_context *, fz_device *, fz_rect area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha); void (*end_group)(fz_context *, fz_device *); - int (*begin_tile)(fz_context *, fz_device *, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id); + int (*begin_tile)(fz_context *, fz_device *, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm, int id); void (*end_tile)(fz_context *, fz_device *); void (*render_flags)(fz_context *, fz_device *, int set, int clear); @@ -118,95 +329,117 @@ struct fz_device_s void (*begin_layer)(fz_context *, fz_device *, const char *layer_name); void (*end_layer)(fz_context *, fz_device *); - fz_rect d1_rect; + void (*begin_structure)(fz_context *, fz_device *, fz_structure standard, const char *raw, int idx); + void (*end_structure)(fz_context *, fz_device *); - int error_depth; - char errmess[256]; + void (*begin_metatext)(fz_context *, fz_device *, fz_metatext meta, const char *text); + void (*end_metatext)(fz_context *, fz_device *); + + fz_rect d1_rect; int container_len; int container_cap; fz_device_container_stack *container; }; -void fz_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params); -void fz_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params); -void fz_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, const fz_matrix *ctm, const fz_rect *scissor); -void fz_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, const fz_rect *scissor); -void fz_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params); -void fz_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params); -void fz_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm, const fz_rect *scissor); -void fz_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm, const fz_rect *scissor); -void fz_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_matrix *ctm); +/** + Device calls; graphics primitives and containers. +*/ +void fz_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params); +void fz_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params); +void fz_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor); +void fz_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor); +void fz_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params); +void fz_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params); +void fz_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor); +void fz_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor); +void fz_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm); void fz_pop_clip(fz_context *ctx, fz_device *dev); -void fz_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, const fz_matrix *ctm, float alpha, const fz_color_params *color_params); -void fz_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, float alpha, const fz_color_params *color_params); -void fz_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, fz_colorspace *colorspace, const float *color, float alpha, const fz_color_params *color_params); -void fz_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, const fz_matrix *ctm, const fz_rect *scissor); -void fz_begin_mask(fz_context *ctx, fz_device *dev, const fz_rect *area, int luminosity, fz_colorspace *colorspace, const float *bc, const fz_color_params *color_params); +void fz_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params); +void fz_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params); +void fz_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params); +void fz_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_rect scissor); +void fz_begin_mask(fz_context *ctx, fz_device *dev, fz_rect area, int luminosity, fz_colorspace *colorspace, const float *bc, fz_color_params color_params); void fz_end_mask(fz_context *ctx, fz_device *dev); -void fz_begin_group(fz_context *ctx, fz_device *dev, const fz_rect *area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha); +void fz_end_mask_tr(fz_context *ctx, fz_device *dev, fz_function *fn); +void fz_begin_group(fz_context *ctx, fz_device *dev, fz_rect area, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha); void fz_end_group(fz_context *ctx, fz_device *dev); -void fz_begin_tile(fz_context *ctx, fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm); -int fz_begin_tile_id(fz_context *ctx, fz_device *dev, const fz_rect *area, const fz_rect *view, float xstep, float ystep, const fz_matrix *ctm, int id); +void fz_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm); +int fz_begin_tile_id(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view, float xstep, float ystep, fz_matrix ctm, int id); void fz_end_tile(fz_context *ctx, fz_device *dev); void fz_render_flags(fz_context *ctx, fz_device *dev, int set, int clear); void fz_set_default_colorspaces(fz_context *ctx, fz_device *dev, fz_default_colorspaces *default_cs); void fz_begin_layer(fz_context *ctx, fz_device *dev, const char *layer_name); void fz_end_layer(fz_context *ctx, fz_device *dev); -fz_device *fz_new_device_of_size(fz_context *ctx, int size); +void fz_begin_structure(fz_context *ctx, fz_device *dev, fz_structure standard, const char *raw, int idx); +void fz_end_structure(fz_context *ctx, fz_device *dev); +void fz_begin_metatext(fz_context *ctx, fz_device *dev, fz_metatext meta, const char *text); +void fz_end_metatext(fz_context *ctx, fz_device *dev); +/** + Devices are created by calls to device implementations, for + instance: foo_new_device(). These will be implemented by calling + fz_new_derived_device(ctx, foo_device) where foo_device is a + structure "derived from" fz_device, for instance + typedef struct { fz_device base; ...extras...} foo_device; +*/ +fz_device *fz_new_device_of_size(fz_context *ctx, int size); #define fz_new_derived_device(CTX, TYPE) \ ((TYPE *)Memento_label(fz_new_device_of_size(ctx,sizeof(TYPE)),#TYPE)) -/* - fz_close_device: Signal the end of input, and flush any buffered output. - This is NOT called implicitly on fz_drop_device. +/** + Signal the end of input, and flush any buffered output. + This is NOT called implicitly on fz_drop_device. This + may throw exceptions. */ void fz_close_device(fz_context *ctx, fz_device *dev); -/* - fz_drop_device: Free a device of any type and its resources. +/** + Reduce the reference count on a device. When the reference count + reaches zero, the device and its resources will be freed. Don't forget to call fz_close_device before dropping the device, or you may get incomplete output! + + Never throws exceptions. */ void fz_drop_device(fz_context *ctx, fz_device *dev); +/** + Increment the reference count for a device. Returns the same + pointer. + + Never throws exceptions. +*/ fz_device *fz_keep_device(fz_context *ctx, fz_device *dev); -/* - fz_enable_device_hints : Enable hints in a device. - - hints: mask of hints to enable. +/** + Enable (set) hint bits within the hint bitfield for a device. */ void fz_enable_device_hints(fz_context *ctx, fz_device *dev, int hints); -/* - fz_disable_device_hints : Disable hints in a device. - - hints: mask of hints to disable. +/** + Disable (clear) hint bits within the hint bitfield for a device. */ void fz_disable_device_hints(fz_context *ctx, fz_device *dev, int hints); -/* +/** Find current scissor region as tracked by the device. */ -const fz_rect *fz_device_current_scissor(fz_context *ctx, fz_device *dev); +fz_rect fz_device_current_scissor(fz_context *ctx, fz_device *dev); enum { /* Hints */ FZ_DONT_INTERPOLATE_IMAGES = 1, - FZ_MAINTAIN_CONTAINER_STACK = 2, - FZ_NO_CACHE = 4, + FZ_NO_CACHE = 2, + FZ_DONT_DECODE_IMAGES = 4 }; -/* +/** Cookie support - simple communication channel between app/library. */ -typedef struct fz_cookie_s fz_cookie; - -/* +/** Provide two-way communication between application and library. Intended for multi-threaded applications where one thread is rendering pages and another thread wants to read progress @@ -242,33 +475,30 @@ typedef struct fz_cookie_s fz_cookie; errors: count of errors during current rendering. - incomplete_ok: If this is set to 1 by the caller, then TRYLATER - errors are swallowed as they occur, setting the 'incomplete' flag. - Rendering continues as much as possible ignoring errors. The caller - is expected to check the 'incomplete' flag at the end to see if the - rendering may be considered final or not. - - incomplete: Initially should be set to 0. Will be set to non-zero - if a TRYLATER error is thrown during rendering and the incomplete_ok - flag is set. + incomplete: Initially should be set to 0. Will be set to + non-zero if a TRYLATER error is thrown during rendering. */ -struct fz_cookie_s +typedef struct { int abort; int progress; - int progress_max; /* -1 for unknown */ + size_t progress_max; /* (size_t)-1 for unknown */ int errors; - int incomplete_ok; int incomplete; -}; +} fz_cookie; -/* - fz_new_trace_device: Create a device to print a debug trace of all device calls. +/** + Create a device to print a debug trace of all device calls. */ fz_device *fz_new_trace_device(fz_context *ctx, fz_output *out); -/* - fz_new_bbox_device: Create a device to compute the bounding +/** + Create a device to output raw information. +*/ +fz_device *fz_new_xmltext_device(fz_context *ctx, fz_output *out); + +/** + Create a device to compute the bounding box of all marks on a page. The returned bounding box will be the union of all bounding @@ -276,8 +506,8 @@ fz_device *fz_new_trace_device(fz_context *ctx, fz_output *out); */ fz_device *fz_new_bbox_device(fz_context *ctx, fz_rect *rectp); -/* - fz_new_test_device: Create a device to test for features. +/** + Create a device to test for features. Currently only tests for the presence of non-grayscale colors. @@ -315,8 +545,8 @@ enum FZ_TEST_OPT_SHADINGS = 2 }; -/* - fz_new_draw_device: Create a device to draw on a pixmap. +/** + Create a device to draw on a pixmap. dest: Target pixmap for the draw device. See fz_new_pixmap* for how to obtain a pixmap. The pixmap is not cleared by the @@ -324,12 +554,13 @@ enum calling fz_new_draw_device. Free the device by calling fz_drop_device. - transform: Transform from user space in points to device space in pixels. + transform: Transform from user space in points to device space + in pixels. */ -fz_device *fz_new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest); +fz_device *fz_new_draw_device(fz_context *ctx, fz_matrix transform, fz_pixmap *dest); -/* - fz_new_draw_device_with_bbox: Create a device to draw on a pixmap. +/** + Create a device to draw on a pixmap. dest: Target pixmap for the draw device. See fz_new_pixmap* for how to obtain a pixmap. The pixmap is not cleared by the @@ -337,15 +568,16 @@ fz_device *fz_new_draw_device(fz_context *ctx, const fz_matrix *transform, fz_pi calling fz_new_draw_device. Free the device by calling fz_drop_device. - transform: Transform from user space in points to device space in pixels. + transform: Transform from user space in points to device space + in pixels. clip: Bounding box to restrict any marking operations of the draw device. */ -fz_device *fz_new_draw_device_with_bbox(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, const fz_irect *clip); +fz_device *fz_new_draw_device_with_bbox(fz_context *ctx, fz_matrix transform, fz_pixmap *dest, const fz_irect *clip); -/* - fz_new_draw_device_with_proof: Create a device to draw on a pixmap. +/** + Create a device to draw on a pixmap. dest: Target pixmap for the draw device. See fz_new_pixmap* for how to obtain a pixmap. The pixmap is not cleared by the @@ -353,15 +585,16 @@ fz_device *fz_new_draw_device_with_bbox(fz_context *ctx, const fz_matrix *transf calling fz_new_draw_device. Free the device by calling fz_drop_device. - transform: Transform from user space in points to device space in pixels. + transform: Transform from user space in points to device space + in pixels. proof_cs: Intermediate color space to map though when mapping to color space defined by pixmap. */ -fz_device *fz_new_draw_device_with_proof(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, fz_colorspace *proof_cs); +fz_device *fz_new_draw_device_with_proof(fz_context *ctx, fz_matrix transform, fz_pixmap *dest, fz_colorspace *proof_cs); -/* - fz_new_draw_device_with_bbox_proof: Create a device to draw on a pixmap. +/** + Create a device to draw on a pixmap. dest: Target pixmap for the draw device. See fz_new_pixmap* for how to obtain a pixmap. The pixmap is not cleared by the @@ -369,23 +602,24 @@ fz_device *fz_new_draw_device_with_proof(fz_context *ctx, const fz_matrix *trans calling fz_new_draw_device. Free the device by calling fz_drop_device. - transform: Transform from user space in points to device space in pixels. + transform: Transform from user space in points to device space + in pixels. clip: Bounding box to restrict any marking operations of the draw device. - proof_cs: Color space to render to prior to mapping to color space defined by pixmap. + proof_cs: Color space to render to prior to mapping to color + space defined by pixmap. */ -fz_device *fz_new_draw_device_with_bbox_proof(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest, const fz_irect *clip, fz_colorspace *cs); +fz_device *fz_new_draw_device_with_bbox_proof(fz_context *ctx, fz_matrix transform, fz_pixmap *dest, const fz_irect *clip, fz_colorspace *cs); -fz_device *fz_new_draw_device_type3(fz_context *ctx, const fz_matrix *transform, fz_pixmap *dest); +fz_device *fz_new_draw_device_type3(fz_context *ctx, fz_matrix transform, fz_pixmap *dest); -/* - struct fz_draw_options: Options for creating a pixmap and draw device. +/** + struct fz_draw_options: Options for creating a pixmap and draw + device. */ -typedef struct fz_draw_options_s fz_draw_options; - -struct fz_draw_options_s +typedef struct { int rotate; int x_resolution; @@ -396,22 +630,25 @@ struct fz_draw_options_s int alpha; int graphics; int text; -}; +} fz_draw_options; -extern const char *fz_draw_options_usage; +FZ_DATA extern const char *fz_draw_options_usage; -/* - fz_parse_draw_options: Parse draw device options from a comma separated key-value string. +/** + Parse draw device options from a comma separated key-value string. */ fz_draw_options *fz_parse_draw_options(fz_context *ctx, fz_draw_options *options, const char *string); -/* - fz_new_draw_device_with_options: Create a new pixmap and draw device, using the specified options. +/** + Create a new pixmap and draw device, using the specified options. + + options: Options to configure the draw device, and choose the + resolution and colorspace. - options: Options to configure the draw device, and choose the resolution and colorspace. mediabox: The bounds of the page in points. + pixmap: An out parameter containing the newly created pixmap. */ -fz_device *fz_new_draw_device_with_options(fz_context *ctx, const fz_draw_options *options, const fz_rect *mediabox, fz_pixmap **pixmap); +fz_device *fz_new_draw_device_with_options(fz_context *ctx, const fz_draw_options *options, fz_rect mediabox, fz_pixmap **pixmap); #endif diff --git a/include/mupdf/fitz/display-list.h b/include/mupdf/fitz/display-list.h index b6a23e4..957efe4 100644 --- a/include/mupdf/fitz/display-list.h +++ b/include/mupdf/fitz/display-list.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_DISPLAY_LIST_H #define MUPDF_FITZ_DISPLAY_LIST_H @@ -6,11 +28,11 @@ #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/device.h" -/* +/** Display list device -- record and play back device commands. */ -/* +/** fz_display_list is a list containing drawing commands (text, images, etc.). The intent is two-fold: as a caching-mechanism to reduce parsing of a page, and to be used as a data @@ -22,20 +44,21 @@ list (once or many times) by calling fz_run_display_list. When the list is no longer needed drop it with fz_drop_display_list. */ -typedef struct fz_display_list_s fz_display_list; +typedef struct fz_display_list fz_display_list; -/* - fz_new_display_list: Create an empty display list. +/** + Create an empty display list. A display list contains drawing commands (text, images, etc.). Use fz_new_list_device for populating the list. - mediabox: Bounds of the page (in points) represented by the display list. + mediabox: Bounds of the page (in points) represented by the + display list. */ -fz_display_list *fz_new_display_list(fz_context *ctx, const fz_rect *mediabox); +fz_display_list *fz_new_display_list(fz_context *ctx, fz_rect mediabox); -/* - fz_new_list_device: Create a rendering device for a display list. +/** + Create a rendering device for a display list. When the device is rendering a page it will populate the display list with drawing commands (text, images, etc.). The @@ -44,24 +67,22 @@ fz_display_list *fz_new_display_list(fz_context *ctx, const fz_rect *mediabox); for each rendering. Once the device is no longer needed, free it with fz_drop_device. - list: A display list that the list device takes ownership of. + list: A display list that the list device takes a reference to. */ fz_device *fz_new_list_device(fz_context *ctx, fz_display_list *list); -/* - fz_run_display_list: (Re)-run a display list through a device. +/** + (Re)-run a display list through a device. list: A display list, created by fz_new_display_list and populated with objects from a page by running fz_run_page on a device obtained from fz_new_list_device. - dev: Device obtained from fz_new_*_device. - ctm: Transform to apply to display list contents. May include for example scaling and rotation, see fz_scale, fz_rotate and fz_concat. Set to fz_identity if no transformation is desired. - area: Only the part of the contents of the display list + scissor: Only the part of the contents of the display list visible within this area will be considered when the list is run through the device. This does not imply for tile objects contained in the display list. @@ -73,25 +94,31 @@ fz_device *fz_new_list_device(fz_context *ctx, fz_display_list *list); progress information back to the caller. The fields inside cookie are continually updated while the page is being run. */ -void fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, const fz_matrix *ctm, const fz_rect *area, fz_cookie *cookie); +void fz_run_display_list(fz_context *ctx, fz_display_list *list, fz_device *dev, fz_matrix ctm, fz_rect scissor, fz_cookie *cookie); -/* - fz_keep_display_list: Keep a reference to a display list. +/** + Increment the reference count for a display list. Returns the + same pointer. + + Never throws exceptions. */ fz_display_list *fz_keep_display_list(fz_context *ctx, fz_display_list *list); -/* - fz_drop_display_list: Drop a reference to a display list, freeing it - if the reference count reaches zero. +/** + Decrement the reference count for a display list. When the + reference count reaches zero, all the references in the display + list itself are dropped, and the display list is freed. + + Never throws exceptions. */ void fz_drop_display_list(fz_context *ctx, fz_display_list *list); -/* - fz_bound_display_list: Return the bounding box of the page recorded in a display list. +/** + Return the bounding box of the page recorded in a display list. */ -fz_rect *fz_bound_display_list(fz_context *ctx, fz_display_list *list, fz_rect *bounds); +fz_rect fz_bound_display_list(fz_context *ctx, fz_display_list *list); -/* +/** Create a new image from a display list. w, h: The conceptual width/height of the image. @@ -103,7 +130,7 @@ fz_rect *fz_bound_display_list(fz_context *ctx, fz_display_list *list, fz_rect * */ fz_image *fz_new_image_from_display_list(fz_context *ctx, float w, float h, fz_display_list *list); -/* +/** Check for a display list being empty list: The list to check. diff --git a/include/mupdf/fitz/document.h b/include/mupdf/fitz/document.h index 95e5963..eca2a70 100644 --- a/include/mupdf/fitz/document.h +++ b/include/mupdf/fitz/document.h @@ -1,7 +1,30 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_DOCUMENT_H #define MUPDF_FITZ_DOCUMENT_H #include "mupdf/fitz/system.h" +#include "mupdf/fitz/types.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/device.h" @@ -10,26 +33,90 @@ #include "mupdf/fitz/outline.h" #include "mupdf/fitz/separation.h" -/* - Document interface -*/ -typedef struct fz_document_s fz_document; -typedef struct fz_document_handler_s fz_document_handler; -typedef struct fz_page_s fz_page; -typedef struct fz_annot_s fz_annot; +typedef struct fz_document_handler fz_document_handler; +typedef struct fz_page fz_page; typedef intptr_t fz_bookmark; +typedef enum +{ + FZ_MEDIA_BOX, + FZ_CROP_BOX, + FZ_BLEED_BOX, + FZ_TRIM_BOX, + FZ_ART_BOX, + FZ_UNKNOWN_BOX +} fz_box_type; + +fz_box_type fz_box_type_from_string(const char *name); +const char *fz_string_from_box_type(fz_box_type box); + +/** + Simple constructor for fz_locations. +*/ +static inline fz_location fz_make_location(int chapter, int page) +{ + fz_location loc = { chapter, page }; + return loc; +} + +enum +{ + /* 6in at 4:3 */ + FZ_LAYOUT_KINDLE_W = 260, + FZ_LAYOUT_KINDLE_H = 346, + FZ_LAYOUT_KINDLE_EM = 9, + + /* 4.25 x 6.87 in */ + FZ_LAYOUT_US_POCKET_W = 306, + FZ_LAYOUT_US_POCKET_H = 495, + FZ_LAYOUT_US_POCKET_EM = 10, + + /* 5.5 x 8.5 in */ + FZ_LAYOUT_US_TRADE_W = 396, + FZ_LAYOUT_US_TRADE_H = 612, + FZ_LAYOUT_US_TRADE_EM = 11, + + /* 110 x 178 mm */ + FZ_LAYOUT_UK_A_FORMAT_W = 312, + FZ_LAYOUT_UK_A_FORMAT_H = 504, + FZ_LAYOUT_UK_A_FORMAT_EM = 10, + + /* 129 x 198 mm */ + FZ_LAYOUT_UK_B_FORMAT_W = 366, + FZ_LAYOUT_UK_B_FORMAT_H = 561, + FZ_LAYOUT_UK_B_FORMAT_EM = 10, + + /* 135 x 216 mm */ + FZ_LAYOUT_UK_C_FORMAT_W = 382, + FZ_LAYOUT_UK_C_FORMAT_H = 612, + FZ_LAYOUT_UK_C_FORMAT_EM = 11, + + /* 148 x 210 mm */ + FZ_LAYOUT_A5_W = 420, + FZ_LAYOUT_A5_H = 595, + FZ_LAYOUT_A5_EM = 11, + + /* Default to A5 */ + FZ_DEFAULT_LAYOUT_W = FZ_LAYOUT_A5_W, + FZ_DEFAULT_LAYOUT_H = FZ_LAYOUT_A5_H, + FZ_DEFAULT_LAYOUT_EM = FZ_LAYOUT_A5_EM, +}; + typedef enum { FZ_PERMISSION_PRINT = 'p', FZ_PERMISSION_COPY = 'c', FZ_PERMISSION_EDIT = 'e', FZ_PERMISSION_ANNOTATE = 'n', + FZ_PERMISSION_FORM = 'f', + FZ_PERMISSION_ACCESSIBILITY = 'y', + FZ_PERMISSION_ASSEMBLE = 'a', + FZ_PERMISSION_PRINT_HQ = 'h', } fz_permission; -/* - fz_document_drop_fn: Type for a function to be called when +/** + Type for a function to be called when the reference count for the fz_document drops to 0. The implementation should release any resources held by the document. The actual document pointer will be freed by the @@ -37,241 +124,237 @@ fz_permission; */ typedef void (fz_document_drop_fn)(fz_context *ctx, fz_document *doc); -/* - fz_document_needs_password_fn: Type for a function to be +/** + Type for a function to be called to enquire whether the document needs a password or not. See fz_needs_password for more information. */ typedef int (fz_document_needs_password_fn)(fz_context *ctx, fz_document *doc); -/* - fz_document_authenticate_password_fn: Type for a function to be +/** + Type for a function to be called to attempt to authenticate a password. See fz_authenticate_password for more information. */ typedef int (fz_document_authenticate_password_fn)(fz_context *ctx, fz_document *doc, const char *password); -/* - fz_document_has_permission_fn: Type for a function to be +/** + Type for a function to be called to see if a document grants a certain permission. See fz_document_has_permission for more information. */ typedef int (fz_document_has_permission_fn)(fz_context *ctx, fz_document *doc, fz_permission permission); -/* - fz_document_load_outline_fn: Type for a function to be called to +/** + Type for a function to be called to load the outlines for a document. See fz_document_load_outline for more information. */ typedef fz_outline *(fz_document_load_outline_fn)(fz_context *ctx, fz_document *doc); -/* - fz_document_layout_fn: Type for a function to be called to lay +/** + Type for a function to be called to obtain an outline iterator + for a document. See fz_document_outline_iterator for more information. +*/ +typedef fz_outline_iterator *(fz_document_outline_iterator_fn)(fz_context *ctx, fz_document *doc); + +/** + Type for a function to be called to lay out a document. See fz_layout_document for more information. */ typedef void (fz_document_layout_fn)(fz_context *ctx, fz_document *doc, float w, float h, float em); -/* - fz_document_resolve_link_fn: Type for a function to be called to - resolve an internal link to a page number. See fz_resolve_link - for more information. +/** + Type for a function to be called to + resolve an internal link to a location (chapter/page number + tuple). See fz_resolve_link_dest for more information. */ -typedef int (fz_document_resolve_link_fn)(fz_context *ctx, fz_document *doc, const char *uri, float *xp, float *yp); +typedef fz_link_dest (fz_document_resolve_link_dest_fn)(fz_context *ctx, fz_document *doc, const char *uri); -/* - fz_document_count_pages_fn: Type for a function to be called to +/** + Type for a function to be called to + create an internal link to a destination (chapter/page/x/y/w/h/zoom/type + tuple). See fz_resolve_link_dest for more information. +*/ +typedef char * (fz_document_format_link_uri_fn)(fz_context *ctx, fz_document *doc, fz_link_dest dest); + +/** + Type for a function to be called to + count the number of chapters in a document. See + fz_count_chapters for more information. +*/ +typedef int (fz_document_count_chapters_fn)(fz_context *ctx, fz_document *doc); + +/** + Type for a function to be called to count the number of pages in a document. See fz_count_pages for more information. */ -typedef int (fz_document_count_pages_fn)(fz_context *ctx, fz_document *doc); +typedef int (fz_document_count_pages_fn)(fz_context *ctx, fz_document *doc, int chapter); -/* - fz_document_load_page_fn: Type for a function to load a given +/** + Type for a function to load a given page from a document. See fz_load_page for more information. */ -typedef fz_page *(fz_document_load_page_fn)(fz_context *ctx, fz_document *doc, int number); +typedef fz_page *(fz_document_load_page_fn)(fz_context *ctx, fz_document *doc, int chapter, int page); -/* - fz_document_lookup_metadata_fn: Type for a function to query - a documents metadata. See fz_lookup_metadata for more +/** + Type for a function to get the page label of a page in the document. + See fz_page_label for more information. +*/ +typedef void (fz_document_page_label_fn)(fz_context *ctx, fz_document *doc, int chapter, int page, char *buf, size_t size); + +/** + Type for a function to query + a document's metadata. See fz_lookup_metadata for more information. */ -typedef int (fz_document_lookup_metadata_fn)(fz_context *ctx, fz_document *doc, const char *key, char *buf, int size); +typedef int (fz_document_lookup_metadata_fn)(fz_context *ctx, fz_document *doc, const char *key, char *buf, size_t size); -/* - fz_document_output_intent_fn: Return output intent color space if it exists +/** + Type for a function to set + a document's metadata. See fz_set_metadata for more + information. */ -typedef fz_colorspace* (fz_document_output_intent_fn)(fz_context *ctx, fz_document *doc); +typedef void (fz_document_set_metadata_fn)(fz_context *ctx, fz_document *doc, const char *key, const char *value); -/* - fz_document_make_bookmark_fn: Type for a function to make +/** + Return output intent color space if it exists +*/ +typedef fz_colorspace *(fz_document_output_intent_fn)(fz_context *ctx, fz_document *doc); + +/** + Write document accelerator data +*/ +typedef void (fz_document_output_accelerator_fn)(fz_context *ctx, fz_document *doc, fz_output *out); + +/** + Send document structure to device +*/ +typedef void (fz_document_run_structure_fn)(fz_context *ctx, fz_document *doc, fz_device *dev, fz_cookie *cookie); + +/** + Get a handle to this document as PDF. + + Returns a borrowed handle. +*/ +typedef fz_document *(fz_document_as_pdf_fn)(fz_context *ctx, fz_document *doc); + +/** + Type for a function to make a bookmark. See fz_make_bookmark for more information. */ -typedef fz_bookmark (fz_document_make_bookmark_fn)(fz_context *ctx, fz_document *doc, int page); +typedef fz_bookmark (fz_document_make_bookmark_fn)(fz_context *ctx, fz_document *doc, fz_location loc); -/* - fz_document_lookup_bookmark_fn: Type for a function to lookup - a bookmark. See fz_lookup_bookmark for more information. +/** + Type for a function to lookup a bookmark. + See fz_lookup_bookmark for more information. */ -typedef int (fz_document_lookup_bookmark_fn)(fz_context *ctx, fz_document *doc, fz_bookmark mark); +typedef fz_location (fz_document_lookup_bookmark_fn)(fz_context *ctx, fz_document *doc, fz_bookmark mark); -/* - fz_page_drop_page_fn: Type for a function to release all the +/** + Type for a function to release all the resources held by a page. Called automatically when the reference count for that page reaches zero. */ typedef void (fz_page_drop_page_fn)(fz_context *ctx, fz_page *page); -/* - fz_page_bound_page_fn: Type for a function to return the +/** + Type for a function to return the bounding box of a page. See fz_bound_page for more information. */ -typedef fz_rect *(fz_page_bound_page_fn)(fz_context *ctx, fz_page *page, fz_rect *); +typedef fz_rect (fz_page_bound_page_fn)(fz_context *ctx, fz_page *page, fz_box_type box); -/* - fz_page_run_page_contents_fn: Type for a function to run the +/** + Type for a function to run the contents of a page. See fz_run_page_contents for more information. */ -typedef void (fz_page_run_page_contents_fn)(fz_context *ctx, fz_page *page, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie); +typedef void (fz_page_run_page_fn)(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); -/* - fz_page_load_links_fn: Type for a function to load the links +/** + Type for a function to load the links from a page. See fz_load_links for more information. */ typedef fz_link *(fz_page_load_links_fn)(fz_context *ctx, fz_page *page); -/* - fz_page_first_annot_fn: Type for a function to load the - annotations from a page. See fz_first_annot for more - information. -*/ -typedef fz_annot *(fz_page_first_annot_fn)(fz_context *ctx, fz_page *page); - -/* - fz_page_page_presentation_fn: Type for a function to +/** + Type for a function to obtain the details of how this page should be presented when in presentation mode. See fz_page_presentation for more information. */ typedef fz_transition *(fz_page_page_presentation_fn)(fz_context *ctx, fz_page *page, fz_transition *transition, float *duration); -/* - fz_page_control_separation: Type for a function to enable/ +/** + Type for a function to enable/ disable separations on a page. See fz_control_separation for more information. */ typedef void (fz_page_control_separation_fn)(fz_context *ctx, fz_page *page, int separation, int disable); -/* - fz_page_separation_disabled_fn: Type for a function to detect +/** + Type for a function to detect whether a given separation is enabled or disabled on a page. See FZ_SEPARATION_DISABLED for more information. */ typedef int (fz_page_separation_disabled_fn)(fz_context *ctx, fz_page *page, int separation); -/* - fz_page_separations_fn: Type for a function to retrieve +/** + Type for a function to retrieve details of separations on a page. See fz_get_separations for more information. */ typedef fz_separations *(fz_page_separations_fn)(fz_context *ctx, fz_page *page); -/* - fz_page_uses_overprint_fn: Type for a function to retrieve +/** + Type for a function to retrieve whether or not a given page uses overprint. */ typedef int (fz_page_uses_overprint_fn)(fz_context *ctx, fz_page *page); -typedef void (fz_annot_drop_fn)(fz_context *ctx, fz_annot *annot); -typedef fz_annot *(fz_annot_next_fn)(fz_context *ctx, fz_annot *annot); -typedef fz_rect *(fz_annot_bound_fn)(fz_context *ctx, fz_annot *annot, fz_rect *rect); -typedef void (fz_annot_run_fn)(fz_context *ctx, fz_annot *annot, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie); -/* - Structure definition is public so other classes can - derive from it. Do not access the members directly. +/** + Type for a function to create a link on a page. */ -struct fz_annot_s -{ - int refs; - fz_annot_drop_fn *drop_annot; - fz_annot_bound_fn *bound_annot; - fz_annot_run_fn *run_annot; - fz_annot_next_fn *next_annot; -}; +typedef fz_link *(fz_page_create_link_fn)(fz_context *ctx, fz_page *page, fz_rect bbox, const char *uri); -/* - Structure definition is public so other classes can - derive from it. Do not access the members directly. +/** + Type for a function to delete a link on a page. */ -struct fz_page_s -{ - int refs; - fz_page_drop_page_fn *drop_page; - fz_page_bound_page_fn *bound_page; - fz_page_run_page_contents_fn *run_page_contents; - fz_page_load_links_fn *load_links; - fz_page_first_annot_fn *first_annot; - fz_page_page_presentation_fn *page_presentation; - fz_page_control_separation_fn *control_separation; - fz_page_separation_disabled_fn *separation_disabled; - fz_page_separations_fn *separations; - fz_page_uses_overprint_fn *overprint; -}; +typedef void (fz_page_delete_link_fn)(fz_context *ctx, fz_page *page, fz_link *link); -/* - Structure definition is public so other classes can - derive from it. Callers shoud not access the members - directly, though implementations will need initialize - functions directly. -*/ -struct fz_document_s -{ - int refs; - fz_document_drop_fn *drop_document; - fz_document_needs_password_fn *needs_password; - fz_document_authenticate_password_fn *authenticate_password; - fz_document_has_permission_fn *has_permission; - fz_document_load_outline_fn *load_outline; - fz_document_layout_fn *layout; - fz_document_make_bookmark_fn *make_bookmark; - fz_document_lookup_bookmark_fn *lookup_bookmark; - fz_document_resolve_link_fn *resolve_link; - fz_document_count_pages_fn *count_pages; - fz_document_load_page_fn *load_page; - fz_document_lookup_metadata_fn *lookup_metadata; - fz_document_output_intent_fn *get_output_intent; - int did_layout; - int is_reflowable; -}; - -/* - fz_document_open_fn: Function type to open a document from a - file. - - filename: file to open - - Pointer to opened document. Throws exception in case of error. -*/ -typedef fz_document *(fz_document_open_fn)(fz_context *ctx, const char *filename); - -/* - fz_document_open_with_stream_fn: Function type to open a +/** + Function type to open a document from a file. + handler: the document handler in use. + stream: fz_stream to read document data from. Must be seekable for formats that require it. + accel: fz_stream to read accelerator data from. May be + NULL. May be ignored. + + dir: 'Directory context' in which the document is loaded; + associated content from (like images for an html stream + will be loaded from this). Maybe NULL. May be ignored. + + recognize_state: NULL, or a state pointer passed back from the call + to recognise_content_fn. Ownership does not pass in. The + caller remains responsible for freeing state. + Pointer to opened document. Throws exception in case of error. */ -typedef fz_document *(fz_document_open_with_stream_fn)(fz_context *ctx, fz_stream *stream); +typedef fz_document *(fz_document_open_fn)(fz_context *ctx, const fz_document_handler *handler, fz_stream *stream, fz_stream *accel, fz_archive *dir, void *recognize_state); -/* - fz_document_recognize_fn: Recognize a document type from +/** + Recognize a document type from a magic string. + handler: the handler in use. + magic: string to recognise - typically a filename or mime type. @@ -279,44 +362,114 @@ typedef fz_document *(fz_document_open_with_stream_fn)(fz_context *ctx, fz_strea (fully recognized) based on how certain the recognizer is that this is of the required type. */ -typedef int (fz_document_recognize_fn)(fz_context *ctx, const char *magic); +typedef int (fz_document_recognize_fn)(fz_context *ctx, const fz_document_handler *handler, const char *magic); -struct fz_document_handler_s -{ - fz_document_recognize_fn *recognize; - fz_document_open_fn *open; - fz_document_open_with_stream_fn *open_with_stream; - const char **extensions; - const char **mimetypes; -}; +typedef void (fz_document_recognize_state_free_fn)(fz_context *ctx, void *state); -/* - fz_register_document_handler: Register a handler - for a document type. +/** + Recognize a document type from stream contents. - handler: The handler to register. + handler: the handler in use. + + stream: stream contents to recognise (may be NULL if document is + a directory). + + dir: directory context from which stream is loaded. + + recognize_state: pointer to retrieve opaque state that may be used + by the open routine, or NULL. + + free_recognize_state: pointer to retrieve a function pointer to + free the opaque state, or NULL. + + Note: state and free_state should either both be NULL or + both be non-NULL! + + Returns a number between 0 (not recognized) and 100 + (fully recognized) based on how certain the recognizer + is that this is of the required type. +*/ +typedef int (fz_document_recognize_content_fn)(fz_context *ctx, const fz_document_handler *handler, fz_stream *stream, fz_archive *dir, void **recognize_state, fz_document_recognize_state_free_fn **free_recognize_state); + +/** + Finalise a document handler. + + This will be called on shutdown for a document handler to + release resources. This should cope with being called with NULL. + + opaque: The value previously returned by the init call. +*/ +typedef void fz_document_handler_fin_fn(fz_context *ctx, const fz_document_handler *handler); + + + +/** + Type for a function to be called when processing an already opened page. + See fz_process_opened_pages. +*/ +typedef void *(fz_process_opened_page_fn)(fz_context *ctx, fz_page *page, void *state); + +/** + Register a handler for a document type. + + handler: The handler to register. This must live on for the duration of the + use of this handler. It will be passed back to the handler for calls so + the caller can use it to retrieve state. */ void fz_register_document_handler(fz_context *ctx, const fz_document_handler *handler); -/* - fz_register_document_handler: Register handlers - for all the standard document types supported in +/** + Register handlers for all the standard document types supported in this build. */ void fz_register_document_handlers(fz_context *ctx); -/* - fz_recognize_document: Given a magic find a document - handler that can handle a document of this type. +/** + Given a magic find a document handler that can handle a + document of this type. - magic: Can be a file extension (including initial period) or + magic: Can be a filename extension (including initial period) or a mimetype. */ const fz_document_handler *fz_recognize_document(fz_context *ctx, const char *magic); -/* - fz_open_document: Open a PDF, XPS or CBZ document. +/** + Given a filename find a document handler that can handle a + document of this type. + filename: The filename of the document. This will be opened and sampled + to check data. +*/ +const fz_document_handler *fz_recognize_document_content(fz_context *ctx, const char *filename); + +/** + Given a magic find a document handler that can handle a + document of this type. + + stream: the file stream to sample. May be NULL if the document is + a directory. + + magic: Can be a filename extension (including initial period) or + a mimetype. +*/ +const fz_document_handler *fz_recognize_document_stream_content(fz_context *ctx, fz_stream *stream, const char *magic); + +/** + Given a magic find a document handler that can handle a + document of this type. + + stream: the file stream to sample. May be NULL if the document is + a directory. + + dir: an fz_archive representing the directory from which the + stream was opened (or NULL). + + magic: Can be a filename extension (including initial period) or + a mimetype. +*/ +const fz_document_handler *fz_recognize_document_stream_and_dir_content(fz_context *ctx, fz_stream *stream, fz_archive *dir, const char *magic); + +/** Open a document file and read its basic structure so pages and objects can be located. MuPDF will try to repair broken documents (without actually changing the file contents). @@ -328,46 +481,139 @@ const fz_document_handler *fz_recognize_document(fz_context *ctx, const char *ma */ fz_document *fz_open_document(fz_context *ctx, const char *filename); -/* - fz_open_document_with_stream: Open a PDF, XPS or CBZ document. +/** + Open a document file and read its basic structure so pages and + objects can be located. MuPDF will try to repair broken + documents (without actually changing the file contents). + The returned fz_document is used when calling most other + document related functions. + + filename: a path to a file as it would be given to open(2). +*/ +fz_document *fz_open_accelerated_document(fz_context *ctx, const char *filename, const char *accel); + +/** Open a document using the specified stream object rather than opening a file on disk. - magic: a string used to detect document type; either a file name or mime-type. + magic: a string used to detect document type; either a file name + or mime-type. + + stream: a stream representing the contents of the document file. + + NOTE: The caller retains ownership of 'stream' - the document will take its + own reference if required. */ fz_document *fz_open_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stream); -/* - fz_new_document: Create and initialize a document struct. +/** + Open a document using the specified stream object rather than + opening a file on disk. + + magic: a string used to detect document type; either a file name + or mime-type. + + stream: a stream representing the contents of the document file. + + dir: a 'directory context' for those filetypes that need it. + + NOTE: The caller retains ownership of 'stream' and 'dir' - the document will + take its own references if required. +*/ +fz_document *fz_open_document_with_stream_and_dir(fz_context *ctx, const char *magic, fz_stream *stream, fz_archive *dir); + +/** + Open a document using a buffer rather than opening a file on disk. +*/ +fz_document *fz_open_document_with_buffer(fz_context *ctx, const char *magic, fz_buffer *buffer); + +/** + Open a document using the specified stream object rather than + opening a file on disk. + + magic: a string used to detect document type; either a file name + or mime-type. + + stream: a stream of the document contents. + + accel: NULL, or a stream of the 'accelerator' contents for this document. + + NOTE: The caller retains ownership of 'stream' and 'accel' - the document will + take its own references if required. +*/ +fz_document *fz_open_accelerated_document_with_stream(fz_context *ctx, const char *magic, fz_stream *stream, fz_stream *accel); + +/** + Open a document using the specified stream object rather than + opening a file on disk. + + magic: a string used to detect document type; either a file name + or mime-type. + + stream: a stream of the document contents. + + accel: NULL, or a stream of the 'accelerator' contents for this document. + + dir: NULL, or the 'directory context' for the stream contents. + + NOTE: The caller retains ownership of 'stream', 'accel' and 'dir' - the document will + take its own references if required. +*/ +fz_document *fz_open_accelerated_document_with_stream_and_dir(fz_context *ctx, const char *magic, fz_stream *stream, fz_stream *accel, fz_archive *dir); + +/** + Query if the document supports the saving of accelerator data. +*/ +int fz_document_supports_accelerator(fz_context *ctx, fz_document *doc); + +/** + Save accelerator data for the document to a given file. +*/ +void fz_save_accelerator(fz_context *ctx, fz_document *doc, const char *accel); + +/** + Output accelerator data for the document to a given output + stream. +*/ +void fz_output_accelerator(fz_context *ctx, fz_document *doc, fz_output *accel); + +/** + New documents are typically created by calls like + foo_new_document(fz_context *ctx, ...). These work by + deriving a new document type from fz_document, for instance: + typedef struct { fz_document base; ...extras... } foo_document; + These are allocated by calling + fz_new_derived_document(ctx, foo_document) */ void *fz_new_document_of_size(fz_context *ctx, int size); - #define fz_new_derived_document(C,M) ((M*)Memento_label(fz_new_document_of_size(C, sizeof(M)), #M)) -/* - fz_keep_document: Keep a reference to an open document. +/** + Increment the document reference count. The same pointer is + returned. + + Never throws exceptions. */ fz_document *fz_keep_document(fz_context *ctx, fz_document *doc); -/* - fz_drop_document: Release an open document. +/** + Decrement the document reference count. When the reference + count reaches 0, the document and all it's references are + freed. - The resource store in the context associated with fz_document - is emptied, and any allocations for the document are freed when - the last reference is dropped. + Never throws exceptions. */ void fz_drop_document(fz_context *ctx, fz_document *doc); -/* - fz_needs_password: Check if a document is encrypted with a +/** + Check if a document is encrypted with a non-blank password. */ int fz_needs_password(fz_context *ctx, fz_document *doc); -/* - fz_authenticate_password: Test if the given password can - decrypt the document. +/** + Test if the given password can decrypt the document. password: The password string to be checked. Some document specifications do not specify any particular text encoding, so @@ -384,69 +630,169 @@ int fz_needs_password(fz_context *ctx, fz_document *doc); */ int fz_authenticate_password(fz_context *ctx, fz_document *doc, const char *password); -/* - fz_load_outline: Load the hierarchical document outline. +/** + Load the hierarchical document outline. Should be freed by fz_drop_outline. */ fz_outline *fz_load_outline(fz_context *ctx, fz_document *doc); -/* - fz_is_document_reflowable: Is the document reflowable. +/** + Get an iterator for the document outline. + + Should be freed by fz_drop_outline_iterator. +*/ +fz_outline_iterator *fz_new_outline_iterator(fz_context *ctx, fz_document *doc); + +/** + Is the document reflowable. Returns 1 to indicate reflowable documents, otherwise 0. */ int fz_is_document_reflowable(fz_context *ctx, fz_document *doc); -/* - fz_layout_document: Layout reflowable document types. +/** + Layout reflowable document types. w, h: Page size in points. em: Default font size in points. */ void fz_layout_document(fz_context *ctx, fz_document *doc, float w, float h, float em); -/* - Create a bookmark for the given page, which can be used to find the - same location after the document has been laid out with different - parameters. +/** + Create a bookmark for the given page, which can be used to find + the same location after the document has been laid out with + different parameters. */ -fz_bookmark fz_make_bookmark(fz_context *ctx, fz_document *doc, int page); +fz_bookmark fz_make_bookmark(fz_context *ctx, fz_document *doc, fz_location loc); -/* +/** Find a bookmark and return its page number. */ -int fz_lookup_bookmark(fz_context *ctx, fz_document *doc, fz_bookmark mark); +fz_location fz_lookup_bookmark(fz_context *ctx, fz_document *doc, fz_bookmark mark); -/* - fz_count_pages: Return the number of pages in document +/** + Return the number of pages in document May return 0 for documents with no pages. */ int fz_count_pages(fz_context *ctx, fz_document *doc); -/* - fz_resolve_link: Resolve an internal link to a page number. +/** + Resolve an internal link to a page number, location, and possible viewing parameters. + + Returns location (-1,-1) if the URI cannot be resolved. +*/ +fz_link_dest fz_resolve_link_dest(fz_context *ctx, fz_document *doc, const char *uri); + +/** + Format an internal link to a page number, location, and possible viewing parameters, + suitable for use with fz_create_link. + + Returns a newly allocated string that the caller must free. +*/ +char *fz_format_link_uri(fz_context *ctx, fz_document *doc, fz_link_dest dest); + +/** + Resolve an internal link to a page number. xp, yp: Pointer to store coordinate of destination on the page. - Returns -1 if the URI cannot be resolved. + Returns (-1,-1) if the URI cannot be resolved. */ -int fz_resolve_link(fz_context *ctx, fz_document *doc, const char *uri, float *xp, float *yp); +fz_location fz_resolve_link(fz_context *ctx, fz_document *doc, const char *uri, float *xp, float *yp); -/* - fz_load_page: Load a page. +/** + Run the document structure through a device. + + doc: Document in question. + + dev: Device obtained from fz_new_*_device. + + cookie: Communication mechanism between caller and library. + Intended for multi-threaded applications, while + single-threaded applications set cookie to NULL. The + caller may abort an ongoing rendering of a page. Cookie also + communicates progress information back to the caller. The + fields inside cookie are continually updated while the page is + rendering. +*/ +void fz_run_document_structure(fz_context *ctx, fz_document *doc, fz_device *dev, fz_cookie *cookie); + +/** + Function to get the location for the last page in the document. + Using this can be far more efficient in some cases than calling + fz_count_pages and using the page number. +*/ +fz_location fz_last_page(fz_context *ctx, fz_document *doc); + +/** + Function to get the location of the next page (allowing for the + end of chapters etc). If at the end of the document, returns the + current location. +*/ +fz_location fz_next_page(fz_context *ctx, fz_document *doc, fz_location loc); + +/** + Function to get the location of the previous page (allowing for + the end of chapters etc). If already at the start of the + document, returns the current page. +*/ +fz_location fz_previous_page(fz_context *ctx, fz_document *doc, fz_location loc); + +/** + Clamps a location into valid chapter/page range. (First clamps + the chapter into range, then the page into range). +*/ +fz_location fz_clamp_location(fz_context *ctx, fz_document *doc, fz_location loc); + +/** + Converts from page number to chapter+page. This may cause many + chapters to be laid out in order to calculate the number of + pages within those chapters. +*/ +fz_location fz_location_from_page_number(fz_context *ctx, fz_document *doc, int number); + +/** + Converts from chapter+page to page number. This may cause many + chapters to be laid out in order to calculate the number of + pages within those chapters. +*/ +int fz_page_number_from_location(fz_context *ctx, fz_document *doc, fz_location loc); + +/** + Load a given page number from a document. This may be much less + efficient than loading by location (chapter+page) for some + document types. +*/ +fz_page *fz_load_page(fz_context *ctx, fz_document *doc, int number); + +/** + Return the number of chapters in the document. + At least 1. +*/ +int fz_count_chapters(fz_context *ctx, fz_document *doc); + +/** + Return the number of pages in a chapter. + May return 0. +*/ +int fz_count_chapter_pages(fz_context *ctx, fz_document *doc, int chapter); + +/** + Load a page. After fz_load_page is it possible to retrieve the size of the page using fz_bound_page, or to render the page using fz_run_page_*. Free the page by calling fz_drop_page. - number: page number, 0 is the first page of the document. + chapter: chapter number, 0 is the first chapter of the document. + number: page number, 0 is the first page of the chapter. */ -fz_page *fz_load_page(fz_context *ctx, fz_document *doc, int number); +fz_page *fz_load_chapter_page(fz_context *ctx, fz_document *doc, int chapter, int page); -/* - fz_load_links: Load the list of links for a page. +/** + Load the list of links for a page. Returns a linked list of all the links on the page, each with its clickable region and link destination. Each link is @@ -457,22 +803,23 @@ fz_page *fz_load_page(fz_context *ctx, fz_document *doc, int number); */ fz_link *fz_load_links(fz_context *ctx, fz_page *page); -/* - fz_new_page_of_size: Create and initialize a page struct. +/** + Different document types will be implemented by deriving from + fz_page. This macro allocates such derived structures, and + initialises the base sections. */ -fz_page *fz_new_page_of_size(fz_context *ctx, int size); - -#define fz_new_derived_page(CTX,TYPE) \ - ((TYPE *)Memento_label(fz_new_page_of_size(CTX,sizeof(TYPE)),#TYPE)) - -/* - fz_bound_page: Determine the size of a page at 72 dpi. +fz_page *fz_new_page_of_size(fz_context *ctx, int size, fz_document *doc); +#define fz_new_derived_page(CTX,TYPE,DOC) \ + ((TYPE *)Memento_label(fz_new_page_of_size(CTX,sizeof(TYPE),DOC),#TYPE)) +/** + Determine the size of a page at 72 dpi. */ -fz_rect *fz_bound_page(fz_context *ctx, fz_page *page, fz_rect *rect); +fz_rect fz_bound_page(fz_context *ctx, fz_page *page); +fz_rect fz_bound_page_box(fz_context *ctx, fz_page *page, fz_box_type box); -/* - fz_run_page: Run a page through a device. +/** + Run a page through a device. page: Page obtained from fz_load_page. @@ -490,10 +837,10 @@ fz_rect *fz_bound_page(fz_context *ctx, fz_page *page, fz_rect *rect); fields inside cookie are continually updated while the page is rendering. */ -void fz_run_page(fz_context *ctx, fz_page *page, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie); +void fz_run_page(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); -/* - fz_run_page_contents: Run a page through a device. Just the main +/** + Run a page through a device. Just the main page content, without the annotations, if any. page: Page obtained from fz_load_page. @@ -512,61 +859,68 @@ void fz_run_page(fz_context *ctx, fz_page *page, fz_device *dev, const fz_matrix fields inside cookie are continually updated while the page is rendering. */ -void fz_run_page_contents(fz_context *ctx, fz_page *page, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie); +void fz_run_page_contents(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); -/* - fz_run_annot: Run an annotation through a device. - - page: Page obtained from fz_load_page. - - annot: an annotation. - - dev: Device obtained from fz_new_*_device. - - transform: Transform to apply to page. May include for example - scaling and rotation, see fz_scale, fz_rotate and fz_concat. - Set to fz_identity if no transformation is desired. - - cookie: Communication mechanism between caller and library - rendering the page. Intended for multi-threaded applications, - while single-threaded applications set cookie to NULL. The - caller may abort an ongoing rendering of a page. Cookie also - communicates progress information back to the caller. The - fields inside cookie are continually updated while the page is - rendering. +/** + Run the annotations on a page through a device. */ -void fz_run_annot(fz_context *ctx, fz_annot *annot, fz_device *dev, const fz_matrix *transform, fz_cookie *cookie); +void fz_run_page_annots(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); -/* - fz_keep_page: Keep a reference to a loaded page. +/** + Run the widgets on a page through a device. +*/ +void fz_run_page_widgets(fz_context *ctx, fz_page *page, fz_device *dev, fz_matrix transform, fz_cookie *cookie); + +/** + Increment the reference count for the page. Returns the same + pointer. + + Never throws exceptions. */ fz_page *fz_keep_page(fz_context *ctx, fz_page *page); -/* - fz_drop_page: Free a loaded page. +/** + Increment the reference count for the page. Returns the same + pointer. Must only be used when the alloc lock is already taken. + + Never throws exceptions. +*/ +fz_page *fz_keep_page_locked(fz_context *ctx, fz_page *page); + +/** + Decrements the reference count for the page. When the reference + count hits 0, the page and its references are freed. + + Never throws exceptions. */ void fz_drop_page(fz_context *ctx, fz_page *page); -/* - fz_page_presentation: Get the presentation details for a given page. +/** + Get the presentation details for a given page. transition: A pointer to a transition struct to fill out. - duration: A pointer to a place to set the page duration in seconds. - Will be set to 0 if no transition is specified for the page. + duration: A pointer to a place to set the page duration in + seconds. Will be set to 0 if no transition is specified for the + page. - Returns: a pointer to the transition structure, or NULL if there is no - transition specified for the page. + Returns: a pointer to the transition structure, or NULL if there + is no transition specified for the page. */ fz_transition *fz_page_presentation(fz_context *ctx, fz_page *page, fz_transition *transition, float *duration); -/* - fz_has_permission: Check permission flags on document. +/** + Get page label for a given page. +*/ +const char *fz_page_label(fz_context *ctx, fz_page *page, char *buf, int size); + +/** + Check permission flags on document. */ int fz_has_permission(fz_context *ctx, fz_document *doc, fz_permission p); -/* - fz_lookup_metadata: Retrieve document meta data strings. +/** + Retrieve document meta data strings. doc: The document to query. @@ -586,59 +940,169 @@ int fz_has_permission(fz_context *ctx, fz_document *doc, fz_permission p); 'info:CreationDate' 'info:ModDate' - buf: The buffer to hold the results (a nul-terminated UTF-8 string). + buf: The buffer to hold the results (a nul-terminated UTF-8 + string). size: Size of 'buf'. - Returns the size of the output string (may be larger than 'size' if - the output was truncated), or -1 if the key is not recognized or found. + Returns the number of bytes need to store the string plus terminator + (will be larger than 'size' if the output was truncated), or -1 if the + key is not recognized or found. */ int fz_lookup_metadata(fz_context *ctx, fz_document *doc, const char *key, char *buf, int size); #define FZ_META_FORMAT "format" #define FZ_META_ENCRYPTION "encryption" -#define FZ_META_INFO_AUTHOR "info:Author" +#define FZ_META_INFO "info:" #define FZ_META_INFO_TITLE "info:Title" +#define FZ_META_INFO_AUTHOR "info:Author" +#define FZ_META_INFO_SUBJECT "info:Subject" +#define FZ_META_INFO_KEYWORDS "info:Keywords" +#define FZ_META_INFO_CREATOR "info:Creator" +#define FZ_META_INFO_PRODUCER "info:Producer" +#define FZ_META_INFO_CREATIONDATE "info:CreationDate" +#define FZ_META_INFO_MODIFICATIONDATE "info:ModDate" -/* - Find the output intent colorspace if the document has defined one. +void fz_set_metadata(fz_context *ctx, fz_document *doc, const char *key, const char *value); + +/** + Find the output intent colorspace if the document has defined + one. + + Returns a borrowed reference that should not be dropped, unless + it is kept first. */ fz_colorspace *fz_document_output_intent(fz_context *ctx, fz_document *doc); -/* - fz_page_separations: Get the separations details for a page. +/** + Get the separations details for a page. This will be NULL, unless the format specifically supports - separations (such as gproof, or PDF files). May be NULL even + separations (such as PDF files). May be NULL even so, if there are no separations on a page. Returns a reference that must be dropped. */ fz_separations *fz_page_separations(fz_context *ctx, fz_page *page); -/* - fz_page_uses_overprint: Find out whether a given page requests - overprint. +/** + Query if a given page requires overprint. */ int fz_page_uses_overprint(fz_context *ctx, fz_page *page); -/* - fz_save_gproof: Given a currently open document, create a - gproof skeleton file from that document. - - doc_filename: The name of the currently opened document file. - - doc: The currently opened document. - - filename: The filename of the desired gproof file. - - res: The resolution at which proofing should be done. - - print_profile: The filename of the ICC profile for the printer we are proofing - - display_profile: The filename of the ICC profile for our display device +/** + Create a new link on a page. */ -void fz_save_gproof(fz_context *ctx, const char *doc_filename, fz_document *doc, const char *filename, int res, - const char *print_profile, const char *display_profile); +fz_link *fz_create_link(fz_context *ctx, fz_page *page, fz_rect bbox, const char *uri); + +/** + Delete an existing link on a page. +*/ +void fz_delete_link(fz_context *ctx, fz_page *page, fz_link *link); + +/** + Iterates over all opened pages of the document, calling the + provided callback for each page for processing. If the callback + returns non-NULL then the iteration stops and that value is returned + to the called of fz_process_opened_pages(). + + The state pointer provided to fz_process_opened_pages() is + passed on to the callback but is owned by the caller. + + Returns the first non-NULL value returned by the callback, + or NULL if the callback returned NULL for all opened pages. +*/ +void *fz_process_opened_pages(fz_context *ctx, fz_document *doc, fz_process_opened_page_fn *process_openend_page, void *state); + +/* Implementation details: subject to change. */ + +/** + Structure definition is public so other classes can + derive from it. Do not access the members directly. +*/ +struct fz_page +{ + int refs; + fz_document *doc; /* kept reference to parent document. Guaranteed non-NULL. */ + int chapter; /* chapter number */ + int number; /* page number in chapter */ + int incomplete; /* incomplete from progressive loading; don't cache! */ + fz_page_drop_page_fn *drop_page; + fz_page_bound_page_fn *bound_page; + fz_page_run_page_fn *run_page_contents; + fz_page_run_page_fn *run_page_annots; + fz_page_run_page_fn *run_page_widgets; + fz_page_load_links_fn *load_links; + fz_page_page_presentation_fn *page_presentation; + fz_page_control_separation_fn *control_separation; + fz_page_separation_disabled_fn *separation_disabled; + fz_page_separations_fn *separations; + fz_page_uses_overprint_fn *overprint; + fz_page_create_link_fn *create_link; + fz_page_delete_link_fn *delete_link; + + /* linked list of currently open pages. This list is maintained + * by fz_load_chapter_page and fz_drop_page. All pages hold a + * kept reference to the document, so the document cannot disappear + * while pages exist. 'Incomplete' pages are NOT kept in this + * list. */ + fz_page **prev, *next; +}; + +/** + Structure definition is public so other classes can + derive from it. Callers should not access the members + directly, though implementations will need initialize + functions directly. +*/ +struct fz_document +{ + int refs; + fz_document_drop_fn *drop_document; + fz_document_needs_password_fn *needs_password; + fz_document_authenticate_password_fn *authenticate_password; + fz_document_has_permission_fn *has_permission; + fz_document_load_outline_fn *load_outline; + fz_document_outline_iterator_fn *outline_iterator; + fz_document_layout_fn *layout; + fz_document_make_bookmark_fn *make_bookmark; + fz_document_lookup_bookmark_fn *lookup_bookmark; + fz_document_resolve_link_dest_fn *resolve_link_dest; + fz_document_format_link_uri_fn *format_link_uri; + fz_document_count_chapters_fn *count_chapters; + fz_document_count_pages_fn *count_pages; + fz_document_load_page_fn *load_page; + fz_document_page_label_fn *page_label; + fz_document_lookup_metadata_fn *lookup_metadata; + fz_document_set_metadata_fn *set_metadata; + fz_document_output_intent_fn *get_output_intent; + fz_document_output_accelerator_fn *output_accelerator; + fz_document_run_structure_fn *run_structure; + fz_document_as_pdf_fn *as_pdf; + int did_layout; + int is_reflowable; + + /* Linked list of currently open pages. These are not + * references, but just a linked list of open pages, + * maintained by fz_load_chapter_page, and fz_drop_page. + * Every page holds a kept reference to the document, so + * the document cannot be destroyed while a page exists. + * Incomplete pages are NOT inserted into this list, but + * do still hold a real document reference. */ + fz_page *open; +}; + +struct fz_document_handler +{ + /* These fields are initialised by the handler when it is registered. */ + fz_document_recognize_fn *recognize; + fz_document_open_fn *open; + const char **extensions; + const char **mimetypes; + fz_document_recognize_content_fn *recognize_content; + int wants_dir; + int wants_file; + fz_document_handler_fin_fn *fin; +}; #endif diff --git a/include/mupdf/fitz/export.h b/include/mupdf/fitz/export.h new file mode 100644 index 0000000..853e2d5 --- /dev/null +++ b/include/mupdf/fitz/export.h @@ -0,0 +1,52 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_EXPORT_H +#define MUPDF_FITZ_EXPORT_H + +/* + * Support for building/using MuPDF DLL on Windows. + * + * When compiling code that uses MuPDF DLL, FZ_DLL_CLIENT should be defined. + * + * When compiling MuPDF DLL itself, FZ_DLL should be defined. + */ + +#if defined(_WIN32) || defined(_WIN64) + #if defined(FZ_DLL) + /* Building DLL. */ + #define FZ_FUNCTION __declspec(dllexport) + #define FZ_DATA __declspec(dllexport) + #elif defined(FZ_DLL_CLIENT) + /* Building DLL client code. */ + #define FZ_FUNCTION __declspec(dllexport) + #define FZ_DATA __declspec(dllimport) + #else + #define FZ_FUNCTION + #define FZ_DATA + #endif +#else + #define FZ_FUNCTION + #define FZ_DATA +#endif + +#endif diff --git a/include/mupdf/fitz/filter.h b/include/mupdf/fitz/filter.h index 782c4d8..bfa8f9d 100644 --- a/include/mupdf/fitz/filter.h +++ b/include/mupdf/fitz/filter.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_FILTER_H #define MUPDF_FITZ_FILTER_H @@ -7,40 +29,235 @@ #include "mupdf/fitz/store.h" #include "mupdf/fitz/stream.h" -typedef struct fz_jbig2_globals_s fz_jbig2_globals; +typedef struct fz_jbig2_globals fz_jbig2_globals; typedef struct { int64_t offset; - int len; + uint64_t length; } fz_range; -fz_stream *fz_open_copy(fz_context *ctx, fz_stream *chain); -fz_stream *fz_open_null_n(fz_context *ctx, fz_stream *chain, fz_range *ranges, int nranges); -fz_stream *fz_open_null(fz_context *ctx, fz_stream *chain, int len, int64_t offset); +/** + The null filter reads a specified amount of data from the + substream. +*/ +fz_stream *fz_open_null_filter(fz_context *ctx, fz_stream *chain, uint64_t len, int64_t offset); + +/** + The range filter copies data from specified ranges of the + chained stream. +*/ +fz_stream *fz_open_range_filter(fz_context *ctx, fz_stream *chain, fz_range *ranges, int nranges); + +/** + The endstream filter reads a PDF substream, and starts to look + for an 'endstream' token after the specified length. +*/ +fz_stream *fz_open_endstream_filter(fz_context *ctx, fz_stream *chain, uint64_t len, int64_t offset); + +/** + Concat filter concatenates several streams into one. +*/ fz_stream *fz_open_concat(fz_context *ctx, int max, int pad); -void fz_concat_push_drop(fz_context *ctx, fz_stream *concat, fz_stream *chain); /* Ownership of chain is passed in */ + +/** + Add a chained stream to the end of the concatenate filter. + + Ownership of chain is passed in. +*/ +void fz_concat_push_drop(fz_context *ctx, fz_stream *concat, fz_stream *chain); + +/** + arc4 filter performs RC4 decoding of data read from the chained + filter using the supplied key. +*/ fz_stream *fz_open_arc4(fz_context *ctx, fz_stream *chain, unsigned char *key, unsigned keylen); + +/** + aesd filter performs AES decoding of data read from the chained + filter using the supplied key. +*/ fz_stream *fz_open_aesd(fz_context *ctx, fz_stream *chain, unsigned char *key, unsigned keylen); + +/** + a85d filter performs ASCII 85 Decoding of data read + from the chained filter. +*/ fz_stream *fz_open_a85d(fz_context *ctx, fz_stream *chain); + +/** + ahxd filter performs ASCII Hex decoding of data read + from the chained filter. +*/ fz_stream *fz_open_ahxd(fz_context *ctx, fz_stream *chain); + +/** + rld filter performs Run Length Decoding of data read + from the chained filter. +*/ fz_stream *fz_open_rld(fz_context *ctx, fz_stream *chain); -fz_stream *fz_open_dctd(fz_context *ctx, fz_stream *chain, int color_transform, int l2factor, fz_stream *jpegtables); + +/** + dctd filter performs DCT (JPEG) decoding of data read + from the chained filter. + + color_transform implements the PDF color_transform option + use -1 for default behavior + use 0 to disable YUV-RGB / YCCK-CMYK transforms + use 1 to enable YUV-RGB / YCCK-CMYK transforms + + invert_cmyk implements the necessary inversion for Photoshop CMYK images + use 0 if embedded in PDF + use 1 if not embedded in PDF + + For subsampling on decode, set l2factor to the log2 of the + reduction required (therefore 0 = full size decode). + + jpegtables is an optional stream from which the JPEG tables + can be read. Use NULL if not required. +*/ +fz_stream *fz_open_dctd(fz_context *ctx, fz_stream *chain, int color_transform, int invert_cmyk, int l2factor, fz_stream *jpegtables); + +/** + faxd filter performs FAX decoding of data read from + the chained filter. + + k: see fax specification (fax default is 0). + + end_of_line: whether we expect end of line markers (fax default + is 0). + + encoded_byte_align: whether we align to bytes after each line + (fax default is 0). + + columns: how many columns in the image (fax default is 1728). + + rows: 0 for unspecified or the number of rows of data to expect. + + end_of_block: whether we expect end of block markers (fax + default is 1). + + black_is_1: determines the polarity of the image (fax default is + 0). +*/ fz_stream *fz_open_faxd(fz_context *ctx, fz_stream *chain, int k, int end_of_line, int encoded_byte_align, int columns, int rows, int end_of_block, int black_is_1); -fz_stream *fz_open_flated(fz_context *ctx, fz_stream *chain, int window_bits); -fz_stream *fz_open_lzwd(fz_context *ctx, fz_stream *chain, int early_change, int min_bits, int reverse_bits, int old_tiff); -fz_stream *fz_open_predict(fz_context *ctx, fz_stream *chain, int predictor, int columns, int colors, int bpc); -fz_stream *fz_open_jbig2d(fz_context *ctx, fz_stream *chain, fz_jbig2_globals *globals); +/** + flated filter performs LZ77 decoding (inflating) of data read + from the chained filter. + + window_bits: How large a decompression window to use. Typically + 15. A negative number, -n, means to use n bits, but to expect + raw data with no header. +*/ +fz_stream *fz_open_flated(fz_context *ctx, fz_stream *chain, int window_bits); + +/** + libarchived filter performs generic compressed decoding of data + in any format understood by libarchive from the chained filter. + + This will throw an exception if libarchive is not built in, or + if the compression format is not recognised. +*/ +fz_stream *fz_open_libarchived(fz_context *ctx, fz_stream *chain); + +/** + lzwd filter performs LZW decoding of data read from the chained + filter. + + early_change: (Default 1) specifies whether to change codes 1 + bit early. + + min_bits: (Default 9) specifies the minimum number of bits to + use. + + reverse_bits: (Default 0) allows for compatibility with gif and + old style tiffs (1). + + old_tiff: (Default 0) allows for different handling of the clear + code, as found in old style tiffs. +*/ +fz_stream *fz_open_lzwd(fz_context *ctx, fz_stream *chain, int early_change, int min_bits, int reverse_bits, int old_tiff); + +/** + predict filter performs pixel prediction on data read from + the chained filter. + + predictor: 1 = copy, 2 = tiff, other = inline PNG predictor + + columns: width of image in pixels + + colors: number of components. + + bpc: bits per component (typically 8) +*/ +fz_stream *fz_open_predict(fz_context *ctx, fz_stream *chain, int predictor, int columns, int colors, int bpc); + +/** + Open a filter that performs jbig2 decompression on the chained + stream, using the optional globals record. +*/ +fz_stream *fz_open_jbig2d(fz_context *ctx, fz_stream *chain, fz_jbig2_globals *globals, int embedded); + +/** + Create a jbig2 globals record from a buffer. + + Immutable once created. +*/ fz_jbig2_globals *fz_load_jbig2_globals(fz_context *ctx, fz_buffer *buf); + +/** + Increment the reference count for a jbig2 globals record. + + Never throws an exception. +*/ +fz_jbig2_globals *fz_keep_jbig2_globals(fz_context *ctx, fz_jbig2_globals *globals); + +/** + Decrement the reference count for a jbig2 globals record. + When the reference count hits zero, the record is freed. + + Never throws an exception. +*/ +void fz_drop_jbig2_globals(fz_context *ctx, fz_jbig2_globals *globals); + +/** + Special jbig2 globals drop function for use in implementing + store support. +*/ void fz_drop_jbig2_globals_imp(fz_context *ctx, fz_storable *globals); +/** + Return buffer containing jbig2 globals data stream. +*/ +fz_buffer * fz_jbig2_globals_data(fz_context *ctx, fz_jbig2_globals *globals); + /* Extra filters for tiff */ + +/** + SGI Log 16bit (greyscale) decode from the chained filter. + Decodes lines of w pixels to 8bpp greyscale. +*/ fz_stream *fz_open_sgilog16(fz_context *ctx, fz_stream *chain, int w); + +/** + SGI Log 24bit (LUV) decode from the chained filter. + Decodes lines of w pixels to 8bpc rgb. +*/ fz_stream *fz_open_sgilog24(fz_context *ctx, fz_stream *chain, int w); + +/** + SGI Log 32bit (LUV) decode from the chained filter. + Decodes lines of w pixels to 8bpc rgb. +*/ fz_stream *fz_open_sgilog32(fz_context *ctx, fz_stream *chain, int w); + +/** + 4bit greyscale Thunderscan decoding from the chained filter. + Decodes lines of w pixels to 8bpp greyscale. +*/ fz_stream *fz_open_thunder(fz_context *ctx, fz_stream *chain, int w); #endif diff --git a/include/mupdf/fitz/font.h b/include/mupdf/fitz/font.h index 654e814..bcfe2d5 100644 --- a/include/mupdf/fitz/font.h +++ b/include/mupdf/fitz/font.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_FONT_H #define MUPDF_FITZ_FONT_H @@ -5,23 +27,92 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/buffer.h" +#include "mupdf/fitz/color.h" /* forward declaration for circular dependency */ -struct fz_device_s; +struct fz_device; -/* +/* Various font encoding tables and lookup functions */ + +FZ_DATA extern const char *fz_glyph_name_from_adobe_standard[256]; +FZ_DATA extern const char *fz_glyph_name_from_iso8859_7[256]; +FZ_DATA extern const char *fz_glyph_name_from_koi8u[256]; +FZ_DATA extern const char *fz_glyph_name_from_mac_expert[256]; +FZ_DATA extern const char *fz_glyph_name_from_mac_roman[256]; +FZ_DATA extern const char *fz_glyph_name_from_win_ansi[256]; +FZ_DATA extern const char *fz_glyph_name_from_windows_1252[256]; + +FZ_DATA extern const unsigned short fz_unicode_from_iso8859_1[256]; +FZ_DATA extern const unsigned short fz_unicode_from_iso8859_7[256]; +FZ_DATA extern const unsigned short fz_unicode_from_koi8u[256]; +FZ_DATA extern const unsigned short fz_unicode_from_pdf_doc_encoding[256]; +FZ_DATA extern const unsigned short fz_unicode_from_windows_1250[256]; +FZ_DATA extern const unsigned short fz_unicode_from_windows_1251[256]; +FZ_DATA extern const unsigned short fz_unicode_from_windows_1252[256]; + +int fz_iso8859_1_from_unicode(int u); +int fz_iso8859_7_from_unicode(int u); +int fz_koi8u_from_unicode(int u); +int fz_windows_1250_from_unicode(int u); +int fz_windows_1251_from_unicode(int u); +int fz_windows_1252_from_unicode(int u); + +int fz_unicode_from_glyph_name(const char *name); +int fz_unicode_from_glyph_name_strict(const char *name); +const char **fz_duplicate_glyph_names_from_unicode(int unicode); +const char *fz_glyph_name_from_unicode_sc(int unicode); + +/** + * A text decoder (to read arbitrary encodings and convert to unicode). + */ +typedef struct fz_text_decoder fz_text_decoder; + +struct fz_text_decoder { + // get maximum size estimate of converted text (fast) + int (*decode_bound)(fz_text_decoder *dec, unsigned char *input, int n); + + // get exact size of converted text (slow) + int (*decode_size)(fz_text_decoder *dec, unsigned char *input, int n); + + // convert text into output buffer + void (*decode)(fz_text_decoder *dec, char *output, unsigned char *input, int n); + + // for internal use only; do not touch! + void *table1; + void *table2; +}; + +/* Initialize a text decoder using an IANA encoding name. + * See source/fitz/text-decoder.c for the exact list of supported encodings. + * Will throw an exception if the requested encoding is not available. + * + * The following is a subset of the supported encodings (see source/fitz/text-decoder.c for the full list): + * iso-8859-1 + * iso-8859-7 + * koi8-r + * euc-jp + * shift_jis + * euc-kr + * euc-cn + * gb18030 + * euc-tw + * big5 + */ +void fz_init_text_decoder(fz_context *ctx, fz_text_decoder *dec, const char *encoding); + +/** An abstract font handle. */ -typedef struct fz_font_s fz_font; +typedef struct fz_font fz_font; -/* - * Fonts come in two variants: - * Regular fonts are handled by FreeType. - * Type 3 fonts have callbacks to the interpreter. - */ +/** + Fonts come in two variants: + Regular fonts are handled by FreeType. + Type 3 fonts have callbacks to the interpreter. +*/ -/* - fz_font_ft_face: Retrieve the FT_Face handle +/** + Retrieve the FT_Face handle for the font. font: The font to query @@ -32,8 +123,8 @@ typedef struct fz_font_s fz_font; */ void *fz_font_ft_face(fz_context *ctx, fz_font *font); -/* - fz_font_t3_procs: Retrieve the Type3 procs +/** + Retrieve the Type3 procs for a font. font: The font to query @@ -43,22 +134,11 @@ void *fz_font_ft_face(fz_context *ctx, fz_font *font); */ fz_buffer **fz_font_t3_procs(fz_context *ctx, fz_font *font); -/* - ft_error_string: map an FT error number to a - static string. - - err: The error number to lookup. - - Returns a pointer to a static textual representation - of a freetype error. -*/ -const char *ft_error_string(int err); - /* common CJK font collections */ -enum { FZ_ADOBE_CNS_1, FZ_ADOBE_GB_1, FZ_ADOBE_JAPAN_1, FZ_ADOBE_KOREA_1 }; +enum { FZ_ADOBE_CNS, FZ_ADOBE_GB, FZ_ADOBE_JAPAN, FZ_ADOBE_KOREA }; -/* - fz_font_flags_t: Every fz_font carries a set of flags +/** + Every fz_font carries a set of flags within it, in a fz_font_flags_t structure. */ typedef struct @@ -74,10 +154,16 @@ typedef struct unsigned int fake_italic : 1; /* synthesize italic */ unsigned int has_opentype : 1; /* has opentype shaping tables */ unsigned int invalid_bbox : 1; + + unsigned int cjk : 1; + unsigned int cjk_lang : 2; /* CNS, GB, JAPAN, or KOREA */ + + unsigned int embed : 1; + unsigned int never_embed : 1; } fz_font_flags_t; -/* - fz_font_flags: Retrieve a pointer to the font flags +/** + Retrieve a pointer to the font flags for a given font. These can then be updated as required. font: The font to query @@ -87,8 +173,8 @@ typedef struct */ fz_font_flags_t *fz_font_flags(fz_font *font); -/* - fz_shaper_data_t: In order to shape a given font, we need to +/** + In order to shape a given font, we need to declare it to a shaper library (harfbuzz, by default, but others are possible). To avoid redeclaring it every time we need to shape, we hold a shaper handle and the destructor for it within @@ -102,8 +188,8 @@ typedef struct void (*destroy)(fz_context *ctx, void *); /* Destructor for shape_handle */ } fz_shaper_data_t; -/* - fz_shaper_data_t: Retrieve a pointer to the shaper data +/** + Retrieve a pointer to the shaper data structure for the given font. font: The font to query. @@ -113,8 +199,8 @@ typedef struct */ fz_shaper_data_t *fz_font_shaper_data(fz_context *ctx, fz_font *font); -/* - fz_font_name: Retrieve a pointer to the name of the font. +/** + Retrieve a pointer to the name of the font. font: The font to query. @@ -123,74 +209,83 @@ fz_shaper_data_t *fz_font_shaper_data(fz_context *ctx, fz_font *font); */ const char *fz_font_name(fz_context *ctx, fz_font *font); -/* - fz_font_is_bold: Returns true if the font is bold. +/** + Query whether the font flags say that this font is bold. */ int fz_font_is_bold(fz_context *ctx, fz_font *font); -/* - fz_font_is_italic: Returns true if the font is italic. +/** + Query whether the font flags say that this font is italic. */ int fz_font_is_italic(fz_context *ctx, fz_font *font); -/* - fz_font_is_serif: Returns true if the font is serif. +/** + Query whether the font flags say that this font is serif. */ int fz_font_is_serif(fz_context *ctx, fz_font *font); -/* - fz_font_is_monospaced: Returns true if the font is monospaced. +/** + Query whether the font flags say that this font is monospaced. */ int fz_font_is_monospaced(fz_context *ctx, fz_font *font); -/* - fz_font_bbox: Retrieve a pointer to the font bbox. +/** + Retrieve the font bbox. font: The font to query. - Returns a pointer to the font bbox (or NULL if the - font is NULL). + Returns the font bbox by value; it is valid only if + fz_font_flags(font)->invalid_bbox is zero. */ -fz_rect *fz_font_bbox(fz_context *ctx, fz_font *font); +fz_rect fz_font_bbox(fz_context *ctx, fz_font *font); -/* - fz_load_system_font_fn: Type for user supplied system font loading hook. +/** + Type for user supplied system font loading hook. name: The name of the font to load. + bold: 1 if a bold font desired, 0 otherwise. + italic: 1 if an italic font desired, 0 otherwise. - needs_exact_metrics: 1 if an exact metric match is required for the font requested. + needs_exact_metrics: 1 if an exact metric match is required for + the font requested. Returns a new font handle, or NULL if no font found (or on error). */ typedef fz_font *(fz_load_system_font_fn)(fz_context *ctx, const char *name, int bold, int italic, int needs_exact_metrics); -/* - fz_load_system_cjk_font_fn: Type for user supplied cjk font loading hook. +/** + Type for user supplied cjk font loading hook. name: The name of the font to load. - ros: The registry from which to load the font (e.g. FZ_ADOBE_KOREA_1) + + ordering: The ordering for which to load the font (e.g. + FZ_ADOBE_KOREA) + serif: 1 if a serif font is desired, 0 otherwise. Returns a new font handle, or NULL if no font found (or on error). */ -typedef fz_font *(fz_load_system_cjk_font_fn)(fz_context *ctx, const char *name, int ros, int serif); +typedef fz_font *(fz_load_system_cjk_font_fn)(fz_context *ctx, const char *name, int ordering, int serif); -/* - fz_load_system_fallback_font_fn: Type for user supplied fallback font loading hook. +/** + Type for user supplied fallback font loading hook. name: The name of the font to load. + script: UCDN script enum. + language: FZ_LANG enum. + serif, bold, italic: boolean style flags. Returns a new font handle, or NULL if no font found (or on error). */ typedef fz_font *(fz_load_system_fallback_font_fn)(fz_context *ctx, int script, int language, int serif, int bold, int italic); -/* - fz_install_load_system_font_fn: Install functions to allow - MuPDF to request fonts from the system. +/** + Install functions to allow MuPDF to request fonts from the + system. Only one set of hooks can be in use at a time. */ @@ -199,10 +294,8 @@ void fz_install_load_system_font_funcs(fz_context *ctx, fz_load_system_cjk_font_fn *f_cjk, fz_load_system_fallback_font_fn *f_fallback); -/* fz_load_*_font returns NULL if no font could be loaded (also on error) */ -/* - fz_load_system_font: Attempt to load a given font from the - system. +/** + Attempt to load a given font from the system. name: The name of the desired font. @@ -218,23 +311,23 @@ void fz_install_load_system_font_funcs(fz_context *ctx, */ fz_font *fz_load_system_font(fz_context *ctx, const char *name, int bold, int italic, int needs_exact_metrics); -/* - fz_load_system_cjk_font: Attempt to load a given font from +/** + Attempt to load a given font from the system. name: The name of the desired font. - ros: The registry to load the font from (e.g. FZ_ADOBE_KOREA_1) + ordering: The ordering to load the font from (e.g. FZ_ADOBE_KOREA) serif: 1 if serif desired, 0 otherwise. Returns a new font handle, or NULL if no matching font was found (or on error). */ -fz_font *fz_load_system_cjk_font(fz_context *ctx, const char *name, int ros, int serif); +fz_font *fz_load_system_cjk_font(fz_context *ctx, const char *name, int ordering, int serif); -/* - fz_lookup_builtin_font: Search the builtin fonts for a match. +/** + Search the builtin fonts for a match. Whether a given font is present or not will depend on the configuration in which MuPDF is built. @@ -251,8 +344,8 @@ fz_font *fz_load_system_cjk_font(fz_context *ctx, const char *name, int ros, int */ const unsigned char *fz_lookup_builtin_font(fz_context *ctx, const char *name, int bold, int italic, int *len); -/* - fz_lookup_base14_font: Search the builtin base14 fonts for a match. +/** + Search the builtin base14 fonts for a match. Whether a given font is present or not will depend on the configuration in which MuPDF is built. @@ -265,42 +358,46 @@ const unsigned char *fz_lookup_builtin_font(fz_context *ctx, const char *name, i */ const unsigned char *fz_lookup_base14_font(fz_context *ctx, const char *name, int *len); -/* ToDo: Share fz_lookup_builtin_font and fz_lookup_icc? Check with Tor */ -/* - fz_lookup_icc: Search for icc profile. - - name: The name of the profile desired (gray-icc, rgb-icc, cmyk-icc or lab-icc). - - len: Pointer to a place to receive the length of the discovered. - - Returns a pointer to the icc file data, or NULL if not present. -*/ -const unsigned char *fz_lookup_icc(fz_context *ctx, const char *name, size_t *len); - -/* - fz_lookup_cjk_font: Search the builtin cjk fonts for a match. +/** + Search the builtin cjk fonts for a match. Whether a font is present or not will depend on the configuration in which MuPDF is built. - registry: The desired registry to lookup in (e.g. - FZ_ADOBE_KOREA_1). - - serif: 1 if serif desired, 0 otherwise. - - wmode: 1 for vertical mode, 0 for horizontal. + ordering: The desired ordering of the font (e.g. FZ_ADOBE_KOREA). len: Pointer to a place to receive the length of the discovered font buffer. - index: Pointer to a place to store the index of the discovered - font. + Returns a pointer to the font file data, or NULL if not present. +*/ +const unsigned char *fz_lookup_cjk_font(fz_context *ctx, int ordering, int *len, int *index); + +/** + Search the builtin cjk fonts for a match for a given language. + Whether a font is present or not will depend on the + configuration in which MuPDF is built. + + lang: Pointer to a (case sensitive) language string (e.g. + "ja", "ko", "zh-Hant" etc). + + len: Pointer to a place to receive the length of the discovered + font buffer. + + subfont: Pointer to a place to store the subfont index of the + discovered font. Returns a pointer to the font file data, or NULL if not present. */ -const unsigned char *fz_lookup_cjk_font(fz_context *ctx, int registry, int serif, int wmode, int *len, int *index); +const unsigned char *fz_lookup_cjk_font_by_language(fz_context *ctx, const char *lang, int *len, int *subfont); -/* - fz_lookup_noto_font: Search the builtin noto fonts for a match. +/** + Return the matching FZ_ADOBE_* ordering + for the given language tag, such as "zh-Hant", "zh-Hans", "ja", or "ko". +*/ +int fz_lookup_cjk_ordering_by_language(const char *name); + +/** + Search the builtin noto fonts for a match. Whether a font is present or not will depend on the configuration in which MuPDF is built. @@ -308,41 +405,27 @@ const unsigned char *fz_lookup_cjk_font(fz_context *ctx, int registry, int serif lang: The language desired (e.g. FZ_LANG_ja). - serif: 1 if serif desired, 0 otherwise. - len: Pointer to a place to receive the length of the discovered font buffer. Returns a pointer to the font file data, or NULL if not present. */ -const unsigned char *fz_lookup_noto_font(fz_context *ctx, int script, int lang, int serif, int *len); +const unsigned char *fz_lookup_noto_font(fz_context *ctx, int script, int lang, int *len, int *subfont); -/* - fz_lookup_noto_symbol_font: Search the builtin noto fonts - for a symbol font. Whether a font is present or not will - depend on the configuration in which MuPDF is built. - - len: Pointer to a place to receive the length of the discovered - font buffer. - - Returns a pointer to the font file data, or NULL if not present. -*/ -const unsigned char *fz_lookup_noto_symbol_font(fz_context *ctx, int *len); - -/* - fz_lookup_noto_emoji_font: Search the builtin noto fonts - for an emoji font. Whether a font is present or not will - depend on the configuration in which MuPDF is built. - - len: Pointer to a place to receive the length of the discovered - font buffer. - - Returns a pointer to the font file data, or NULL if not present. +/** + Search the builtin noto fonts specific symbol fonts. + Whether a font is present or not will depend on the + configuration in which MuPDF is built. */ +const unsigned char *fz_lookup_noto_math_font(fz_context *ctx, int *len); +const unsigned char *fz_lookup_noto_music_font(fz_context *ctx, int *len); +const unsigned char *fz_lookup_noto_symbol1_font(fz_context *ctx, int *len); +const unsigned char *fz_lookup_noto_symbol2_font(fz_context *ctx, int *len); const unsigned char *fz_lookup_noto_emoji_font(fz_context *ctx, int *len); +const unsigned char *fz_lookup_noto_boxes_font(fz_context *ctx, int *len); -/* - fz_load_fallback_font: Try to load a fallback font for the +/** + Try to load a fallback font for the given combination of font attributes. Whether a font is present or not will depend on the configuration in which MuPDF is built. @@ -361,26 +444,8 @@ const unsigned char *fz_lookup_noto_emoji_font(fz_context *ctx, int *len); */ fz_font *fz_load_fallback_font(fz_context *ctx, int script, int language, int serif, int bold, int italic); -/* - fz_load_fallback_symbol_font: Try to load a fallback - symbol font. Whether a font is present or not will - depend on the configuration in which MuPDF is built. - - Returns a new font handle, or NULL if not available. -*/ -fz_font *fz_load_fallback_symbol_font(fz_context *ctx); - -/* - fz_load_fallback_emoji_font: Try to load a fallback - emoji font. Whether a font is present or not will - depend on the configuration in which MuPDF is built. - - Returns a new font handle, or NULL if not available. -*/ -fz_font *fz_load_fallback_emoji_font(fz_context *ctx); - -/* - fz_new_type3_font: Create a new (empty) type3 font. +/** + Create a new (empty) type3 font. name: Name of font (or NULL). @@ -389,11 +454,12 @@ fz_font *fz_load_fallback_emoji_font(fz_context *ctx); Returns a new font handle, or throws exception on allocation failure. */ -fz_font *fz_new_type3_font(fz_context *ctx, const char *name, const fz_matrix *matrix); +fz_font *fz_new_type3_font(fz_context *ctx, const char *name, fz_matrix matrix); -/* - fz_new_font_from_memory: Create a new font from a font - file in memory. +/** + Create a new font from a font file in memory. + + Fonts created in this way, will be eligible for embedding by default. name: Name of font (leave NULL to use name from font). @@ -409,9 +475,10 @@ fz_font *fz_new_type3_font(fz_context *ctx, const char *name, const fz_matrix *m */ fz_font *fz_new_font_from_memory(fz_context *ctx, const char *name, const unsigned char *data, int len, int index, int use_glyph_bbox); -/* - fz_new_font_from_buffer: Create a new font from a font - file in a fz_buffer. +/** + Create a new font from a font file in a fz_buffer. + + Fonts created in this way, will be eligible for embedding by default. name: Name of font (leave NULL to use name from font). @@ -425,9 +492,10 @@ fz_font *fz_new_font_from_memory(fz_context *ctx, const char *name, const unsign */ fz_font *fz_new_font_from_buffer(fz_context *ctx, const char *name, fz_buffer *buffer, int index, int use_glyph_bbox); -/* - fz_new_font_from_file: Create a new font from a font - file. +/** + Create a new font from a font file. + + Fonts created in this way, will be eligible for embedding by default. name: Name of font (leave NULL to use name from font). @@ -441,12 +509,19 @@ fz_font *fz_new_font_from_buffer(fz_context *ctx, const char *name, fz_buffer *b */ fz_font *fz_new_font_from_file(fz_context *ctx, const char *name, const char *path, int index, int use_glyph_bbox); -/* Create a new font from one of the built-in fonts. */ +/** + Create a new font from one of the built-in fonts. +*/ fz_font *fz_new_base14_font(fz_context *ctx, const char *name); -fz_font *fz_new_cjk_font(fz_context *ctx, int registry, int serif, int wmode); +fz_font *fz_new_cjk_font(fz_context *ctx, int ordering); fz_font *fz_new_builtin_font(fz_context *ctx, const char *name, int is_bold, int is_italic); -/* +/** + Control whether a given font should be embedded or not when writing. +*/ +void fz_set_font_embedding(fz_context *ctx, fz_font *font, int embed); + +/** Add a reference to an existing fz_font. font: The font to add a reference to. @@ -455,7 +530,7 @@ fz_font *fz_new_builtin_font(fz_context *ctx, const char *name, int is_bold, int */ fz_font *fz_keep_font(fz_context *ctx, fz_font *font); -/* +/** Drop a reference to a fz_font, destroying the font when the last reference is dropped. @@ -463,8 +538,8 @@ fz_font *fz_keep_font(fz_context *ctx, fz_font *font); */ void fz_drop_font(fz_context *ctx, fz_font *font); -/* - fz_set_font_bbox: Set the font bbox. +/** + Set the font bbox. font: The font to set the bbox for. @@ -472,8 +547,8 @@ void fz_drop_font(fz_context *ctx, fz_font *font); */ void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax); -/* - fz_bound_glyph: Return a bbox for a given glyph in a font. +/** + Return a bbox for a given glyph in a font. font: The font to look for the glyph in. @@ -481,14 +556,13 @@ void fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, fl trm: The matrix to apply to the glyph before bounding. - r: Pointer to a fz_rect to use for storage. - - Returns r, after filling it in with the bounds of the given glyph. + Returns rectangle by value containing the bounds of the given + glyph. */ -fz_rect *fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, fz_rect *r); +fz_rect fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm); -/* - fz_glyph_cacheable: Determine if a given glyph in a font +/** + Determine if a given glyph in a font is cacheable. Certain glyphs in a type 3 font cannot safely be cached, as their appearance depends on the enclosing graphic state. @@ -501,8 +575,8 @@ fz_rect *fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix */ int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid); -/* - fz_run_t3_glyph: Run a glyph from a Type3 font to +/** + Run a glyph from a Type3 font to a given device. font: The font to find the glyph in. @@ -513,28 +587,10 @@ int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid); dev: The device to render onto. */ -void fz_run_t3_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *trm, struct fz_device_s *dev); +void fz_run_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, struct fz_device *dev); -/* - fz_decouple_type3_font: Internal function to remove the - references to a document held by a Type3 font. This is - called during document destruction to ensure that Type3 - fonts clean up properly. - - Without this call being made, Type3 fonts can be left - holding pdf_obj references for the sake of interpretation - operations that will never come. These references - cannot be freed after the document, hence this function - forces them to be freed earlier in the process. - - font: The font to decouple. - - t3doc: The document to which the font may refer. -*/ -void fz_decouple_type3_font(fz_context *ctx, fz_font *font, void *t3doc); - -/* - fz_advance_glyph: Return the advance for a given glyph. +/** + Return the advance for a given glyph. font: The font to look for the glyph in. @@ -546,8 +602,8 @@ void fz_decouple_type3_font(fz_context *ctx, fz_font *font, void *t3doc); */ float fz_advance_glyph(fz_context *ctx, fz_font *font, int glyph, int wmode); -/* - fz_encode_character: Find the glyph id for a given unicode +/** + Find the glyph id for a given unicode character within a font. font: The font to look for the unicode character in. @@ -559,8 +615,31 @@ float fz_advance_glyph(fz_context *ctx, fz_font *font, int glyph, int wmode); */ int fz_encode_character(fz_context *ctx, fz_font *font, int unicode); -/* - fz_encode_character_with_fallback: Find the glyph id for +/** + Encode character, preferring small-caps variant if available. + + font: The font to look for the unicode character in. + + unicode: The unicode character to encode. + + Returns the glyph id for the given unicode value, or 0 if + unknown. +*/ +int fz_encode_character_sc(fz_context *ctx, fz_font *font, int unicode); + +/** + Encode character. + + Either by direct lookup of glyphname within a font, or, failing + that, by mapping glyphname to unicode and thence to the glyph + index within the given font. + + Returns zero for type3 fonts. +*/ +int fz_encode_character_by_glyph_name(fz_context *ctx, fz_font *font, const char *glyphname); + +/** + Find the glyph id for a given unicode character within a font, falling back to an alternative if not found. @@ -586,8 +665,8 @@ int fz_encode_character(fz_context *ctx, fz_font *font, int unicode); */ int fz_encode_character_with_fallback(fz_context *ctx, fz_font *font, int unicode, int script, int language, fz_font **out_font); -/* - fz_get_glyph_name: Find the name of a glyph +/** + Find the name of a glyph font: The font to look for the glyph in. @@ -604,28 +683,133 @@ int fz_encode_character_with_fallback(fz_context *ctx, fz_font *font, int unicod */ void fz_get_glyph_name(fz_context *ctx, fz_font *font, int glyph, char *buf, int size); -/* - Get font ascender and descender values. +/** + Retrieve font ascender in ems. */ float fz_font_ascender(fz_context *ctx, fz_font *font); + +/** + Retrieve font descender in ems. +*/ float fz_font_descender(fz_context *ctx, fz_font *font); -/* +/** + Retrieve the MD5 digest for the font's data. +*/ +void fz_font_digest(fz_context *ctx, fz_font *font, unsigned char digest[16]); + +/* Implementation details: subject to change. */ + +void fz_decouple_type3_font(fz_context *ctx, fz_font *font, void *t3doc); + +/** + map an FT error number to a + static string. + + err: The error number to lookup. + + Returns a pointer to a static textual representation + of a freetype error. +*/ +const char *ft_error_string(int err); +int ft_char_index(void *face, int cid); +int ft_name_index(void *face, const char *name); + +/** Internal functions for our Harfbuzz integration to work around the lack of thread safety. */ -/* - fz_hb_lock: Lock against Harfbuzz being called +/** + Lock against Harfbuzz being called simultaneously in several threads. This reuses FZ_LOCK_FREETYPE. */ void fz_hb_lock(fz_context *ctx); -/* - fz_hb_unlock: Unlock after a Harfbuzz call. This reuses +/** + Unlock after a Harfbuzz call. This reuses FZ_LOCK_FREETYPE. */ void fz_hb_unlock(fz_context *ctx); +struct fz_font +{ + int refs; + char name[32]; + fz_buffer *buffer; + + fz_font_flags_t flags; + + void *ft_face; /* has an FT_Face if used */ + fz_shaper_data_t shaper_data; + + fz_matrix t3matrix; + void *t3resources; + fz_buffer **t3procs; /* has 256 entries if used */ + struct fz_display_list **t3lists; /* has 256 entries if used */ + float *t3widths; /* has 256 entries if used */ + unsigned short *t3flags; /* has 256 entries if used */ + void *t3doc; /* a pdf_document for the callback */ + void (*t3run)(fz_context *ctx, void *doc, void *resources, fz_buffer *contents, struct fz_device *dev, fz_matrix ctm, void *gstate, fz_default_colorspaces *default_cs); + void (*t3freeres)(fz_context *ctx, void *doc, void *resources); + + fz_rect bbox; /* font bbox is used only for t3 fonts */ + + int glyph_count; + + /* per glyph bounding box cache. */ + fz_rect **bbox_table; + int use_glyph_bbox; + + /* substitute metrics */ + int width_count; + short width_default; /* in 1000 units */ + short *width_table; /* in 1000 units */ + + /* cached glyph metrics */ + float **advance_cache; + + /* cached encoding lookup */ + uint16_t *encoding_cache[256]; + + /* cached md5sum for caching */ + int has_digest; + unsigned char digest[16]; + + /* Which font to use in a collection. */ + int subfont; +}; + +void fz_ft_lock(fz_context *ctx); + +void fz_ft_unlock(fz_context *ctx); + +/* Internal function. Must be called with FT_ALLOC_LOCK + * held. Returns 1 if this thread (context!) already holds + * the freeetype lock. */ +int fz_ft_lock_held(fz_context *ctx); + +/* Internal function: Extract a ttf from the ttc that underlies + * a given fz_font. Caller takes ownership of the returned + * buffer. + */ +fz_buffer *fz_extract_ttf_from_ttc(fz_context *ctx, fz_font *font); + +/* Internal function: Given a ttf in a buffer, create a subset + * ttf in a new buffer that only provides the required gids. + * Caller takes ownership of the returned buffer. + * + * EXPERIMENTAL AND VERY SUBJECT TO CHANGE. + */ +fz_buffer *fz_subset_ttf_for_gids(fz_context *ctx, fz_buffer *orig, int *gids, int num_gids, int symbolic, int cidfont); + +/* Internal function: Given a cff in a buffer, create a subset + * cff in a new buffer that only provides the required gids. + * Caller takes ownership of the returned buffer. + * + * EXPERIMENTAL AND VERY SUBJECT TO CHANGE. + */ +fz_buffer *fz_subset_cff_for_gids(fz_context *ctx, fz_buffer *orig, int *gids, int num_gids, int symbolic, int cidfont); + #endif diff --git a/include/mupdf/fitz/geometry.h b/include/mupdf/fitz/geometry.h index 180ae8d..57ca0e8 100644 --- a/include/mupdf/fitz/geometry.h +++ b/include/mupdf/fitz/geometry.h @@ -1,9 +1,33 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_MATH_H #define MUPDF_FITZ_MATH_H #include "mupdf/fitz/system.h" -/* +#include + +/** Multiply scaled two integers in the 0..255 range */ static inline int fz_mul255(int a, int b) @@ -14,45 +38,57 @@ static inline int fz_mul255(int a, int b) return x >> 8; } -/* +/** + Undo alpha premultiplication. +*/ +static inline int fz_div255(int c, int a) +{ + return a ? c * (255 * 256 / a) >> 8 : 0; +} + +/** Expand a value A from the 0...255 range to the 0..256 range */ #define FZ_EXPAND(A) ((A)+((A)>>7)) -/* +/** Combine values A (in any range) and B (in the 0..256 range), to give a single value in the same range as A was. */ #define FZ_COMBINE(A,B) (((A)*(B))>>8) -/* +/** Combine values A and C (in the same (any) range) and B and D (in the 0..256 range), to give a single value in the same range as A and C were. */ #define FZ_COMBINE2(A,B,C,D) (((A) * (B) + (C) * (D))>>8) -/* +/** Blend SRC and DST (in the same range) together according to AMOUNT (in the 0...256 range). */ #define FZ_BLEND(SRC, DST, AMOUNT) ((((SRC)-(DST))*(AMOUNT) + ((DST)<<8))>>8) -/* +/** Range checking atof */ float fz_atof(const char *s); -/* +/** atoi that copes with NULL */ int fz_atoi(const char *s); + +/** + 64bit atoi that copes with NULL +*/ int64_t fz_atoi64(const char *s); -/* +/** Some standard math functions, done as static inlines for speed. - People with compilers that do not adequately implement inlines may - like to reimplement these using macros. + People with compilers that do not adequately implement inline + may like to reimplement these using macros. */ static inline float fz_abs(float f) { @@ -79,6 +115,11 @@ static inline size_t fz_minz(size_t a, size_t b) return (a < b ? a : b); } +static inline int64_t fz_mini64(int64_t a, int64_t b) +{ + return (a < b ? a : b); +} + static inline float fz_max(float a, float b) { return (a > b ? a : b); @@ -89,41 +130,50 @@ static inline int fz_maxi(int a, int b) return (a > b ? a : b); } +static inline size_t fz_maxz(size_t a, size_t b) +{ + return (a > b ? a : b); +} + static inline int64_t fz_maxi64(int64_t a, int64_t b) { return (a > b ? a : b); } -static inline float fz_clamp(float f, float min, float max) +static inline float fz_clamp(float x, float min, float max) { - return (f > min ? (f < max ? f : max) : min); + return x < min ? min : x > max ? max : x; } -static inline int fz_clampi(int i, int min, int max) +static inline int fz_clampi(int x, int min, int max) { - return (i > min ? (i < max ? i : max) : min); + return x < min ? min : x > max ? max : x; } -static inline double fz_clampd(double d, double min, double max) +static inline int64_t fz_clamp64(int64_t x, int64_t min, int64_t max) { - return (d > min ? (d < max ? d : max) : min); + return x < min ? min : x > max ? max : x; } -static inline void *fz_clampp(void *p, void *min, void *max) +static inline double fz_clampd(double x, double min, double max) { - return (p > min ? (p < max ? p : max) : min); + return x < min ? min : x > max ? max : x; +} + +static inline void *fz_clampp(void *x, void *min, void *max) +{ + return x < min ? min : x > max ? max : x; } #define DIV_BY_ZERO(a, b, min, max) (((a) < 0) ^ ((b) < 0) ? (min) : (max)) -/* +/** fz_point is a point in a two-dimensional space. */ -typedef struct fz_point_s fz_point; -struct fz_point_s +typedef struct { float x, y; -}; +} fz_point; static inline fz_point fz_make_point(float x, float y) { @@ -131,30 +181,44 @@ static inline fz_point fz_make_point(float x, float y) return p; } -/* +/** fz_rect is a rectangle represented by two diagonally opposite corners at arbitrary coordinates. - Rectangles are always axis-aligned with the X- and Y- axes. - The relationship between the coordinates are that x0 <= x1 and - y0 <= y1 in all cases except for infinite rectangles. The area - of a rectangle is defined as (x1 - x0) * (y1 - y0). If either - x0 > x1 or y0 > y1 is true for a given rectangle then it is - defined to be infinite. + Rectangles are always axis-aligned with the X- and Y- axes. We + wish to distinguish rectangles in 3 categories; infinite, finite, + and invalid. Zero area rectangles are a sub-category of finite + ones. + + For all valid rectangles, x0 <= x1 and y0 <= y1 in all cases. + Infinite rectangles have x0 = y0 = FZ_MIN_INF_RECT, + x1 = y1 = FZ_MAX_INF_RECT. For any non infinite valid rectangle, + the area is defined as (x1 - x0) * (y1 - y0). To check for empty or infinite rectangles use fz_is_empty_rect - and fz_is_infinite_rect. + and fz_is_infinite_rect. To check for valid rectangles use + fz_is_valid_rect. + + We choose this representation, so that we can easily distinguish + the difference between intersecting 2 valid rectangles and + getting an invalid one, as opposed to getting a zero area one + (which nonetheless has valid bounds within the plane). x0, y0: The top left corner. x1, y1: The bottom right corner. + + We choose FZ_{MIN,MAX}_INF_RECT to be the largest 32bit signed + integer values that survive roundtripping to floats. */ -typedef struct fz_rect_s fz_rect; -struct fz_rect_s +#define FZ_MIN_INF_RECT ((int)0x80000000) +#define FZ_MAX_INF_RECT ((int)0x7fffff80) + +typedef struct { float x0, y0; float x1, y1; -}; +} fz_rect; static inline fz_rect fz_make_rect(float x0, float y0, float x1, float y1) { @@ -162,33 +226,16 @@ static inline fz_rect fz_make_rect(float x0, float y0, float x1, float y1) return r; } -/* - fz_rect_min: get the minimum point from a rectangle as a fz_point. -*/ -static inline fz_point *fz_rect_min(fz_rect *f) -{ - return (fz_point *)&f->x0; -} - -/* - fz_rect_max: get the maximum point from a rectangle as a fz_point. -*/ -static inline fz_point *fz_rect_max(fz_rect *f) -{ - return (fz_point *)&f->x1; -} - -/* +/** fz_irect is a rectangle using integers instead of floats. It's used in the draw device and for pixmap dimensions. */ -typedef struct fz_irect_s fz_irect; -struct fz_irect_s +typedef struct { int x0, y0; int x1, y1; -}; +} fz_irect; static inline fz_irect fz_make_irect(int x0, int y0, int x1, int y1) { @@ -196,74 +243,116 @@ static inline fz_irect fz_make_irect(int x0, int y0, int x1, int y1) return r; } -/* +/** A rectangle with sides of length one. The bottom left corner is at (0, 0) and the top right corner is at (1, 1). */ -extern const fz_rect fz_unit_rect; +FZ_DATA extern const fz_rect fz_unit_rect; -/* +/** An empty rectangle with an area equal to zero. - - Both the top left and bottom right corner are at (0, 0). */ -extern const fz_rect fz_empty_rect; -extern const fz_irect fz_empty_irect; +FZ_DATA extern const fz_rect fz_empty_rect; +FZ_DATA extern const fz_irect fz_empty_irect; -/* - An infinite rectangle with negative area. - - The corner (x0, y0) is at (1, 1) while the corner (x1, y1) is - at (-1, -1). +/** + An infinite rectangle. */ -extern const fz_rect fz_infinite_rect; -extern const fz_irect fz_infinite_irect; +FZ_DATA extern const fz_rect fz_infinite_rect; +FZ_DATA extern const fz_irect fz_infinite_irect; -/* - fz_is_empty_rect: Check if rectangle is empty. +/** + Check if rectangle is empty. An empty rectangle is defined as one whose area is zero. + All invalid rectangles are empty. */ -static inline int -fz_is_empty_rect(const fz_rect *r) +static inline int fz_is_empty_rect(fz_rect r) { - return ((r)->x0 == (r)->x1 || (r)->y0 == (r)->y1); + return (r.x0 >= r.x1 || r.y0 >= r.y1); } -static inline int -fz_is_empty_irect(const fz_irect *r) +static inline int fz_is_empty_irect(fz_irect r) { - return ((r)->x0 == (r)->x1 || (r)->y0 == (r)->y1); + return (r.x0 >= r.x1 || r.y0 >= r.y1); } -/* - fz_is_infinite_rect: Check if rectangle is infinite. - - An infinite rectangle is defined as one where either of the - two relationships between corner coordinates are not true. +/** + Check if rectangle is infinite. */ -static inline int -fz_is_infinite_rect(const fz_rect *r) +static inline int fz_is_infinite_rect(fz_rect r) { - return ((r)->x0 > (r)->x1 || (r)->y0 > (r)->y1); + return (r.x0 == FZ_MIN_INF_RECT && r.x1 == FZ_MAX_INF_RECT && + r.y0 == FZ_MIN_INF_RECT && r.y1 == FZ_MAX_INF_RECT); } -/* - fz_is_infinite_irect: Check if an integer rectangle +/** + Check if an integer rectangle is infinite. - - An infinite rectangle is defined as one where either of the - two relationships between corner coordinates are not true. */ -static inline int -fz_is_infinite_irect(const fz_irect *r) +static inline int fz_is_infinite_irect(fz_irect r) { - return ((r)->x0 > (r)->x1 || (r)->y0 > (r)->y1); + return (r.x0 == FZ_MIN_INF_RECT && r.x1 == FZ_MAX_INF_RECT && + r.y0 == FZ_MIN_INF_RECT && r.y1 == FZ_MAX_INF_RECT); } -/* +/** + Check if rectangle is valid. +*/ +static inline int fz_is_valid_rect(fz_rect r) +{ + return (r.x0 <= r.x1 && r.y0 <= r.y1); +} + +/** + Check if an integer rectangle is valid. +*/ +static inline int fz_is_valid_irect(fz_irect r) +{ + return (r.x0 <= r.x1 && r.y0 <= r.y1); +} + +/** + Return the width of an irect. Invalid irects return 0. +*/ +static inline unsigned int +fz_irect_width(fz_irect r) +{ + unsigned int w; + if (r.x0 >= r.x1) + return 0; + /* Check for w overflowing. This should never happen, but + * if it does, it's pretty likely an indication of a severe + * problem. */ + w = (unsigned int)r.x1 - r.x0; + assert((int)w >= 0); + if ((int)w < 0) + return 0; + return (int)w; +} + +/** + Return the height of an irect. Invalid irects return 0. +*/ +static inline int +fz_irect_height(fz_irect r) +{ + unsigned int h; + if (r.y0 >= r.y1) + return 0; + /* Check for h overflowing. This should never happen, but + * if it does, it's pretty likely an indication of a severe + * problem. */ + h = (unsigned int)(r.y1 - r.y0); + assert((int)h >= 0); + if ((int)h < 0) + return 0; + return (int)h; +} + +/** fz_matrix is a row-major 3x3 matrix used for representing transformations of coordinates throughout MuPDF. @@ -276,16 +365,15 @@ fz_is_infinite_irect(const fz_irect *r) | c d 0 | normally represented as [ a b c d e f ]. \ e f 1 / */ -typedef struct fz_matrix_s fz_matrix; -struct fz_matrix_s +typedef struct { float a, b, c, d, e, f; -}; +} fz_matrix; -/* - fz_identity: Identity transform matrix. +/** + Identity transform matrix. */ -extern const fz_matrix fz_identity; +FZ_DATA extern const fz_matrix fz_identity; static inline fz_matrix fz_make_matrix(float a, float b, float c, float d, float e, float f) { @@ -293,24 +381,23 @@ static inline fz_matrix fz_make_matrix(float a, float b, float c, float d, float return m; } -static inline fz_matrix *fz_copy_matrix(fz_matrix *restrict m, const fz_matrix *restrict s) +static inline int fz_is_identity(fz_matrix m) { - *m = *s; - return m; + return m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && m.e == 0 && m.f == 0; } -/* - fz_concat: Multiply two matrices. +/** + Multiply two matrices. The order of the two matrices are important since matrix multiplication is not commutative. Returns result. */ -fz_matrix *fz_concat(fz_matrix *result, const fz_matrix *left, const fz_matrix *right); +fz_matrix fz_concat(fz_matrix left, fz_matrix right); -/* - fz_scale: Create a scaling matrix. +/** + Create a scaling matrix. The returned matrix is of the form [ sx 0 0 sy 0 0 ]. @@ -322,10 +409,10 @@ fz_matrix *fz_concat(fz_matrix *result, const fz_matrix *left, const fz_matrix * Returns m. */ -fz_matrix *fz_scale(fz_matrix *m, float sx, float sy); +fz_matrix fz_scale(float sx, float sy); -/* - fz_pre_scale: Scale a matrix by premultiplication. +/** + Scale a matrix by premultiplication. m: Pointer to the matrix to scale @@ -335,10 +422,10 @@ fz_matrix *fz_scale(fz_matrix *m, float sx, float sy); Returns m (updated). */ -fz_matrix *fz_pre_scale(fz_matrix *m, float sx, float sy); +fz_matrix fz_pre_scale(fz_matrix m, float sx, float sy); -/* - fz_post_scale: Scale a matrix by postmultiplication. +/** + Scale a matrix by postmultiplication. m: Pointer to the matrix to scale @@ -348,10 +435,10 @@ fz_matrix *fz_pre_scale(fz_matrix *m, float sx, float sy); Returns m (updated). */ -fz_matrix *fz_post_scale(fz_matrix *m, float sx, float sy); +fz_matrix fz_post_scale(fz_matrix m, float sx, float sy); -/* - fz_shear: Create a shearing matrix. +/** + Create a shearing matrix. The returned matrix is of the form [ 1 sy sx 1 0 0 ]. @@ -362,10 +449,10 @@ fz_matrix *fz_post_scale(fz_matrix *m, float sx, float sy); Returns m. */ -fz_matrix *fz_shear(fz_matrix *m, float sx, float sy); +fz_matrix fz_shear(float sx, float sy); -/* - fz_pre_shear: Premultiply a matrix with a shearing matrix. +/** + Premultiply a matrix with a shearing matrix. The shearing matrix is of the form [ 1 sy sx 1 0 0 ]. @@ -376,10 +463,10 @@ fz_matrix *fz_shear(fz_matrix *m, float sx, float sy); Returns m (updated). */ -fz_matrix *fz_pre_shear(fz_matrix *m, float sx, float sy); +fz_matrix fz_pre_shear(fz_matrix m, float sx, float sy); -/* - fz_rotate: Create a rotation matrix. +/** + Create a rotation matrix. The returned matrix is of the form [ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ]. @@ -391,10 +478,10 @@ fz_matrix *fz_pre_shear(fz_matrix *m, float sx, float sy); Returns m. */ -fz_matrix *fz_rotate(fz_matrix *m, float degrees); +fz_matrix fz_rotate(float degrees); -/* - fz_pre_rotate: Rotate a transformation by premultiplying. +/** + Rotate a transformation by premultiplying. The premultiplied matrix is of the form [ cos(deg) sin(deg) -sin(deg) cos(deg) 0 0 ]. @@ -406,10 +493,10 @@ fz_matrix *fz_rotate(fz_matrix *m, float degrees); Returns m (updated). */ -fz_matrix *fz_pre_rotate(fz_matrix *m, float degrees); +fz_matrix fz_pre_rotate(fz_matrix m, float degrees); -/* - fz_translate: Create a translation matrix. +/** + Create a translation matrix. The returned matrix is of the form [ 1 0 0 1 tx ty ]. @@ -421,10 +508,10 @@ fz_matrix *fz_pre_rotate(fz_matrix *m, float degrees); Returns m. */ -fz_matrix *fz_translate(fz_matrix *m, float tx, float ty); +fz_matrix fz_translate(float tx, float ty); -/* - fz_pre_translate: Translate a matrix by premultiplication. +/** + Translate a matrix by premultiplication. m: The matrix to translate @@ -434,10 +521,18 @@ fz_matrix *fz_translate(fz_matrix *m, float tx, float ty); Returns m. */ -fz_matrix *fz_pre_translate(fz_matrix *m, float tx, float ty); +fz_matrix fz_pre_translate(fz_matrix m, float tx, float ty); -/* - fz_invert_matrix: Create an inverse matrix. +/** + Create transform matrix to draw page + at a given resolution and rotation. Adjusts the scaling + factors so that the page covers whole number of + pixels and adjust the page origin to be at 0,0. +*/ +fz_matrix fz_transform_page(fz_rect mediabox, float resolution, float rotate); + +/** + Create an inverse matrix. inverse: Place to store inverse matrix. @@ -447,10 +542,10 @@ fz_matrix *fz_pre_translate(fz_matrix *m, float tx, float ty); Returns inverse. */ -fz_matrix *fz_invert_matrix(fz_matrix *inverse, const fz_matrix *matrix); +fz_matrix fz_invert_matrix(fz_matrix matrix); -/* - fz_try_invert_matrix: Attempt to create an inverse matrix. +/** + Attempt to create an inverse matrix. inverse: Place to store inverse matrix. @@ -459,25 +554,25 @@ fz_matrix *fz_invert_matrix(fz_matrix *inverse, const fz_matrix *matrix); Returns 1 if matrix is degenerate (singular), or 0 otherwise. */ - int fz_try_invert_matrix(fz_matrix *inverse, const fz_matrix *matrix); +int fz_try_invert_matrix(fz_matrix *inv, fz_matrix src); -/* - fz_is_rectilinear: Check if a transformation is rectilinear. +/** + Check if a transformation is rectilinear. Rectilinear means that no shearing is present and that any rotations present are a multiple of 90 degrees. Usually this is used to make sure that axis-aligned rectangles before the transformation are still axis-aligned rectangles afterwards. */ -int fz_is_rectilinear(const fz_matrix *m); +int fz_is_rectilinear(fz_matrix m); -/* - fz_matrix_expansion: Calculate average scaling factor of matrix. +/** + Calculate average scaling factor of matrix. */ -float fz_matrix_expansion(const fz_matrix *m); /* sumatrapdf */ +float fz_matrix_expansion(fz_matrix m); -/* - fz_intersect_rect: Compute intersection of two rectangles. +/** + Compute intersection of two rectangles. Given two rectangles, update the first to be the smallest axis-aligned rectangle that covers the area covered by both @@ -487,18 +582,18 @@ float fz_matrix_expansion(const fz_matrix *m); /* sumatrapdf */ Should both rectangles be infinite, then the intersection is also infinite. */ -fz_rect *fz_intersect_rect(fz_rect *restrict a, const fz_rect *restrict b); +fz_rect fz_intersect_rect(fz_rect a, fz_rect b); -/* - fz_intersect_irect: Compute intersection of two bounding boxes. +/** + Compute intersection of two bounding boxes. Similar to fz_intersect_rect but operates on two bounding boxes instead of two rectangles. */ -fz_irect *fz_intersect_irect(fz_irect *restrict a, const fz_irect *restrict b); +fz_irect fz_intersect_irect(fz_irect a, fz_irect b); -/* - fz_union_rect: Compute union of two rectangles. +/** + Compute union of two rectangles. Given two rectangles, update the first to be the smallest axis-aligned rectangle that encompasses both given rectangles. @@ -507,28 +602,21 @@ fz_irect *fz_intersect_irect(fz_irect *restrict a, const fz_irect *restrict b); non-empty rectangle. Should both rectangles be empty, then the union is also empty. */ -fz_rect *fz_union_rect(fz_rect *restrict a, const fz_rect *restrict b); +fz_rect fz_union_rect(fz_rect a, fz_rect b); -/* - fz_irect_from_rect: Convert a rect into the minimal bounding box +/** + Convert a rect into the minimal bounding box that covers the rectangle. - bbox: Place to store the returned bbox. - - rect: The rectangle to convert to a bbox. - Coordinates in a bounding box are integers, so rounding of the rects coordinates takes place. The top left corner is rounded upwards and left while the bottom right corner is rounded downwards and to the right. - - Returns bbox (updated). */ +fz_irect fz_irect_from_rect(fz_rect rect); -fz_irect *fz_irect_from_rect(fz_irect *restrict bbox, const fz_rect *restrict rect); - -/* - fz_round_rect: Round rectangle coordinates. +/** + Round rectangle coordinates. Coordinates in a bounding box are integers, so rounding of the rects coordinates takes place. The top left corner is rounded @@ -536,15 +624,15 @@ fz_irect *fz_irect_from_rect(fz_irect *restrict bbox, const fz_rect *restrict re downwards and to the right. This differs from fz_irect_from_rect, in that fz_irect_from_rect - slavishly follows the numbers (i.e any slight over/under calculations - can cause whole extra pixels to be added). fz_round_rect - allows for a small amount of rounding error when calculating - the bbox. + slavishly follows the numbers (i.e any slight over/under + calculations can cause whole extra pixels to be added). + fz_round_rect allows for a small amount of rounding error when + calculating the bbox. */ -fz_irect *fz_round_rect(fz_irect *restrict bbox, const fz_rect *restrict rect); +fz_irect fz_round_rect(fz_rect rect); -/* - fz_rect_from_irect: Convert a bbox into a rect. +/** + Convert a bbox into a rect. For our purposes, a rect can represent all the values we meet in a bbox, so nothing can go wrong. @@ -555,39 +643,39 @@ fz_irect *fz_round_rect(fz_irect *restrict bbox, const fz_rect *restrict rect); Returns rect (updated). */ -fz_rect *fz_rect_from_irect(fz_rect *restrict rect, const fz_irect *restrict bbox); +fz_rect fz_rect_from_irect(fz_irect bbox); -/* - fz_expand_rect: Expand a bbox by a given amount in all directions. +/** + Expand a bbox by a given amount in all directions. */ -fz_rect *fz_expand_rect(fz_rect *b, float expand); -fz_irect *fz_expand_irect(fz_irect *a, int expand); +fz_rect fz_expand_rect(fz_rect b, float expand); +fz_irect fz_expand_irect(fz_irect a, int expand); -/* - fz_include_point_in_rect: Expand a bbox to include a given point. +/** + Expand a bbox to include a given point. To create a rectangle that encompasses a sequence of points, the rectangle must first be set to be the empty rectangle at one of the points before including the others. */ -fz_rect *fz_include_point_in_rect(fz_rect *r, const fz_point *p); +fz_rect fz_include_point_in_rect(fz_rect r, fz_point p); -/* - fz_translate_irect: Translate bounding box. +/** + Translate bounding box. Translate a bbox by a given x and y offset. Allows for overflow. */ -fz_rect *fz_translate_rect(fz_rect *a, float xoff, float yoff); -fz_irect *fz_translate_irect(fz_irect *a, int xoff, int yoff); +fz_rect fz_translate_rect(fz_rect a, float xoff, float yoff); +fz_irect fz_translate_irect(fz_irect a, int xoff, int yoff); -/* - fz_contains_rect: Test rectangle inclusion. +/** + Test rectangle inclusion. Return true if a entirely contains b. */ -int fz_contains_rect(const fz_rect *a, const fz_rect *b); +int fz_contains_rect(fz_rect a, fz_rect b); -/* - fz_transform_point: Apply a transformation to a point. +/** + Apply a transformation to a point. transform: Transformation matrix to apply. See fz_concat, fz_scale, fz_rotate and fz_translate for how to create a @@ -597,11 +685,11 @@ int fz_contains_rect(const fz_rect *a, const fz_rect *b); Returns transform (unchanged). */ -fz_point *fz_transform_point(fz_point *restrict point, const fz_matrix *restrict transform); -fz_point *fz_transform_point_xy(fz_point *restrict point, const fz_matrix *restrict transform, float x, float y); +fz_point fz_transform_point(fz_point point, fz_matrix m); +fz_point fz_transform_point_xy(float x, float y, fz_matrix m); -/* - fz_transform_vector: Apply a transformation to a vector. +/** + Apply a transformation to a vector. transform: Transformation matrix to apply. See fz_concat, fz_scale and fz_rotate for how to create a matrix. Any @@ -609,10 +697,10 @@ fz_point *fz_transform_point_xy(fz_point *restrict point, const fz_matrix *restr vector: Pointer to vector to update. */ -fz_point *fz_transform_vector(fz_point *restrict vector, const fz_matrix *restrict transform); +fz_point fz_transform_vector(fz_point vector, fz_matrix m); -/* - fz_transform_rect: Apply a transform to a rectangle. +/** + Apply a transform to a rectangle. After the four corner points of the axis-aligned rectangle have been transformed it may not longer be axis-aligned. So a @@ -626,15 +714,105 @@ fz_point *fz_transform_vector(fz_point *restrict vector, const fz_matrix *restri fz_empty_rect and fz_infinite_rect, may be used but are returned unchanged as expected. */ -fz_rect *fz_transform_rect(fz_rect *restrict rect, const fz_matrix *restrict transform); +fz_rect fz_transform_rect(fz_rect rect, fz_matrix m); -/* - fz_normalize_vector: Normalize a vector to length one. +/** + Normalize a vector to length one. */ -void fz_normalize_vector(fz_point *p); +fz_point fz_normalize_vector(fz_point p); -void fz_gridfit_matrix(int as_tiled, fz_matrix *m); +/** + Grid fit a matrix. -float fz_matrix_max_expansion(const fz_matrix *m); + as_tiled = 0 => adjust the matrix so that the image of the unit + square completely covers any pixel that was touched by the + image of the unit square under the original matrix. + + as_tiled = 1 => adjust the matrix so that the corners of the + image of the unit square align with the closest integer corner + of the image of the unit square under the original matrix. +*/ +fz_matrix fz_gridfit_matrix(int as_tiled, fz_matrix m); + +/** + Find the largest expansion performed by this matrix. + (i.e. max(abs(m.a),abs(m.b),abs(m.c),abs(m.d)) +*/ +float fz_matrix_max_expansion(fz_matrix m); + +/** + A representation for a region defined by 4 points. + + The significant difference between quads and rects is that + the edges of quads are not axis aligned. +*/ +typedef struct +{ + fz_point ul, ur, ll, lr; +} fz_quad; + +/** + Inline convenience construction function. +*/ +static inline fz_quad fz_make_quad( + float ul_x, float ul_y, + float ur_x, float ur_y, + float ll_x, float ll_y, + float lr_x, float lr_y) +{ + fz_quad q = { + { ul_x, ul_y }, + { ur_x, ur_y }, + { ll_x, ll_y }, + { lr_x, lr_y }, + }; + return q; +} + +/** + Convert a rect to a quad (losslessly). +*/ +fz_quad fz_quad_from_rect(fz_rect r); + +/** + Convert a quad to the smallest rect that covers it. +*/ +fz_rect fz_rect_from_quad(fz_quad q); + +/** + Transform a quad by a matrix. +*/ +fz_quad fz_transform_quad(fz_quad q, fz_matrix m); + +/** + Inclusion test for quads. +*/ +int fz_is_point_inside_quad(fz_point p, fz_quad q); + +/** + Inclusion test for rects. (Rect is assumed to be open, i.e. + top right corner is not included). +*/ +int fz_is_point_inside_rect(fz_point p, fz_rect r); + +/** + Inclusion test for irects. (Rect is assumed to be open, i.e. + top right corner is not included). +*/ +int fz_is_point_inside_irect(int x, int y, fz_irect r); + +/** + Inclusion test for quad in quad. + + This may break down if quads are not 'well formed'. +*/ +int fz_is_quad_inside_quad(fz_quad needle, fz_quad haystack); + +/** + Intersection test for quads. + + This may break down if quads are not 'well formed'. +*/ +int fz_is_quad_intersecting_quad(fz_quad a, fz_quad b); #endif diff --git a/include/mupdf/fitz/getopt.h b/include/mupdf/fitz/getopt.h index 8f71120..50409a0 100644 --- a/include/mupdf/fitz/getopt.h +++ b/include/mupdf/fitz/getopt.h @@ -1,20 +1,128 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_GETOPT_H #define MUPDF_FITZ_GETOPT_H -/* - getopt: Simple functions/variables for use in tools. +#include "export.h" + +typedef struct +{ + char *option; + int *flag; + void *opaque; +} fz_getopt_long_options; + +/** + Simple functions/variables for use in tools. + + ostr = option string. Comprises single letter options, followed by : if there + is an argument to the option. + + longopts: NULL (indicating no long options), or a pointer to an array of + longoptions, terminated by an entry with option == NULL. + + In the event of matching a single char option, this function will normally + return the char. The exception to this is when the option requires an + argument and none is supplied; in this case we return ':'. + + In the event of matching a long option, this function returns 0, with fz_optlong + set to point to the matching option. + + A long option entry may be followed with : to indicate there is an argument to the + option. If the need for an argument is specified in this way, and no argument is + given, an error will be displayed and argument processing will stop. If an argument + is given, and the long option record contains a non-null flag pointer, then the code + will decode the argument and fill in that flag pointer. Specifically, + case-insensitive matches to 'yes', 'no', 'true' and 'false' will cause a value of 0 + or 1 as appropriate to be written; failing this the arg will be interpreted as a + decimal integer using atoi. + + A long option entry may be followed by an list of options (e.g. myoption=foo|bar|baz) + and the option will be passed to fz_opt_from_list. The return value of that will be + placed in fz_optitem. If the return value of that function is -1, then an error will + be displayed and argument processing will stop. + + In the event of reaching the end of the arg list or '--', this function returns EOF. + + In the event of failing to match anything, an error is printed, and we return '?'. + + If an argument is expected for the option, then fz_optarg will be returned pointing + at the start of the argument. Examples of supported argument formats: '-r500', '-r 500', + '--resolution 500', '--resolution=500'. +*/ +extern int fz_getopt_long(int nargc, char * const *nargv, const char *ostr, const fz_getopt_long_options *longopts); + +/** + Identical to fz_getopt_long, but with a NULL longopts field, signifying no long + options. */ extern int fz_getopt(int nargc, char * const *nargv, const char *ostr); -extern int fz_optind; -extern char *fz_optarg; -/* - Windows unicode versions. +/** + fz_optind is updated to point to the current index being read from the + arguments. */ -#ifdef _WIN32 -extern int fz_getoptw(int nargc, wchar_t * const *nargv, const wchar_t *ostr); -extern int fz_optindw; -extern wchar_t *fz_optargw; -#endif +FZ_DATA extern int fz_optind; + +/** + fz_optarg is a pointer to the argument data for the most recently + read option. +*/ +FZ_DATA extern char *fz_optarg; + +/** + fz_optlong is a pointer to the record for the most recently + read long option. (i.e. if a long option is detected, this + will be set to point to the record for that option, otherwise + it will be NULL). +*/ +FZ_DATA extern const fz_getopt_long_options *fz_optlong; + +/** + The item number for the most recently matched item list. + + First item in the list is numbered 0. No match is -1. +*/ +FZ_DATA extern int fz_optitem; + +/** + Return the index of a (case-insensitive) option within an optlist. + + For instance for optlist = "Foo|Bar|Baz", and opt = "bar", + this would return 1. + + If the optlist ends with "|*" then that is a catch all case and + matches all options allowing the caller to process it itself. + fz_optarg will be set to point to the option, and the return + value will be the index of the '*' option within that list. + + If an optlist entry ends with ':' (e.g. "Foo:") then that option + may have suboptions appended to it (for example "JPG:80") and + fz_optarg will be set to point at "80". Otherwise fz_optarg will + be set to NULL. + + In the event of no-match found, prints an error and returns -1. +*/ +int fz_opt_from_list(char *opt, const char *optlist); #endif diff --git a/include/mupdf/fitz/glyph-cache.h b/include/mupdf/fitz/glyph-cache.h index 2a86213..c4b5fcf 100644 --- a/include/mupdf/fitz/glyph-cache.h +++ b/include/mupdf/fitz/glyph-cache.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_GLYPH_CACHE_H #define MUPDF_FITZ_GLYPH_CACHE_H @@ -5,12 +27,70 @@ #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/font.h" #include "mupdf/fitz/pixmap.h" +#include "mupdf/fitz/device.h" +/** + Purge all the glyphs from the cache. +*/ void fz_purge_glyph_cache(fz_context *ctx); -fz_pixmap *fz_render_glyph_pixmap(fz_context *ctx, fz_font*, int, fz_matrix *, const fz_irect *scissor, int aa); -void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, const fz_matrix *trm, void *gstate, int nested_depth, fz_default_colorspaces *def_cs); -void fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid, int nested_depth); -void fz_dump_glyph_cache_stats(fz_context *ctx); + +/** + Create a pixmap containing a rendered glyph. + + Lookup gid from font, clip it with scissor, and rendering it + with aa bits of antialiasing into a new pixmap. + + The caller takes ownership of the pixmap and so must free it. + + Note: This function is no longer used for normal rendering + operations, and is kept around just because we use it in the + app. It should be considered "at risk" of removal from the API. +*/ +fz_pixmap *fz_render_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, const fz_irect *scissor, int aa); + +/** + Nasty PDF interpreter specific hernia, required to allow the + interpreter to replay glyphs from a type3 font directly into + the target device. + + This is only used in exceptional circumstances (such as type3 + glyphs that inherit current graphics state, or nested type3 + glyphs). +*/ +void fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate, fz_default_colorspaces *def_cs); + +/** + Force a type3 font to cache the displaylist for a given glyph + id. + + This caching can involve reading the underlying file, so must + happen ahead of time, so we aren't suddenly forced to read the + file while playing a displaylist back. +*/ +void fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid); + +/** + Dump debug statistics for the glyph cache. +*/ +void fz_dump_glyph_cache_stats(fz_context *ctx, fz_output *out); + +/** + Perform subpixel quantisation and adjustment on a glyph matrix. + + ctm: On entry, the desired 'ideal' transformation for a glyph. + On exit, adjusted to a (very similar) transformation quantised + for subpixel caching. + + subpix_ctm: Initialised by the routine to the transform that + should be used to render the glyph. + + qe, qf: which subpixel position we quantised to. + + Returns: the size of the glyph. + + Note: This is currently only exposed for use in our app. It + should be considered "at risk" of removal from the API. +*/ float fz_subpixel_adjust(fz_context *ctx, fz_matrix *ctm, fz_matrix *subpix_ctm, unsigned char *qe, unsigned char *qf); #endif diff --git a/include/mupdf/fitz/glyph.h b/include/mupdf/fitz/glyph.h index 4b2bfdb..960a4ff 100644 --- a/include/mupdf/fitz/glyph.h +++ b/include/mupdf/fitz/glyph.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_GLYPH_H #define MUPDF_FITZ_GLYPH_H @@ -5,71 +27,33 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/store.h" -#include "mupdf/fitz/colorspace.h" +#include "mupdf/fitz/font.h" +#include "mupdf/fitz/path.h" -/* +/** Glyphs represent a run length encoded set of pixels for a 2 dimensional region of a plane. */ -typedef struct fz_glyph_s fz_glyph; +typedef struct fz_glyph fz_glyph; -/* - fz_glyph_bbox: Return the bounding box for a glyph. +/** + Return the bounding box of the glyph in pixels. */ -fz_irect *fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph, fz_irect *bbox); +fz_irect fz_glyph_bbox(fz_context *ctx, fz_glyph *glyph); +fz_irect fz_glyph_bbox_no_ctx(fz_glyph *src); -/* - fz_glyph_width: Return the width of the glyph in pixels. +/** + Return the width of the glyph in pixels. */ int fz_glyph_width(fz_context *ctx, fz_glyph *glyph); -/* - fz_glyph_height: Return the height of the glyph in pixels. +/** + Return the height of the glyph in pixels. */ int fz_glyph_height(fz_context *ctx, fz_glyph *glyph); -/* - fz_new_glyph_from_pixmap: Create a new glyph from a pixmap - - Returns a pointer to the new glyph. Throws exception on failure to - allocate. -*/ -fz_glyph *fz_new_glyph_from_pixmap(fz_context *ctx, fz_pixmap *pix); - -/* - fz_new_glyph_from_8bpp_data: Create a new glyph from 8bpp data - - x, y: X and Y position for the glyph - - w, h: Width and Height for the glyph - - sp: Source Pointer to data - - span: Increment from line to line of data - - Returns a pointer to the new glyph. Throws exception on failure to - allocate. -*/ -fz_glyph *fz_new_glyph_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span); - -/* - fz_new_glyph_from_1bpp_data: Create a new glyph from 1bpp data - - x, y: X and Y position for the glyph - - w, h: Width and Height for the glyph - - sp: Source Pointer to data - - span: Increment from line to line of data - - Returns a pointer to the new glyph. Throws exception on failure to - allocate. -*/ -fz_glyph *fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span); - -/* - fz_keep_glyph: Take a reference to a glyph. +/** + Take a reference to a glyph. pix: The glyph to increment the reference for. @@ -77,57 +61,21 @@ fz_glyph *fz_new_glyph_from_1bpp_data(fz_context *ctx, int x, int y, int w, int */ fz_glyph *fz_keep_glyph(fz_context *ctx, fz_glyph *pix); -/* - fz_drop_glyph: Drop a reference and free a glyph. +/** + Drop a reference and free a glyph. Decrement the reference count for the glyph. When no references remain the glyph will be freed. */ void fz_drop_glyph(fz_context *ctx, fz_glyph *pix); -/* - Glyphs represent a set of pixels for a 2 dimensional region of a - plane. +/** + Look a glyph up from a font, and return the outline of the + glyph using the given transform. - x, y: The minimum x and y coord of the region in pixels. - - w, h: The width and height of the region in pixels. - - samples: The sample data. The sample data is in a compressed format - designed to give reasonable compression, and to be fast to plot from. - - The first sizeof(int) * h bytes of the table, when interpreted as - ints gives the offset within the data block of that lines data. An - offset of 0 indicates that that line is completely blank. - - The data for individual lines is a sequence of bytes: - 00000000 = end of lines data - LLLLLL00 = extend the length given in the next run by the 6 L bits - given here. - LLLLLL01 = A run of length L+1 transparent pixels. - LLLLLE10 = A run of length L+1 solid pixels. If E then this is the - last run on this line. - LLLLLE11 = A run of length L+1 intermediate pixels followed by L+1 - bytes of literal pixel data. If E then this is the last run - on this line. + The caller owns the returned path, and so is responsible for + ensuring that it eventually gets dropped. */ -struct fz_glyph_s -{ - fz_storable storable; - int x, y, w, h; - fz_pixmap *pixmap; - size_t size; - unsigned char data[1]; -}; - -fz_irect *fz_glyph_bbox_no_ctx(fz_glyph *src, fz_irect *bbox); - -static inline size_t -fz_glyph_size(fz_context *ctx, fz_glyph *glyph) -{ - if (glyph == NULL) - return 0; - return sizeof(fz_glyph) + glyph->size + fz_pixmap_size(ctx, glyph->pixmap); -} +fz_path *fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm); #endif diff --git a/include/mupdf/fitz/hash.h b/include/mupdf/fitz/hash.h index 22bcff0..873cf32 100644 --- a/include/mupdf/fitz/hash.h +++ b/include/mupdf/fitz/hash.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_HASH_H #define MUPDF_FITZ_HASH_H @@ -5,28 +27,100 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/output.h" -/* - * Generic hash-table with fixed-length keys. - * - * The keys and values are NOT reference counted by the hash table. - * Callers are responsible for taking care the reference counts are correct. - * Inserting a duplicate entry will NOT overwrite the old value, and will - * return the old value. - * - * The drop_val callback function is only used to release values when the hash table - * is destroyed. - */ +#define FZ_HASH_TABLE_KEY_LENGTH 48 -typedef struct fz_hash_table_s fz_hash_table; +/** + Generic hash-table with fixed-length keys. + + The keys and values are NOT reference counted by the hash table. + Callers are responsible for taking care the reference counts are + correct. Inserting a duplicate entry will NOT overwrite the old + value, and will return the old value. + + The drop_val callback function is only used to release values + when the hash table is destroyed. +*/ + +typedef struct fz_hash_table fz_hash_table; + +/** + Function type called when a hash table entry is dropped. + + Only used when the entire hash table is dropped. +*/ typedef void (fz_hash_table_drop_fn)(fz_context *ctx, void *val); -typedef void (fz_hash_table_for_each_fn)(fz_context *ctx, void *state, void *key, int keylen, void *val); +/** + Create a new hash table. + + initialsize: The initial size of the hashtable. The hashtable + may grow (double in size) if it starts to get crowded (80% + full). + + keylen: byte length for each key. + + lock: -1 for no lock, otherwise the FZ_LOCK to use to protect + this table. + + drop_val: Function to use to destroy values on table drop. +*/ fz_hash_table *fz_new_hash_table(fz_context *ctx, int initialsize, int keylen, int lock, fz_hash_table_drop_fn *drop_val); + +/** + Destroy the hash table. + + Values are dropped using the drop function. +*/ void fz_drop_hash_table(fz_context *ctx, fz_hash_table *table); +/** + Search for a matching hash within the table, and return the + associated value. +*/ void *fz_hash_find(fz_context *ctx, fz_hash_table *table, const void *key); + +/** + Insert a new key/value pair into the hash table. + + If an existing entry with the same key is found, no change is + made to the hash table, and a pointer to the existing value is + returned. + + If no existing entry with the same key is found, ownership of + val passes in, key is copied, and NULL is returned. +*/ void *fz_hash_insert(fz_context *ctx, fz_hash_table *table, const void *key, void *val); + +/** + Remove the entry for a given key. + + The value is NOT freed, so the caller is expected to take care + of this. +*/ void fz_hash_remove(fz_context *ctx, fz_hash_table *table, const void *key); + +/** + Callback function called on each key/value pair in the hash + table, when fz_hash_for_each is run. +*/ +typedef void (fz_hash_table_for_each_fn)(fz_context *ctx, void *state, void *key, int keylen, void *val); + +/** + Iterate over the entries in a hash table. +*/ void fz_hash_for_each(fz_context *ctx, fz_hash_table *table, void *state, fz_hash_table_for_each_fn *callback); +/** + Callback function called on each key/value pair in the hash + table, when fz_hash_filter is run to remove entries where the + callback returns true. +*/ +typedef int (fz_hash_table_filter_fn)(fz_context *ctx, void *state, void *key, int keylen, void *val); + +/** + Iterate over the entries in a hash table, removing all the ones where callback returns true. + Does NOT free the value of the entry, so the caller is expected to take care of this. +*/ +void fz_hash_filter(fz_context *ctx, fz_hash_table *table, void *state, fz_hash_table_filter_fn *callback); + #endif diff --git a/include/mupdf/fitz/heap-imp.h b/include/mupdf/fitz/heap-imp.h new file mode 100644 index 0000000..5e042d9 --- /dev/null +++ b/include/mupdf/fitz/heap-imp.h @@ -0,0 +1,163 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +/* This file has preprocessor magic in it to instantiate both + * protoypes and implementations for heap sorting structures + * of various different types. Effectively, it's templating for + * C. + * + * If you are including this file directly without intending to + * be instantiating a new set of heap sort functions, you are + * doing the wrong thing. + */ + +#ifndef MUPDF_FITZ_HEAP_I_KNOW_WHAT_IM_DOING +#error Do not include heap-imp.h unless you know what youre doing +#endif + +#define HEAP_XCAT(A,B) A##B +#define HEAP_CAT(A,B) HEAP_XCAT(A,B) + +#ifndef MUPDF_FITZ_HEAP_IMPLEMENT +typedef struct +{ + int max; + int len; + HEAP_CONTAINER_TYPE *heap; +} HEAP_TYPE_NAME; +#endif + +void HEAP_CAT(HEAP_TYPE_NAME,_insert)(fz_context *ctx, HEAP_TYPE_NAME *heap, HEAP_CONTAINER_TYPE v +#ifndef HEAP_CMP + , int (*HEAP_CMP)(HEAP_CONTAINER_TYPE *a, HEAP_CONTAINER_TYPE *b) +#endif + ) +#ifndef MUPDF_FITZ_HEAP_IMPLEMENT +; +#else +{ + int i; + HEAP_CONTAINER_TYPE *h; + + if (heap->max == heap->len) + { + int m = heap->max * 2; + + if (m == 0) + m = 32; + + heap->heap = (HEAP_CONTAINER_TYPE *)fz_realloc(ctx, heap->heap, sizeof(*heap->heap) * m); + heap->max = m; + } + h = heap->heap; + + /* Insert it into the heap. Consider inserting at position i, and + * then 'heapify' back. We can delay the actual insertion to the + * end of the process. */ + i = heap->len++; + while (i != 0) + { + int parent_idx = (i-1)/2; + HEAP_CONTAINER_TYPE *parent_val = &h[parent_idx]; + if (HEAP_CMP(parent_val, &v) > 0) + break; + h[i] = h[parent_idx]; + i = parent_idx; + } + h[i] = v; +} +#endif + +void HEAP_CAT(HEAP_TYPE_NAME,_sort)(fz_context *ctx, HEAP_TYPE_NAME *heap +#ifndef HEAP_CMP + , int (*HEAP_CMP)(HEAP_CONTAINER_TYPE *a, HEAP_CONTAINER_TYPE *b) +#endif + ) +#ifndef MUPDF_FITZ_HEAP_IMPLEMENT +; +#else +{ + int j; + HEAP_CONTAINER_TYPE *h = heap->heap; + + /* elements j to len are always sorted. 0 to j are always a valid heap. Gradually move j to 0. */ + for (j = heap->len-1; j > 0; j--) + { + int k; + HEAP_CONTAINER_TYPE val; + + /* Swap max element with j. Invariant valid for next value to j. */ + val = h[j]; + h[j] = h[0]; + /* Now reform the heap. 0 to k is a valid heap. */ + k = 0; + while (1) + { + int kid = k*2+1; + if (kid >= j) + break; + if (kid+1 < j && (HEAP_CMP(&h[kid+1], &h[kid])) > 0) + kid++; + if ((HEAP_CMP(&val, &h[kid])) > 0) + break; + h[k] = h[kid]; + k = kid; + } + h[k] = val; + } +} +#endif + +void HEAP_CAT(HEAP_TYPE_NAME,_uniq)(fz_context *ctx, HEAP_TYPE_NAME *heap +#ifndef HEAP_CMP + , int (*HEAP_CMP)(HEAP_CONTAINER_TYPE *a, HEAP_CONTAINER_TYPE *b) +#endif + ) +#ifndef MUPDF_FITZ_HEAP_IMPLEMENT +; +#else +{ + int n = heap->len; + int i, j = 0; + HEAP_CONTAINER_TYPE *h = heap->heap; + + if (n == 0) + return; + + j = 0; + for (i = 1; i < n; i++) + { + if (HEAP_CMP(&h[j], &h[i]) == 0) + continue; + j++; + if (i != j) + h[j] = h[i]; + } + heap->len = j+1; +} +#endif + +#undef HEAP_CONTAINER_TYPE +#undef HEAP_TYPE_NAME +#undef HEAP_CMP +#undef HEAP_XCAT +#undef HEAP_CAT diff --git a/include/mupdf/fitz/heap.h b/include/mupdf/fitz/heap.h new file mode 100644 index 0000000..97d98a8 --- /dev/null +++ b/include/mupdf/fitz/heap.h @@ -0,0 +1,140 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +/* This file has preprocessor magic in it to instantiate both + * protoypes and implementations for heap sorting structures + * of various different types. Effectively, it's templating for + * C. + * + * If you are including this file directly without intending to + * be instantiating a new set of heap sort functions, you are + * doing the wrong thing. + */ + +/* This header file declares some useful heap functions. (Heap + * as in heap sort, not as in memory heap). It uses some + * clever (read "hacky") multiple inclusion techniques to allow + * us to generate multiple different versions of this code. + * This is kinda like 'templating' in C++, but without language + * support. + */ + +/* For every instance of this code, we end up a heap structure: + * + * typedef struct + * { + * int max; + * int len; + * *heap; + * } fz__heap; + * + * This can be created and initialised on the stack in user code using: + * + * fz__heap heap = { 0 }; + * + * and some functions. + * + * When is a simple int (or float or similar), the ordering required is + * obvious, and so the functions are simple (Form 1): + * + * First some to insert elements into the heap: + * + * void fz__heap_insert(fz_context *ctx, fz__heap *heap, v); + * + * Once all the elements have been inserted, the heap can be sorted: + * + * void fz__heap_sort(fz_context *ctx, fz__heap *heap); + * + * Once sorted, repeated elements can be removed: + * + * void fz__heap_uniq(fz_context *ctx, fz__heap *heap); + * + * + * For more complex TYPEs (such as pointers) the ordering may not be implicit within the , + * but rather depends upon the data found by dereferencing those pointers. For such types, + * the functions are modified with a function, of the form used by qsort etc: + * + * int (x, y) that returns 0 for x == y, +ve for x > y, and -ve for x < y. + * + * The functions are modified thus (Form 2): + * + * void fz__heap_insert(fz_context *ctx, fz__heap *heap, v, t); + * void fz__heap_sort(fz_context *ctx, fz__heap *heap, t); + * void fz__heap_uniq(fz_context *ctx, fz__heap *heap, t); + * + * Currently, we define: + * + * fz_int_heap Operates on 'int' values. Form 1. + * fz_ptr_heap Operates on 'void *' values. Form 2. + * fz_int2_heap Operates on 'typedef struct { int a; int b} fz_int2' values, + * with the sort/uniq being done based on 'a' alone. Form 1. + * fz_intptr_heap Operates on 'typedef struct { int a; void *b} fz_intptr' values, + * with the sort/uniq being done based on 'a' alone. Form 1. + */ + +/* Everything after this point is preprocessor magic. Ignore it, and just read the above + * unless you are wanting to instantiate a new set of functions. */ + +#ifndef MUPDF_FITZ_HEAP_H + +#define MUPDF_FITZ_HEAP_H + +#define MUPDF_FITZ_HEAP_I_KNOW_WHAT_IM_DOING + +/* Instantiate fz_int_heap */ +#define HEAP_TYPE_NAME fz_int_heap +#define HEAP_CONTAINER_TYPE int +#define HEAP_CMP(a,b) ((*a) - (*b)) +#include "mupdf/fitz/heap-imp.h" + +/* Instantiate fz_ptr_heap */ +#define HEAP_TYPE_NAME fz_ptr_heap +#define HEAP_CONTAINER_TYPE void * +#include "mupdf/fitz/heap-imp.h" + +/* Instantiate fz_int2_heap */ +#ifndef MUPDF_FITZ_HEAP_IMPLEMENT +typedef struct +{ + int a; + int b; +} fz_int2; +#endif +#define HEAP_TYPE_NAME fz_int2_heap +#define HEAP_CMP(A,B) (((A)->a) - ((B)->a)) +#define HEAP_CONTAINER_TYPE fz_int2 +#include "mupdf/fitz/heap-imp.h" + +/* Instantiate fz_intptr_heap */ +#ifndef MUPDF_FITZ_HEAP_IMPLEMENT +typedef struct +{ + int a; + int b; +} fz_intptr; +#endif +#define HEAP_TYPE_NAME fz_intptr_heap +#define HEAP_CONTAINER_TYPE fz_intptr +#define HEAP_CMP(A,B) (((A)->a) - ((B)->a)) +#include "mupdf/fitz/heap-imp.h" + +#endif /* MUPDF_FITZ_HEAP_H */ diff --git a/include/mupdf/fitz/image.h b/include/mupdf/fitz/image.h index 3d6fe43..3f9dee1 100644 --- a/include/mupdf/fitz/image.h +++ b/include/mupdf/fitz/image.h @@ -1,40 +1,60 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_IMAGE_H #define MUPDF_FITZ_IMAGE_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/store.h" -#include "mupdf/fitz/colorspace.h" #include "mupdf/fitz/pixmap.h" #include "mupdf/fitz/buffer.h" #include "mupdf/fitz/stream.h" #include "mupdf/fitz/compressed-buffer.h" -/* +/** Images are storable objects from which we can obtain fz_pixmaps. - These may be implemented as simple wrappers around a pixmap, or as - more complex things that decode at different subsample settings on - demand. + These may be implemented as simple wrappers around a pixmap, or + as more complex things that decode at different subsample + settings on demand. */ -typedef struct fz_image_s fz_image; -typedef struct fz_compressed_image_s fz_compressed_image; -typedef struct fz_pixmap_image_s fz_pixmap_image; +typedef struct fz_image fz_image; +typedef struct fz_compressed_image fz_compressed_image; +typedef struct fz_pixmap_image fz_pixmap_image; -/* - fz_get_pixmap_from_image: Called to get a handle to a pixmap from an image. +/** + Called to get a handle to a pixmap from an image. image: The image to retrieve a pixmap from. - color_params: The color parameters (or NULL for defaults). + subarea: The subarea of the image that we actually care about + (or NULL to indicate the whole image). - subarea: The subarea of the image that we actually care about (or NULL - to indicate the whole image). - - trans: Optional, unless subarea is given. If given, then on entry this is - the transform that will be applied to the complete image. It should be - updated on exit to the transform to apply to the given subarea of the - image. This is used to calculate the desired width/height for subsampling. + ctm: Optional, unless subarea is given. If given, then on + entry this is the transform that will be applied to the complete + image. It should be updated on exit to the transform to apply to + the given subarea of the image. This is used to calculate the + desired width/height for subsampling. w: If non-NULL, a pointer to an int to be updated on exit to the width (in pixels) that the scaled output will cover. @@ -42,38 +62,58 @@ typedef struct fz_pixmap_image_s fz_pixmap_image; h: If non-NULL, a pointer to an int to be updated on exit to the height (in pixels) that the scaled output will cover. - Returns a non NULL pixmap pointer. May throw exceptions. + Returns a non NULL kept pixmap pointer. May throw exceptions. */ -fz_pixmap *fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *trans, int *w, int *h); +fz_pixmap *fz_get_pixmap_from_image(fz_context *ctx, fz_image *image, const fz_irect *subarea, fz_matrix *ctm, int *w, int *h); -/* - fz_drop_image: Drop a reference to an image. - - image: The image to drop a reference to. +/** + Calls fz_get_pixmap_from_image() with ctm, subarea, w and h all set to NULL. */ -void fz_drop_image(fz_context *ctx, fz_image *image); +fz_pixmap *fz_get_unscaled_pixmap_from_image(fz_context *ctx, fz_image *image); -/* - fz_keep_image: Increment the reference count of an image. +/** + Increment the (normal) reference count for an image. Returns the + same pointer. - image: The image to take a reference to. - - Returns a pointer to the image. + Never throws exceptions. */ fz_image *fz_keep_image(fz_context *ctx, fz_image *image); +/** + Decrement the (normal) reference count for an image. When the + total (normal + key) reference count reaches zero, the image and + its resources are freed. + + Never throws exceptions. +*/ +void fz_drop_image(fz_context *ctx, fz_image *image); + +/** + Increment the store key reference for an image. Returns the same + pointer. (This is the count of references for an image held by + keys in the image store). + + Never throws exceptions. +*/ fz_image *fz_keep_image_store_key(fz_context *ctx, fz_image *image); + +/** + Decrement the store key reference count for an image. When the + total (normal + key) reference count reaches zero, the image and + its resources are freed. + + Never throws exceptions. +*/ void fz_drop_image_store_key(fz_context *ctx, fz_image *image); -/* - fz_drop_image_fn: Function type to destroy an images data +/** + Function type to destroy an images data when it's reference count reaches zero. */ typedef void (fz_drop_image_fn)(fz_context *ctx, fz_image *image); -/* - fz_get_pixmap_fn: Function type to get a decoded pixmap - for an image. +/** + Function type to get a decoded pixmap for an image. im: The image to decode. @@ -92,20 +132,21 @@ typedef void (fz_drop_image_fn)(fz_context *ctx, fz_image *image); knows what remains to be done. Returns a reference to a decoded pixmap that satisfies the - requirements of the request. + requirements of the request. The caller owns the returned + reference. */ typedef fz_pixmap *(fz_image_get_pixmap_fn)(fz_context *ctx, fz_image *im, fz_irect *subarea, int w, int h, int *l2factor); -/* - fz_image_get_size_fn: Function type to get the given storage +/** + Function type to get the given storage size for an image. Returns the size in bytes used for a given image. */ typedef size_t (fz_image_get_size_fn)(fz_context *, fz_image *); -/* - fz_new_image_of_size: Internal function to make a new fz_image structure +/** + Internal function to make a new fz_image structure for a derived class. w,h: Width and height of the created image. @@ -127,7 +168,7 @@ typedef size_t (fz_image_get_size_fn)(fz_context *, fz_image *); decode array is [0 1] (repeated n times, for n color components). colorkey: NULL, or a pointer to a colorkey array. The default - colorkey array is [0 255] (repeatd n times, for n color + colorkey array is [0 255] (repeated n times, for n color components). mask: NULL, or another image to use as a mask for this one. @@ -158,10 +199,10 @@ fz_image *fz_new_image_of_size(fz_context *ctx, int yres, int interpolate, int imagemask, - float *decode, - int *colorkey, + const float *decode, + const int *colorkey, fz_image *mask, - int size, + size_t size, fz_image_get_pixmap_fn *get_pixmap, fz_image_get_size_fn *get_size, fz_drop_image_fn *drop); @@ -169,8 +210,8 @@ fz_image *fz_new_image_of_size(fz_context *ctx, #define fz_new_derived_image(CTX,W,H,B,CS,X,Y,I,IM,D,C,M,T,G,S,Z) \ ((T*)Memento_label(fz_new_image_of_size(CTX,W,H,B,CS,X,Y,I,IM,D,C,M,sizeof(T),G,S,Z),#T)) -/* - fz_new_image_from_compressed_buffer: Create an image based on +/** + Create an image based on the data in the supplied compressed buffer. w,h: Width and height of the created image. @@ -185,14 +226,14 @@ fz_image *fz_new_image_of_size(fz_context *ctx, interpolate: 1 if interpolation should be used when decoding this image, 0 otherwise. - imagemask: 1 if this is an imagemask (i.e. transparent), 0 - otherwise. + imagemask: 1 if this is an imagemask (i.e. transparency bitmap + mask), 0 otherwise. decode: NULL, or a pointer to to a decode array. The default decode array is [0 1] (repeated n times, for n color components). colorkey: NULL, or a pointer to a colorkey array. The default - colorkey array is [0 255] (repeatd n times, for n color + colorkey array is [0 255] (repeated n times, for n color components). buffer: Buffer of compressed data and compression parameters. @@ -202,10 +243,10 @@ fz_image *fz_new_image_of_size(fz_context *ctx, A new reference is taken to this image. Supplying a masked image as a mask to another image is illegal! */ -fz_image *fz_new_image_from_compressed_buffer(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace, int xres, int yres, int interpolate, int imagemask, float *decode, int *colorkey, fz_compressed_buffer *buffer, fz_image *mask); +fz_image *fz_new_image_from_compressed_buffer(fz_context *ctx, int w, int h, int bpc, fz_colorspace *colorspace, int xres, int yres, int interpolate, int imagemask, const float *decode, const int *colorkey, fz_compressed_buffer *buffer, fz_image *mask); -/* - fz_new_image_from_pixmap: Create an image from the given +/** + Create an image from the given pixmap. pixmap: The pixmap to base the image upon. A new reference @@ -217,32 +258,76 @@ fz_image *fz_new_image_from_compressed_buffer(fz_context *ctx, int w, int h, int */ fz_image *fz_new_image_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, fz_image *mask); -/* - fz_new_image_from_buffer: Create a new image from a +/** + Create a new image from a buffer of data, inferring its type from the format of the data. */ fz_image *fz_new_image_from_buffer(fz_context *ctx, fz_buffer *buffer); -/* - fz_image_from_file: Create a new image from the contents +/** + Create a new image from the contents of a file, inferring its type from the format of the data. */ fz_image *fz_new_image_from_file(fz_context *ctx, const char *path); +/** + Internal destructor exposed for fz_store integration. +*/ void fz_drop_image_imp(fz_context *ctx, fz_storable *image); + +/** + Internal destructor for the base image class members. + + Exposed to allow derived image classes to be written. +*/ void fz_drop_image_base(fz_context *ctx, fz_image *image); -fz_pixmap *fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_compressed_image *image, fz_irect *subarea, int indexed, int l2factor); -unsigned char *fz_indexed_colorspace_palette(fz_context *ctx, fz_colorspace *cs, int *high); -fz_pixmap *fz_expand_indexed_pixmap(fz_context *ctx, const fz_pixmap *src, int alpha); + +/** + Decode a subarea of a compressed image. l2factor is the amount + of subsampling inbuilt to the stream (i.e. performed by the + decoder). If non NULL, l2extra is the extra amount of + subsampling that should be performed by this routine. This will + be updated on exit to the amount of subsampling that is still + required to be done. + + Returns a kept reference. +*/ +fz_pixmap *fz_decomp_image_from_stream(fz_context *ctx, fz_stream *stm, fz_compressed_image *image, fz_irect *subarea, int indexed, int l2factor, int *l2extra); + +/** + Convert pixmap from indexed to base colorspace. + + This creates a new bitmap containing the converted pixmap data. + */ +fz_pixmap *fz_convert_indexed_pixmap_to_base(fz_context *ctx, const fz_pixmap *src); + +/** + Convert pixmap from DeviceN/Separation to base colorspace. + + This creates a new bitmap containing the converted pixmap data. +*/ +fz_pixmap *fz_convert_separation_pixmap_to_base(fz_context *ctx, const fz_pixmap *src); + +/** + Return the size of the storage used by an image. +*/ size_t fz_image_size(fz_context *ctx, fz_image *im); -/* +/** + Return the type of a compressed image. + + Any non-compressed image will have the type returned as UNKNOWN. +*/ +int fz_compressed_image_type(fz_context *ctx, fz_image *image); + + +/** Structure is public to allow other structures to be derived from it. Do not access members directly. */ -struct fz_image_s +struct fz_image { fz_key_storable key_storable; int w, h; @@ -252,9 +337,9 @@ struct fz_image_s unsigned int interpolate:1; unsigned int use_colorkey:1; unsigned int use_decode:1; - unsigned int invert_cmyk_jpeg:1; unsigned int decoded:1; unsigned int scalable:1; + uint8_t orientation; fz_image *mask; int xres; /* As given in the image, not necessarily as rendered */ int yres; /* As given in the image, not necessarily as rendered */ @@ -266,29 +351,8 @@ struct fz_image_s float decode[FZ_MAX_COLORS * 2]; }; -fz_pixmap *fz_load_jpeg(fz_context *ctx, const unsigned char *data, size_t size); -fz_pixmap *fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *cs); -fz_pixmap *fz_load_png(fz_context *ctx, const unsigned char *data, size_t size); -fz_pixmap *fz_load_tiff(fz_context *ctx, const unsigned char *data, size_t size); -fz_pixmap *fz_load_jxr(fz_context *ctx, const unsigned char *data, size_t size); -fz_pixmap *fz_load_gif(fz_context *ctx, const unsigned char *data, size_t size); -fz_pixmap *fz_load_bmp(fz_context *ctx, const unsigned char *data, size_t size); -fz_pixmap *fz_load_pnm(fz_context *ctx, const unsigned char *data, size_t size); - -void fz_load_jpeg_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_jpx_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_png_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_tiff_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_jxr_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_gif_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_bmp_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); -void fz_load_pnm_info(fz_context *ctx, const unsigned char *data, size_t size, int *w, int *h, int *xres, int *yres, fz_colorspace **cspace); - -int fz_load_tiff_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len); -fz_pixmap *fz_load_tiff_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage); - -/* - fz_image_resolution: Request the natural resolution +/** + Request the natural resolution of an image. xres, yres: Pointers to ints to be updated with the @@ -297,12 +361,35 @@ fz_pixmap *fz_load_tiff_subimage(fz_context *ctx, const unsigned char *buf, size */ void fz_image_resolution(fz_image *image, int *xres, int *yres); -fz_pixmap *fz_compressed_image_tile(fz_context *ctx, fz_compressed_image *cimg); -void fz_set_compressed_image_tile(fz_context *ctx, fz_compressed_image *cimg, fz_pixmap *pix); +/** + Request the natural orientation of an image. -/* - fz_compressed_image_buffer: Retrieve the underlying compressed - data for an image. + This is for images (such as JPEG) that can contain internal + specifications of rotation/flips. This is ignored by all the + internal decode/rendering routines, but can be used by callers + (such as the image document handler) to respect such + specifications. + + The values used by MuPDF are as follows, with the equivalent + Exif specifications given for information: + + 0: Undefined + 1: 0 degree ccw rotation. (Exif = 1) + 2: 90 degree ccw rotation. (Exif = 8) + 3: 180 degree ccw rotation. (Exif = 3) + 4: 270 degree ccw rotation. (Exif = 6) + 5: flip on X. (Exif = 2) + 6: flip on X, then rotate ccw by 90 degrees. (Exif = 5) + 7: flip on X, then rotate ccw by 180 degrees. (Exif = 4) + 8: flip on X, then rotate ccw by 270 degrees. (Exif = 7) +*/ +uint8_t fz_image_orientation(fz_context *ctx, fz_image *image); + +fz_matrix +fz_image_orientation_matrix(fz_context *ctx, fz_image *image); + +/** + Retrieve the underlying compressed data for an image. Returns a pointer to the underlying data buffer for an image, or NULL if this image is not based upon a compressed data @@ -314,9 +401,8 @@ void fz_set_compressed_image_tile(fz_context *ctx, fz_compressed_image *cimg, fz fz_compressed_buffer *fz_compressed_image_buffer(fz_context *ctx, fz_image *image); void fz_set_compressed_image_buffer(fz_context *ctx, fz_compressed_image *cimg, fz_compressed_buffer *buf); -/* - fz_pixmap_image_tile: Retried the underlying fz_pixmap - for an image. +/** + Retrieve the underlying fz_pixmap for an image. Returns a pointer to the underlying fz_pixmap for an image, or NULL if this image is not based upon an fz_pixmap. @@ -328,4 +414,30 @@ void fz_set_compressed_image_buffer(fz_context *ctx, fz_compressed_image *cimg, fz_pixmap *fz_pixmap_image_tile(fz_context *ctx, fz_pixmap_image *cimg); void fz_set_pixmap_image_tile(fz_context *ctx, fz_pixmap_image *cimg, fz_pixmap *pix); +/* Implementation details: subject to change. */ + +/** + Exposed for PDF. +*/ +fz_pixmap *fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *cs); + +/** + Exposed because compression and decompression need to share this. +*/ +void opj_lock(fz_context *ctx); +void opj_unlock(fz_context *ctx); + + +/** + Exposed for CBZ. +*/ +int fz_load_tiff_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len); +fz_pixmap *fz_load_tiff_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage); +int fz_load_pnm_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len); +fz_pixmap *fz_load_pnm_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage); +int fz_load_jbig2_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len); +fz_pixmap *fz_load_jbig2_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage); +int fz_load_bmp_subimage_count(fz_context *ctx, const unsigned char *buf, size_t len); +fz_pixmap *fz_load_bmp_subimage(fz_context *ctx, const unsigned char *buf, size_t len, int subimage); + #endif diff --git a/include/mupdf/fitz/link.h b/include/mupdf/fitz/link.h index 3aa5116..1a20a22 100644 --- a/include/mupdf/fitz/link.h +++ b/include/mupdf/fitz/link.h @@ -1,17 +1,39 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_LINK_H #define MUPDF_FITZ_LINK_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" +#include "mupdf/fitz/types.h" -/* - Links -*/ +typedef struct fz_link fz_link; +typedef void (fz_link_set_rect_fn)(fz_context *ctx, fz_link *link, fz_rect rect); +typedef void (fz_link_set_uri_fn)(fz_context *ctx, fz_link *link, const char *uri); +typedef void (fz_link_drop_link_fn)(fz_context *ctx, fz_link *link); -typedef struct fz_link_s fz_link; - -/* +/** fz_link is a list of interactive links on a page. There is no relation between the order of the links in the @@ -30,26 +52,79 @@ typedef struct fz_link_s fz_link; next: A pointer to the next link on the same page. */ -struct fz_link_s +typedef struct fz_link { int refs; - fz_link *next; + struct fz_link *next; fz_rect rect; - void *doc; char *uri; -}; + fz_link_set_rect_fn *set_rect_fn; + fz_link_set_uri_fn *set_uri_fn; + fz_link_drop_link_fn *drop; +} fz_link; -fz_link *fz_new_link(fz_context *ctx, const fz_rect *bbox, void *doc, const char *uri); +typedef enum +{ + FZ_LINK_DEST_FIT, + FZ_LINK_DEST_FIT_B, + FZ_LINK_DEST_FIT_H, + FZ_LINK_DEST_FIT_BH, + FZ_LINK_DEST_FIT_V, + FZ_LINK_DEST_FIT_BV, + FZ_LINK_DEST_FIT_R, + FZ_LINK_DEST_XYZ +} fz_link_dest_type; + +typedef struct +{ + fz_location loc; + fz_link_dest_type type; + float x, y, w, h, zoom; +} fz_link_dest; + +fz_link_dest fz_make_link_dest_none(void); +fz_link_dest fz_make_link_dest_xyz(int chapter, int page, float x, float y, float z); + +/** + Create a new link record. + + next is set to NULL with the expectation that the caller will + handle the linked list setup. Internal function. + + Different document types will be implemented by deriving from + fz_link. This macro allocates such derived structures, and + initialises the base sections. +*/ +fz_link *fz_new_link_of_size(fz_context *ctx, int size, fz_rect rect, const char *uri); +#define fz_new_derived_link(CTX,TYPE,RECT,URI) \ + ((TYPE *)Memento_label(fz_new_link_of_size(CTX,sizeof(TYPE),RECT,URI),#TYPE)) + +/** + Increment the reference count for a link. The same pointer is + returned. + + Never throws exceptions. +*/ fz_link *fz_keep_link(fz_context *ctx, fz_link *link); -/* - Checks if a link destination is external or internal. -*/ -int fz_is_external_link(fz_context *ctx, const char *uri); +/** + Decrement the reference count for a link. When the reference + count reaches zero, the link is destroyed. -/* - fz_drop_link: Drop and free a list of links. + When a link is freed, the reference for any linked link (next) + is dropped too, thus an entire linked list of fz_link's can be + freed by just dropping the head. */ void fz_drop_link(fz_context *ctx, fz_link *link); +/** + Query whether a link is external to a document (determined by + uri containing a ':', intended to match with '://' which + separates the scheme from the scheme specific parts in URIs). +*/ +int fz_is_external_link(fz_context *ctx, const char *uri); + +void fz_set_link_rect(fz_context *ctx, fz_link *link, fz_rect rect); +void fz_set_link_uri(fz_context *ctx, fz_link *link, const char *uri); + #endif diff --git a/include/mupdf/fitz/log.h b/include/mupdf/fitz/log.h new file mode 100644 index 0000000..50892a0 --- /dev/null +++ b/include/mupdf/fitz/log.h @@ -0,0 +1,61 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_LOG_H +#define MUPDF_FITZ_LOG_H + +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/output.h" + +/** + The functions in this file offer simple logging abilities. + + The default logfile is "fitz_log.txt". This can overridden by + defining an environment variable "FZ_LOG_FILE", or module + specific environment variables "FZ_LOG_FILE_" (e.g. + "FZ_LOG_FILE_STORE"). + + Enable the following define(s) to enable built in debug logging + from within the appropriate module(s). +*/ + +/* #define ENABLE_STORE_LOGGING */ + + +/** + Output a line to the log. +*/ +void fz_log(fz_context *ctx, const char *fmt, ...); + +/** + Output a line to the log for a given module. +*/ +void fz_log_module(fz_context *ctx, const char *module, const char *fmt, ...); + +/** + Internal function to actually do the opening of the logfile. + + Caller should close/drop the output when finished with it. +*/ +fz_output *fz_new_log_for_module(fz_context *ctx, const char *module); + +#endif diff --git a/include/mupdf/fitz/outline.h b/include/mupdf/fitz/outline.h index 85ce2f2..6f5810c 100644 --- a/include/mupdf/fitz/outline.h +++ b/include/mupdf/fitz/outline.h @@ -1,14 +1,94 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_OUTLINE_H #define MUPDF_FITZ_OUTLINE_H #include "mupdf/fitz/system.h" +#include "mupdf/fitz/types.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/link.h" #include "mupdf/fitz/output.h" /* Outline */ -/* +typedef struct { + char *title; + char *uri; + int is_open; +} fz_outline_item; + +typedef struct fz_outline_iterator fz_outline_iterator; + +/** + Call to get the current outline item. + + Can return NULL. The item is only valid until the next call. +*/ +fz_outline_item *fz_outline_iterator_item(fz_context *ctx, fz_outline_iterator *iter); + +/** + Calls to move the iterator position. + + A negative return value means we could not move as requested. Otherwise: + 0 = the final position has a valid item. + 1 = not a valid item, but we can insert an item here. +*/ +int fz_outline_iterator_next(fz_context *ctx, fz_outline_iterator *iter); +int fz_outline_iterator_prev(fz_context *ctx, fz_outline_iterator *iter); +int fz_outline_iterator_up(fz_context *ctx, fz_outline_iterator *iter); +int fz_outline_iterator_down(fz_context *ctx, fz_outline_iterator *iter); + +/** + Call to insert a new item BEFORE the current point. + + Ownership of pointers are retained by the caller. The item data will be copied. + + After an insert, we do not change where we are pointing. + The return code is the same as for next, it indicates the current iterator position. +*/ +int fz_outline_iterator_insert(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item); + +/** + Delete the current item. + + This implicitly moves us to the 'next' item, and the return code is as for fz_outline_iterator_next. +*/ +int fz_outline_iterator_delete(fz_context *ctx, fz_outline_iterator *iter); + +/** + Update the current item properties according to the given item. +*/ +void fz_outline_iterator_update(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item); + +/** + Drop the current iterator. +*/ +void fz_drop_outline_iterator(fz_context *ctx, fz_outline_iterator *iter); + + +/** Structure based API */ + +/** fz_outline is a tree of the outline of a document (also known as table of contents). @@ -28,22 +108,121 @@ down: The outline items immediate children in the hierarchy. May be NULL if no children exist. */ -typedef struct fz_outline_s fz_outline; - -struct fz_outline_s +typedef struct fz_outline { int refs; char *title; char *uri; - int page; + fz_location page; float x, y; - fz_outline *next; - fz_outline *down; + struct fz_outline *next; + struct fz_outline *down; int is_open; -}; +} fz_outline; +/** + Create a new outline entry with zeroed fields for the caller + to fill in. +*/ fz_outline *fz_new_outline(fz_context *ctx); + +/** + Increment the reference count. Returns the same pointer. + + Never throws exceptions. +*/ fz_outline *fz_keep_outline(fz_context *ctx, fz_outline *outline); + +/** + Decrements the reference count. When the reference point + reaches zero, the outline is freed. + + When freed, it will drop linked outline entries (next and down) + too, thus a whole outline structure can be dropped by dropping + the top entry. + + Never throws exceptions. +*/ void fz_drop_outline(fz_context *ctx, fz_outline *outline); +/** + Routine to implement the old Structure based API from an iterator. +*/ +fz_outline * +fz_load_outline_from_iterator(fz_context *ctx, fz_outline_iterator *iter); + + +/** + Implementation details. + Of use to people coding new document handlers. +*/ + +/** + Function type for getting the current item. + + Can return NULL. The item is only valid until the next call. +*/ +typedef fz_outline_item *(fz_outline_iterator_item_fn)(fz_context *ctx, fz_outline_iterator *iter); + +/** + Function types for moving the iterator position. + + A negative return value means we could not move as requested. Otherwise: + 0 = the final position has a valid item. + 1 = not a valid item, but we can insert an item here. +*/ +typedef int (fz_outline_iterator_next_fn)(fz_context *ctx, fz_outline_iterator *iter); +typedef int (fz_outline_iterator_prev_fn)(fz_context *ctx, fz_outline_iterator *iter); +typedef int (fz_outline_iterator_up_fn)(fz_context *ctx, fz_outline_iterator *iter); +typedef int (fz_outline_iterator_down_fn)(fz_context *ctx, fz_outline_iterator *iter); + +/** + Function type for inserting a new item BEFORE the current point. + + Ownership of pointers are retained by the caller. The item data will be copied. + + After an insert, we implicitly do a next, so that a successive insert operation + would insert after the item inserted here. The return code is therefore as for next. +*/ +typedef int (fz_outline_iterator_insert_fn)(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item); + +/** + Function type for deleting the current item. + + This implicitly moves us to the 'next' item, and the return code is as for fz_outline_iterator_next. +*/ +typedef int (fz_outline_iterator_delete_fn)(fz_context *ctx, fz_outline_iterator *iter); + +/** + Function type for updating the current item properties according to the given item. +*/ +typedef void (fz_outline_iterator_update_fn)(fz_context *ctx, fz_outline_iterator *iter, fz_outline_item *item); + +/** + Function type for dropping the current iterator. +*/ +typedef void (fz_outline_iterator_drop_fn)(fz_context *ctx, fz_outline_iterator *iter); + +#define fz_new_derived_outline_iter(CTX, TYPE, DOC)\ + ((TYPE *)Memento_label(fz_new_outline_iterator_of_size(ctx,sizeof(TYPE),DOC),#TYPE)) + +fz_outline_iterator *fz_new_outline_iterator_of_size(fz_context *ctx, size_t size, fz_document *doc); + +fz_outline_iterator *fz_outline_iterator_from_outline(fz_context *ctx, fz_outline *outline); + +struct fz_outline_iterator { + /* Functions */ + fz_outline_iterator_drop_fn *drop; + fz_outline_iterator_item_fn *item; + fz_outline_iterator_next_fn *next; + fz_outline_iterator_prev_fn *prev; + fz_outline_iterator_up_fn *up; + fz_outline_iterator_down_fn *down; + fz_outline_iterator_insert_fn *insert; + fz_outline_iterator_update_fn *update; + fz_outline_iterator_delete_fn *del; + /* Common state */ + fz_document *doc; +}; + #endif diff --git a/include/mupdf/fitz/output-pcl.h b/include/mupdf/fitz/output-pcl.h deleted file mode 100644 index 3d6a033..0000000 --- a/include/mupdf/fitz/output-pcl.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PCL_H -#define MUPDF_FITZ_OUTPUT_PCL_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/bitmap.h" - -/* - PCL output -*/ -typedef struct fz_pcl_options_s fz_pcl_options; - -struct fz_pcl_options_s -{ - /* Features of a particular printer */ - int features; - const char *odd_page_init; - const char *even_page_init; - - /* Options for this job */ - int tumble; - int duplex_set; - int duplex; - int paper_size; - int manual_feed_set; - int manual_feed; - int media_position_set; - int media_position; - int orientation; - - /* Updated as we move through the job */ - int page_count; -}; - -/* - fz_pcl_preset: Initialize PCL option struct for a given preset. - - Currently defined presets include: - - generic Generic PCL printer - ljet4 HP DeskJet - dj500 HP DeskJet 500 - fs600 Kyocera FS-600 - lj HP LaserJet, HP LaserJet Plus - lj2 HP LaserJet IIp, HP LaserJet IId - lj3 HP LaserJet III - lj3d HP LaserJet IIId - lj4 HP LaserJet 4 - lj4pl HP LaserJet 4 PL - lj4d HP LaserJet 4d - lp2563b HP 2563B line printer - oce9050 Oce 9050 Line printer -*/ -void fz_pcl_preset(fz_context *ctx, fz_pcl_options *opts, const char *preset); - -/* - fz_parse_pcl_options: Parse PCL options. - - Currently defined options and values are as follows: - - preset=X Either "generic" or one of the presets as for fz_pcl_preset. - spacing=0 No vertical spacing capability - spacing=1 PCL 3 spacing (*p+Y) - spacing=2 PCL 4 spacing (*bY) - spacing=3 PCL 5 spacing (*bY and clear seed row) - mode2 Disable/Enable mode 2 graphics compression - mode3 Disable/Enable mode 3 graphics compression - eog_reset End of graphics (*rB) resets all parameters - has_duplex Duplex supported (&lS) - has_papersize Papersize setting supported (&lA) - has_copies Number of copies supported (&lX) - is_ljet4pjl Disable/Enable HP 4PJL model-specific output - is_oce9050 Disable/Enable Oce 9050 model-specific output -*/ -fz_pcl_options *fz_parse_pcl_options(fz_context *ctx, fz_pcl_options *opts, const char *args); - -fz_band_writer *fz_new_mono_pcl_band_writer(fz_context *ctx, fz_output *out, const fz_pcl_options *options); -void fz_write_bitmap_as_pcl(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pcl_options *pcl); -void fz_save_bitmap_as_pcl(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pcl_options *pcl); - -fz_band_writer *fz_new_color_pcl_band_writer(fz_context *ctx, fz_output *out, const fz_pcl_options *options); -void fz_write_pixmap_as_pcl(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pcl_options *pcl); -void fz_save_pixmap_as_pcl(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pcl_options *pcl); - -#endif diff --git a/include/mupdf/fitz/output-pclm.h b/include/mupdf/fitz/output-pclm.h deleted file mode 100644 index 74c811f..0000000 --- a/include/mupdf/fitz/output-pclm.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PCLM_H -#define MUPDF_FITZ_OUTPUT_PCLM_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/bitmap.h" - -/* - PCLm output -*/ -typedef struct fz_pclm_options_s fz_pclm_options; - -struct fz_pclm_options_s -{ - int compress; - int strip_height; - - /* Updated as we move through the job */ - int page_count; -}; - -/* - fz_parse_pclm_options: Parse PCLm options. - - Currently defined options and values are as follows: - - compression=none: No compression - compression=flate: Flate compression - strip-height=n: Strip height (default 16) -*/ -fz_pclm_options *fz_parse_pclm_options(fz_context *ctx, fz_pclm_options *opts, const char *args); - -fz_band_writer *fz_new_pclm_band_writer(fz_context *ctx, fz_output *out, const fz_pclm_options *options); -fz_document_writer *fz_new_pclm_writer(fz_context *ctx, const char *path, const char *options); -void fz_write_pixmap_as_pclm(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pclm_options *options); -void fz_save_pixmap_as_pclm(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pclm_options *options); - -#endif diff --git a/include/mupdf/fitz/output-png.h b/include/mupdf/fitz/output-png.h deleted file mode 100644 index 5c29911..0000000 --- a/include/mupdf/fitz/output-png.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PNG_H -#define MUPDF_FITZ_OUTPUT_PNG_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/bitmap.h" - -#include "mupdf/fitz/buffer.h" -#include "mupdf/fitz/image.h" - -/* - fz_save_pixmap_as_png: Save a pixmap as a PNG image file. -*/ -void fz_save_pixmap_as_png(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -/* - Write a pixmap to an output stream in PNG format. -*/ -void fz_write_pixmap_as_png(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap); - -/* - fz_new_png_band_writer: Obtain a fz_band_writer instance - for producing PNG output. -*/ -fz_band_writer *fz_new_png_band_writer(fz_context *ctx, fz_output *out); - -/* - Create a new buffer containing the image/pixmap in PNG format. -*/ -fz_buffer *fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image, const fz_color_params *color_params); -fz_buffer *fz_new_buffer_from_pixmap_as_png(fz_context *ctx, fz_pixmap *pixmap, const fz_color_params *color_params); - -#endif diff --git a/include/mupdf/fitz/output-pnm.h b/include/mupdf/fitz/output-pnm.h deleted file mode 100644 index 1301154..0000000 --- a/include/mupdf/fitz/output-pnm.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PNM_H -#define MUPDF_FITZ_OUTPUT_PNM_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/bitmap.h" - -/* - fz_save_pixmap_as_pnm: Save a pixmap as a PNM image file. -*/ -void fz_save_pixmap_as_pnm(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -void fz_write_pixmap_as_pnm(fz_context *ctx, fz_output *out, fz_pixmap *pixmap); - -fz_band_writer *fz_new_pnm_band_writer(fz_context *ctx, fz_output *out); - -/* - fz_save_pixmap_as_pam: Save a pixmap as a PAM image file. -*/ -void fz_save_pixmap_as_pam(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -void fz_write_pixmap_as_pam(fz_context *ctx, fz_output *out, fz_pixmap *pixmap); - -fz_band_writer *fz_new_pam_band_writer(fz_context *ctx, fz_output *out); - -/* - fz_save_bitmap_as_pbm: Save a bitmap as a PBM image file. -*/ -void fz_save_bitmap_as_pbm(fz_context *ctx, fz_bitmap *bitmap, const char *filename); - -void fz_write_bitmap_as_pbm(fz_context *ctx, fz_output *out, fz_bitmap *bitmap); - -fz_band_writer *fz_new_pbm_band_writer(fz_context *ctx, fz_output *out); - -void fz_save_pixmap_as_pbm(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -/* - fz_save_bitmap_as_pkm: Save a 4bpp cmyk bitmap as a PAM image file. -*/ -void fz_save_bitmap_as_pkm(fz_context *ctx, fz_bitmap *bitmap, const char *filename); - -void fz_write_bitmap_as_pkm(fz_context *ctx, fz_output *out, fz_bitmap *bitmap); - -fz_band_writer *fz_new_pkm_band_writer(fz_context *ctx, fz_output *out); - -void fz_save_pixmap_as_pkm(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -#endif diff --git a/include/mupdf/fitz/output-ps.h b/include/mupdf/fitz/output-ps.h deleted file mode 100644 index 7ece483..0000000 --- a/include/mupdf/fitz/output-ps.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PS_H -#define MUPDF_FITZ_OUTPUT_PS_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" - -/* - PS (image) output -*/ -void fz_write_pixmap_as_ps(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap); - -void fz_save_pixmap_as_ps(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append); - -void fz_write_ps_file_header(fz_context *ctx, fz_output *out); - -fz_band_writer *fz_new_ps_band_writer(fz_context *ctx, fz_output *out); - -void fz_write_ps_file_trailer(fz_context *ctx, fz_output *out, int pages); - -#endif diff --git a/include/mupdf/fitz/output-psd.h b/include/mupdf/fitz/output-psd.h deleted file mode 100644 index 94fc01b..0000000 --- a/include/mupdf/fitz/output-psd.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PSD_H -#define MUPDF_FITZ_OUTPUT_PSD_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/bitmap.h" - -#include "mupdf/fitz/buffer.h" -#include "mupdf/fitz/image.h" - -/* - fz_save_pixmap_as_psd: Save a pixmap as a PSD image file. -*/ -void fz_save_pixmap_as_psd(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -/* - Write a pixmap to an output stream in PSD format. -*/ -void fz_write_pixmap_as_psd(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap); - -/* - fz_new_psd_band_writer: Obtain a fz_band_writer instance - for producing PSD output. -*/ -fz_band_writer *fz_new_psd_band_writer(fz_context *ctx, fz_output *out); - -#endif diff --git a/include/mupdf/fitz/output-pwg.h b/include/mupdf/fitz/output-pwg.h deleted file mode 100644 index 54363e0..0000000 --- a/include/mupdf/fitz/output-pwg.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_PWG_H -#define MUPDF_FITZ_OUTPUT_PWG_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" -#include "mupdf/fitz/bitmap.h" - -typedef struct fz_pwg_options_s fz_pwg_options; - -struct fz_pwg_options_s -{ - /* These are not interpreted as CStrings by the writing code, but - * are rather copied directly out. */ - char media_class[64]; - char media_color[64]; - char media_type[64]; - char output_type[64]; - - unsigned int advance_distance; - int advance_media; - int collate; - int cut_media; - int duplex; - int insert_sheet; - int jog; - int leading_edge; - int manual_feed; - unsigned int media_position; - unsigned int media_weight; - int mirror_print; - int negative_print; - unsigned int num_copies; - int orientation; - int output_face_up; - unsigned int PageSize[2]; - int separations; - int tray_switch; - int tumble; - - int media_type_num; - int compression; - unsigned int row_count; - unsigned int row_feed; - unsigned int row_step; - - /* These are not interpreted as CStrings by the writing code, but - * are rather copied directly out. */ - char rendering_intent[64]; - char page_size_name[64]; -}; - -/* - fz_save_pixmap_as_pwg: Save a pixmap as a pwg - - filename: The filename to save as (including extension). - - append: If non-zero, then append a new page to existing file. - - pwg: NULL, or a pointer to an options structure (initialised to zero - before being filled in, for future expansion). -*/ -void fz_save_pixmap_as_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pwg_options *pwg); - -/* - fz_save_bitmap_as_pwg: Save a bitmap as a pwg - - filename: The filename to save as (including extension). - - append: If non-zero, then append a new page to existing file. - - pwg: NULL, or a pointer to an options structure (initialised to zero - before being filled in, for future expansion). -*/ -void fz_save_bitmap_as_pwg(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pwg_options *pwg); - -/* - Output a pixmap to an output stream as a pwg raster. -*/ -void fz_write_pixmap_as_pwg(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg); - -/* - Output a bitmap to an output stream as a pwg raster. -*/ -void fz_write_bitmap_as_pwg(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg); - -/* - Output the file header to a pwg stream, ready for pages to follow it. -*/ -void fz_write_pwg_file_header(fz_context *ctx, fz_output *out); - -/* - Output a page to a pwg stream to follow a header, or other pages. -*/ -void fz_write_pixmap_as_pwg_page(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg); - -/* - Output a bitmap page to a pwg stream to follow a header, or other pages. -*/ -void fz_write_bitmap_as_pwg_page(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg); - -/* - fz_new_mono_pwg_band_writer: Generate a new band writer for - PWG format images. -*/ -fz_band_writer *fz_new_mono_pwg_band_writer(fz_context *ctx, fz_output *out, const fz_pwg_options *pwg); - -/* - fz_new_pwg_band_writer: Generate a new band writer for - contone PWG format images. -*/ -fz_band_writer *fz_new_pwg_band_writer(fz_context *ctx, fz_output *out, const fz_pwg_options *pwg); - -#endif diff --git a/include/mupdf/fitz/output-svg.h b/include/mupdf/fitz/output-svg.h index 16e2102..b1b07ab 100644 --- a/include/mupdf/fitz/output-svg.h +++ b/include/mupdf/fitz/output-svg.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_OUTPUT_SVG_H #define MUPDF_FITZ_OUTPUT_SVG_H @@ -11,20 +33,32 @@ enum { FZ_SVG_TEXT_AS_TEXT = 1, }; -/* - fz_new_svg_device: Create a device that outputs (single page) - SVG files to the given output stream. +/** + Create a device that outputs (single page) SVG files to + the given output stream. + + Equivalent to fz_new_svg_device_with_id passing id = NULL. +*/ +fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format, int reuse_images); + +/** + Create a device that outputs (single page) SVG files to + the given output stream. output: The output stream to send the constructed SVG page to. page_width, page_height: The page dimensions to use (in points). text_format: How to emit text. One of the following values: - FZ_SVG_TEXT_AS_TEXT: As elements with possible layout errors and mismatching fonts. - FZ_SVG_TEXT_AS_PATH: As elements with exact visual appearance. + FZ_SVG_TEXT_AS_TEXT: As elements with possible + layout errors and mismatching fonts. + FZ_SVG_TEXT_AS_PATH: As elements with exact + visual appearance. reuse_images: Share image resources using definitions. + + id: ID parameter to keep generated IDs unique across SVG files. */ -fz_device *fz_new_svg_device(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format, int reuse_images); +fz_device *fz_new_svg_device_with_id(fz_context *ctx, fz_output *out, float page_width, float page_height, int text_format, int reuse_images, int *id); #endif diff --git a/include/mupdf/fitz/output-tga.h b/include/mupdf/fitz/output-tga.h deleted file mode 100644 index 4684a0d..0000000 --- a/include/mupdf/fitz/output-tga.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef MUPDF_FITZ_OUTPUT_TGA_H -#define MUPDF_FITZ_OUTPUT_TGA_H - -#include "mupdf/fitz/system.h" -#include "mupdf/fitz/context.h" -#include "mupdf/fitz/output.h" -#include "mupdf/fitz/band-writer.h" -#include "mupdf/fitz/pixmap.h" - -/* - fz_save_pixmap_as_tga: Save a pixmap as a TGA image file. - Can accept RGB, BGR or Grayscale pixmaps, with or without - alpha. -*/ -void fz_save_pixmap_as_tga(fz_context *ctx, fz_pixmap *pixmap, const char *filename); - -/* - Write a pixmap to an output stream in TGA format. - Can accept RGB, BGR or Grayscale pixmaps, with or without - alpha. -*/ -void fz_write_pixmap_as_tga(fz_context *ctx, fz_output *out, fz_pixmap *pixmap); - -/* - fz_new_tga_band_writer: Generate a new band writer for TGA - format images. Note that image must be generated vertically - flipped for use with this writer! - - Can accept RGB, BGR or Grayscale pixmaps, with or without - alpha. - - is_bgr: True, if the image is generated in bgr format. -*/ -fz_band_writer *fz_new_tga_band_writer(fz_context *ctx, fz_output *out, int is_bgr); - - -#endif diff --git a/include/mupdf/fitz/output.h b/include/mupdf/fitz/output.h index c3fede3..ee3d099 100644 --- a/include/mupdf/fitz/output.h +++ b/include/mupdf/fitz/output.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_OUTPUT_H #define MUPDF_FITZ_OUTPUT_H @@ -7,14 +29,13 @@ #include "mupdf/fitz/string-util.h" #include "mupdf/fitz/stream.h" -/* - Generic output streams - generalise between outputting to a file, - a buffer, etc. +/** + Generic output streams - generalise between outputting to a + file, a buffer, etc. */ -typedef struct fz_output_s fz_output; -/* - fz_output_write_fn: A function type for use when implementing +/** + A function type for use when implementing fz_outputs. The supplied function of this type is called whenever data is written to the output. @@ -26,19 +47,19 @@ typedef struct fz_output_s fz_output; */ typedef void (fz_output_write_fn)(fz_context *ctx, void *state, const void *data, size_t n); -/* - fz_output_seek_fn: A function type for use when implementing +/** + A function type for use when implementing fz_outputs. The supplied function of this type is called when fz_seek_output is requested. state: The output stream state to seek within. - offset, whence: as defined for fs_seek_output. + offset, whence: as defined for fz_seek(). */ typedef void (fz_output_seek_fn)(fz_context *ctx, void *state, int64_t offset, int whence); -/* - fz_output_tell_fn: A function type for use when implementing +/** + A function type for use when implementing fz_outputs. The supplied function of this type is called when fz_tell_output is requested. @@ -48,30 +69,45 @@ typedef void (fz_output_seek_fn)(fz_context *ctx, void *state, int64_t offset, i */ typedef int64_t (fz_output_tell_fn)(fz_context *ctx, void *state); -/* - fz_output_close_fn: A function type for use when implementing +/** + A function type for use when implementing fz_outputs. The supplied function of this type is called when the output stream is closed, to flush any pending writes. */ typedef void (fz_output_close_fn)(fz_context *ctx, void *state); -/* - fz_output_drop_fn: A function type for use when implementing +/** + A function type for use when implementing fz_outputs. The supplied function of this type is called - when the output stream is dropped, to release the stream specific - state information. + when the output stream is reset, and resets the state + to that when it was first initialised. +*/ +typedef void (fz_output_reset_fn)(fz_context *ctx, void *state); + +/** + A function type for use when implementing + fz_outputs. The supplied function of this type is called + when the output stream is dropped, to release the stream + specific state information. */ typedef void (fz_output_drop_fn)(fz_context *ctx, void *state); -/* - fz_stream_from_output_fn: A function type for use when implementing +/** + A function type for use when implementing fz_outputs. The supplied function of this type is called when the fz_stream_from_output is called. */ typedef fz_stream *(fz_stream_from_output_fn)(fz_context *ctx, void *state); +/** + A function type for use when implementing + fz_outputs. The supplied function of this type is called + when fz_truncate_output is called to truncate the file + at that point. +*/ +typedef void (fz_truncate_fn)(fz_context *ctx, void *state); -struct fz_output_s +struct fz_output { void *state; fz_output_write_fn *write; @@ -79,12 +115,19 @@ struct fz_output_s fz_output_tell_fn *tell; fz_output_close_fn *close; fz_output_drop_fn *drop; + fz_output_reset_fn *reset; fz_stream_from_output_fn *as_stream; + fz_truncate_fn *truncate; + int closed; char *bp, *wp, *ep; + /* If buffered is non-zero, then we have that many + * bits (1-7) waiting to be written in bits. */ + int buffered; + int bits; }; -/* - fz_new_output: Create a new output object with the given +/** + Create a new output object with the given internal state and function pointers. state: Internal state (opaque to everything but implementation). @@ -96,8 +139,8 @@ struct fz_output_s */ fz_output *fz_new_output(fz_context *ctx, int bufsiz, void *state, fz_output_write_fn *write, fz_output_close_fn *close, fz_output_drop_fn *drop); -/* - fz_new_output_with_path: Open an output stream that writes to a +/** + Open an output stream that writes to a given path. filename: The filename to write to (specified in UTF-8). @@ -107,207 +150,262 @@ fz_output *fz_new_output(fz_context *ctx, int bufsiz, void *state, fz_output_wri */ fz_output *fz_new_output_with_path(fz_context *, const char *filename, int append); -/* - fz_new_output_with_buffer: Open an output stream that appends +/** + Open an output stream that writes to a + given FILE *. + + file: The file pointers to write to. NULL is interpreted as effectively + meaning /dev/null or similar. +*/ +fz_output *fz_new_output_with_file_ptr(fz_context *ctx, FILE *file); + +/** + Open an output stream that appends to a buffer. buf: The buffer to append to. */ fz_output *fz_new_output_with_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_stdout: The standard out output stream. By default - this stream writes to stdout. This may be overridden - using fz_set_stdout. +/** + Retrieve an fz_output that directs to stdout. + + Optionally may be fz_dropped when finished with. */ fz_output *fz_stdout(fz_context *ctx); -/* - fz_stderr: The standard error output stream. By default - this stream writes to stderr. This may be overridden - using fz_set_stderr. +/** + Retrieve an fz_output that directs to stdout. + + Optionally may be fz_dropped when finished with. */ fz_output *fz_stderr(fz_context *ctx); -/* - fz_set_stdout: Replace default standard output stream - with a given stream. +#ifdef _WIN32 +/** + Retrieve an fz_output that directs to OutputDebugString. - out: The new stream to use. + Optionally may be fz_dropped when finished with. */ -void fz_set_stdout(fz_context *ctx, fz_output *out); +fz_output *fz_stdods(fz_context *ctx); +#endif -/* - fz_set_stderr: Replace default standard error stream - with a given stream. - - err: The new stream to use. +/** + Set the output stream to be used for fz_stddbg. Set to NULL to + reset to default (stderr). */ -void fz_set_stderr(fz_context *ctx, fz_output *err); +void fz_set_stddbg(fz_context *ctx, fz_output *out); -/* - fz_write_printf: Format and write data to an output stream. - See fz_vsnprintf for formatting details. +/** + Retrieve an fz_output for the default debugging stream. On + Windows this will be OutputDebugString for non-console apps. + Otherwise, it is always fz_stderr. + + Optionally may be fz_dropped when finished with. +*/ +fz_output *fz_stddbg(fz_context *ctx); + +/** + Format and write data to an output stream. + See fz_format_string for formatting details. */ void fz_write_printf(fz_context *ctx, fz_output *out, const char *fmt, ...); -/* - fz_write_vprintf: va_list version of fz_write_printf. +/** + va_list version of fz_write_printf. */ void fz_write_vprintf(fz_context *ctx, fz_output *out, const char *fmt, va_list ap); -/* - fz_seek_output: Seek to the specified file position. +/** + Seek to the specified file position. See fseek for arguments. Throw an error on unseekable outputs. */ void fz_seek_output(fz_context *ctx, fz_output *out, int64_t off, int whence); -/* - fz_tell_output: Return the current file position. +/** + Return the current file position. Throw an error on untellable outputs. */ int64_t fz_tell_output(fz_context *ctx, fz_output *out); -/* - fz_flush_output: Flush unwritten data. +/** + Flush unwritten data. */ void fz_flush_output(fz_context *ctx, fz_output *out); -/* - fz_close_output: Flush pending output and close an output stream. +/** + Flush pending output and close an output stream. */ void fz_close_output(fz_context *, fz_output *); -/* - fz_drop_output: Free an output stream. Don't forget to close it first! +/** + Reset a closed output stream. Returns state to + (broadly) that which it was in when opened. Not + all outputs can be reset, so this may throw an + exception. +*/ +void fz_reset_output(fz_context *, fz_output *); + +/** + Free an output stream. Don't forget to close it first! */ void fz_drop_output(fz_context *, fz_output *); -/* - fz_stream_from_output: obtain the fz_output in the form of a fz_stream +/** + Query whether a given fz_output supports fz_stream_from_output. +*/ +int fz_output_supports_stream(fz_context *ctx, fz_output *out); - This allows data to be read back from some forms of fz_output object. - When finished reading, the fz_stream should be released by calling - fz_drop_stream. Until the fz_stream is dropped, no further operations - should be performed on the fz_output object. +/** + Obtain the fz_output in the form of a fz_stream. + + This allows data to be read back from some forms of fz_output + object. When finished reading, the fz_stream should be released + by calling fz_drop_stream. Until the fz_stream is dropped, no + further operations should be performed on the fz_output object. */ fz_stream *fz_stream_from_output(fz_context *, fz_output *); -/* - fz_write_data: Write data to output. +/** + Truncate the output at the current position. + + This allows output streams which have seeked back from the end + of their storage to be truncated at the current point. +*/ +void fz_truncate_output(fz_context *, fz_output *); + +/** + Write data to output. data: Pointer to data to write. size: Size of data to write in bytes. */ void fz_write_data(fz_context *ctx, fz_output *out, const void *data, size_t size); +void fz_write_buffer(fz_context *ctx, fz_output *out, fz_buffer *data); -/* - fz_write_string: Write a string. Does not write zero terminator. +/** + Write a string. Does not write zero terminator. */ void fz_write_string(fz_context *ctx, fz_output *out, const char *s); -/* - fz_write_int32_be: Write a big-endian 32-bit binary integer. +/** + Write different sized data to an output stream. */ void fz_write_int32_be(fz_context *ctx, fz_output *out, int x); - -/* - fz_write_int32_le: Write a little-endian 32-bit binary integer. -*/ void fz_write_int32_le(fz_context *ctx, fz_output *out, int x); - -/* - fz_write_int16_be: Write a big-endian 16-bit binary integer. -*/ +void fz_write_uint32_be(fz_context *ctx, fz_output *out, unsigned int x); +void fz_write_uint32_le(fz_context *ctx, fz_output *out, unsigned int x); void fz_write_int16_be(fz_context *ctx, fz_output *out, int x); - -/* - fz_write_int16_le: Write a little-endian 16-bit binary integer. -*/ void fz_write_int16_le(fz_context *ctx, fz_output *out, int x); - -/* - fz_write_byte: Write a single byte. -*/ +void fz_write_uint16_be(fz_context *ctx, fz_output *out, unsigned int x); +void fz_write_uint16_le(fz_context *ctx, fz_output *out, unsigned int x); +void fz_write_char(fz_context *ctx, fz_output *out, char x); void fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x); +void fz_write_float_be(fz_context *ctx, fz_output *out, float f); +void fz_write_float_le(fz_context *ctx, fz_output *out, float f); -/* - fz_write_rune: Write a UTF-8 encoded unicode character. +/** + Write a UTF-8 encoded unicode character. */ void fz_write_rune(fz_context *ctx, fz_output *out, int rune); -/* - fz_write_base64: Write base64 encoded data. +/** + Write a base64 encoded data block, optionally with periodic + newlines. +*/ +void fz_write_base64(fz_context *ctx, fz_output *out, const unsigned char *data, size_t size, int newline); + +/** + Write a base64 encoded fz_buffer, optionally with periodic + newlines. */ -void fz_write_base64(fz_context *ctx, fz_output *out, const unsigned char *data, int size, int newline); void fz_write_base64_buffer(fz_context *ctx, fz_output *out, fz_buffer *data, int newline); -/* - fz_format_string: Our customised 'printf'-like string formatter. - Takes %c, %d, %s, %u, %x, as usual. - Modifiers are not supported except for zero-padding ints (e.g. %02d, %03u, %04x, etc). - %g output in "as short as possible hopefully lossless non-exponent" form, - see fz_ftoa for specifics. +/** + Write num_bits of data to the end of the output stream, assumed to be packed + most significant bits first. +*/ +void fz_write_bits(fz_context *ctx, fz_output *out, unsigned int data, int num_bits); + +/** + Sync to byte boundary after writing bits. +*/ +void fz_write_bits_sync(fz_context *ctx, fz_output *out); + +/** + Copy the stream contents to the output. +*/ +void fz_write_stream(fz_context *ctx, fz_output *out, fz_stream *in); + +/** + Our customised 'printf'-like string formatter. + Takes %c, %d, %s, %u, %x, %X as usual. + Modifiers are not supported except for zero-padding ints (e.g. + %02d, %03u, %04x, etc). + %g output in "as short as possible hopefully lossless + non-exponent" form, see fz_ftoa for specifics. %f and %e output as usual. %C outputs a utf8 encoded int. - %M outputs a fz_matrix*. %R outputs a fz_rect*. %P outputs a fz_point*. + %M outputs a fz_matrix*. + %R outputs a fz_rect*. + %P outputs a fz_point*. + %n outputs a PDF name (with appropriate escaping). %q and %( output escaped strings in C/PDF syntax. - %l{d,u,x} indicates that the values are int64_t. - %z{d,u,x} indicates that the value is a size_t. + %l{d,u,x,X} indicates that the values are int64_t. + %z{d,u,x,X} indicates that the value is a size_t. user: An opaque pointer that is passed to the emit function. - emit: A function pointer called to emit output bytes as the string is being formatted. -*/ -void -fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args); -/* - fz_vsnprintf: A vsnprintf work-alike, using our custom formatter. + emit: A function pointer called to emit output bytes as the + string is being formatted. +*/ +void fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args); + +/** + A vsnprintf work-alike, using our custom formatter. */ size_t fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args); -/* - fz_snprintf: The non va_list equivalent of fz_vsnprintf. +/** + The non va_list equivalent of fz_vsnprintf. */ size_t fz_snprintf(char *buffer, size_t space, const char *fmt, ...); -/* - fz_asprintf: Print to allocated string. +/** + Allocated sprintf. + + Returns a null terminated allocated block containing the + formatted version of the format string/args. */ char *fz_asprintf(fz_context *ctx, const char *fmt, ...); -/* - fz_tempfilename: Get a temporary filename based upon 'base'. - - 'hint' is the path of a file (normally the existing document file) - supplied to give the function an idea of what directory to use. This - may or may not be used depending on the implementation's whim. - - The returned path must be freed. -*/ -char *fz_tempfilename(fz_context *ctx, const char *base, const char *hint); - -/* - fz_save_buffer: Save contents of a buffer to file. +/** + Save the contents of a buffer to a file. */ void fz_save_buffer(fz_context *ctx, fz_buffer *buf, const char *filename); -/* +/** Compression and other filtering outputs. - These outputs write encoded data to another output. Create a filter - output with the destination, write to the filter, then drop it when - you're done. These can also be chained together, for example to write - ASCII Hex encoded, Deflate compressed, and RC4 encrypted data to a - buffer output. + These outputs write encoded data to another output. Create a + filter output with the destination, write to the filter, then + close and drop it when you're done. These can also be chained + together, for example to write ASCII Hex encoded, Deflate + compressed, and RC4 encrypted data to a buffer output. - Output streams don't use reference counting, so make sure to drop all - of the filters in the reverse order of creation so that data is flushed - properly. + Output streams don't use reference counting, so make sure to + close all of the filters in the reverse order of creation so + that data is flushed properly. + + Accordingly, ownership of 'chain' is never passed into the + following functions, but remains with the caller, whose + responsibility it is to ensure they exist at least until + the returned fz_output is dropped. */ + fz_output *fz_new_asciihex_output(fz_context *ctx, fz_output *chain); fz_output *fz_new_ascii85_output(fz_context *ctx, fz_output *chain); fz_output *fz_new_rle_output(fz_context *ctx, fz_output *chain); diff --git a/include/mupdf/fitz/path.h b/include/mupdf/fitz/path.h index 47e8084..78c9b08 100644 --- a/include/mupdf/fitz/path.h +++ b/include/mupdf/fitz/path.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_PATH_H #define MUPDF_FITZ_PATH_H @@ -5,7 +27,7 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" -/* +/** * Vector path buffer. * It can be stroked and dashed, or be filled. * It has a fill rule (nonzero or even_odd). @@ -14,10 +36,9 @@ * into the Global Edge List. */ -typedef struct fz_path_s fz_path; -typedef struct fz_stroke_state_s fz_stroke_state; +typedef struct fz_path fz_path; -typedef enum fz_linecap_e +typedef enum { FZ_LINECAP_BUTT = 0, FZ_LINECAP_ROUND = 1, @@ -25,7 +46,7 @@ typedef enum fz_linecap_e FZ_LINECAP_TRIANGLE = 3 } fz_linecap; -typedef enum fz_linejoin_e +typedef enum { FZ_LINEJOIN_MITER = 0, FZ_LINEJOIN_ROUND = 1, @@ -33,7 +54,7 @@ typedef enum fz_linejoin_e FZ_LINEJOIN_MITER_XPS = 3 } fz_linejoin; -struct fz_stroke_state_s +typedef struct { int refs; fz_linecap start_cap, dash_cap, end_cap; @@ -43,7 +64,7 @@ struct fz_stroke_state_s float dash_phase; int dash_len; float dash_list[32]; -}; +} fz_stroke_state; typedef struct { @@ -59,8 +80,8 @@ typedef struct void (*rectto)(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2); } fz_path_walker; -/* - fz_walk_path: Walk the segments of a path, calling the +/** + Walk the segments of a path, calling the appropriate callback function from a given set for each segment of the path. @@ -79,59 +100,50 @@ typedef struct */ void fz_walk_path(fz_context *ctx, const fz_path *path, const fz_path_walker *walker, void *arg); -/* - fz_new_path: Create an empty path, and return - a reference to it. - - Throws exception on failure to allocate. +/** + Create a new (empty) path structure. */ fz_path *fz_new_path(fz_context *ctx); -/* - fz_keep_path: Take an additional reference to - a path. +/** + Increment the reference count. Returns the same pointer. - No modifications should be carried out on a path - to which more than one reference is held, as - this can cause race conditions. + All paths can be kept, regardless of their packing type. Never throws exceptions. */ fz_path *fz_keep_path(fz_context *ctx, const fz_path *path); -/* - fz_drop_path: Drop a reference to a path, - destroying the path if it is the last - reference. +/** + Decrement the reference count. When the reference count hits + zero, free the path. + + All paths can be dropped, regardless of their packing type. + Packed paths do not own the blocks into which they are packed + so dropping them does not free those blocks. Never throws exceptions. */ void fz_drop_path(fz_context *ctx, const fz_path *path); -/* - fz_trim_path: Minimise the internal storage - used by a path. +/** + Minimise the internal storage used by a path. As paths are constructed, the internal buffers grow. To avoid repeated reallocations they grow with some spare space. Once a path has been fully constructed, this call allows the excess space to be trimmed. - - Never throws exceptions. */ void fz_trim_path(fz_context *ctx, fz_path *path); -/* - fz_packed_path_size: Return the number of - bytes required to pack a path. - - Never throws exceptions. +/** + Return the number of bytes required to pack a path. */ int fz_packed_path_size(const fz_path *path); -/* - fz_pack_path: Pack a path into the given block. +/** + Pack a path into the given block. To minimise the size of paths, this function allows them to be packed into a buffer with other information. Paths can be used interchangeably regardless of how they are packed. @@ -140,28 +152,20 @@ int fz_packed_path_size(const fz_path *path); be aligned by the caller to the same alignment as required for a fz_path pointer. - max: The number of bytes available in the block. - If max < sizeof(fz_path) then an exception will - be thrown. If max >= the value returned by - fz_packed_path_size, then this call will never - fail, except in low memory situations with large - paths. - path: The path to pack. Returns the number of bytes within the block used. Callers can access the packed path data by casting the value of pack on entry to be a fz_path *. - Throws exceptions on failure to allocate, or if - max < sizeof(fz_path). + Throws exceptions on failure to allocate. Implementation details: Paths can be 'unpacked', 'flat', or - 'open'. Standard paths, as created are 'unpacked'. Paths that - will pack into less than max bytes will be packed as 'flat', - unless they are too large (where large indicates that they - exceed some private implementation defined limits, currently - including having more than 256 coordinates or commands). + 'open'. Standard paths, as created are 'unpacked'. Paths + will be packed as 'flat', unless they are too large + (where large indicates that they exceed some private + implementation defined limits, currently including having + more than 256 coordinates or commands). Large paths are 'open' packed as a header into the given block, plus pointers to other data blocks. @@ -170,10 +174,10 @@ int fz_packed_path_size(const fz_path *path); or 'flat' packed. Simply pack a path (if required), and then forget about the details. */ -int fz_pack_path(fz_context *ctx, uint8_t *pack, int max, const fz_path *path); +size_t fz_pack_path(fz_context *ctx, uint8_t *pack, const fz_path *path); -/* - fz_clone_path: Clone the data for a path. +/** + Clone the data for a path. This is used in preference to fz_keep_path when a whole new copy of a path is required, rather than just a shared @@ -186,39 +190,41 @@ int fz_pack_path(fz_context *ctx, uint8_t *pack, int max, const fz_path *path); */ fz_path *fz_clone_path(fz_context *ctx, fz_path *path); -/* - fz_currentpoint: Return the current point that a path has +/** + Return the current point that a path has reached or (0,0) if empty. path: path to return the current point of. */ fz_point fz_currentpoint(fz_context *ctx, fz_path *path); -/* - fz_moveto: Append a 'moveto' command to a path. +/** + Append a 'moveto' command to a path. This 'opens' a path. path: The path to modify. x, y: The coordinate to move to. - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_moveto(fz_context *ctx, fz_path *path, float x, float y); -/* - fz_lineto: Append a 'lineto' command to an open path. +/** + Append a 'lineto' command to an open path. path: The path to modify. x, y: The coordinate to line to. - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_lineto(fz_context *ctx, fz_path *path, float x, float y); -/* - fz_rectto: Append a 'rectto' command to an open path. +/** + Append a 'rectto' command to an open path. The rectangle is equivalent to: moveto x0 y0 @@ -233,12 +239,13 @@ void fz_lineto(fz_context *ctx, fz_path *path, float x, float y); x1, y1: Second corner of the rectangle. - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_rectto(fz_context *ctx, fz_path *path, float x0, float y0, float x1, float y1); -/* - fz_quadto: Append a 'quadto' command to an open path. (For a +/** + Append a 'quadto' command to an open path. (For a quadratic bezier). path: The path to modify. @@ -247,12 +254,13 @@ void fz_rectto(fz_context *ctx, fz_path *path, float x0, float y0, float x1, flo x1, y1: The end coordinates for the quadratic curve. - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_quadto(fz_context *ctx, fz_path *path, float x0, float y0, float x1, float y1); -/* - fz_curveto: Append a 'curveto' command to an open path. (For a +/** + Append a 'curveto' command to an open path. (For a cubic bezier). path: The path to modify. @@ -265,12 +273,13 @@ void fz_quadto(fz_context *ctx, fz_path *path, float x0, float y0, float x1, flo x2, y2: The end coordinates for the curve. - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_curveto(fz_context *ctx, fz_path *path, float x0, float y0, float x1, float y1, float x2, float y2); -/* - fz_curvetov: Append a 'curvetov' command to an open path. (For a +/** + Append a 'curvetov' command to an open path. (For a cubic bezier with the first control coordinate equal to the start point). @@ -281,12 +290,13 @@ void fz_curveto(fz_context *ctx, fz_path *path, float x0, float y0, float x1, fl x2, y2: The end coordinates for the curve. - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_curvetov(fz_context *ctx, fz_path *path, float x1, float y1, float x2, float y2); -/* - fz_curvetoy: Append a 'curvetoy' command to an open path. (For a +/** + Append a 'curvetoy' command to an open path. (For a cubic bezier with the second control coordinate equal to the end point). @@ -298,22 +308,24 @@ void fz_curvetov(fz_context *ctx, fz_path *path, float x1, float y1, float x2, f x2, y2: The end coordinates for the curve (and the second control coordinate). - Throws exceptions on failure to allocate. + Throws exceptions on failure to allocate, or attempting to + modify a packed path. */ void fz_curvetoy(fz_context *ctx, fz_path *path, float x0, float y0, float x2, float y2); -/* - fz_closepath: Close the current subpath. +/** + Close the current subpath. path: The path to modify. - Throws exceptions on failure to allocate, and illegal - path closes (i.e. closing a non open path). + Throws exceptions on failure to allocate, attempting to modify + a packed path, and illegal path closes (i.e. closing a non open + path). */ void fz_closepath(fz_context *ctx, fz_path *path); -/* - fz_transform_path: Transform a path by a given +/** + Transform a path by a given matrix. path: The path to modify (must not be a packed path). @@ -323,10 +335,10 @@ void fz_closepath(fz_context *ctx, fz_path *path); Throws exceptions if the path is packed, or on failure to allocate. */ -void fz_transform_path(fz_context *ctx, fz_path *path, const fz_matrix *transform); +void fz_transform_path(fz_context *ctx, fz_path *path, fz_matrix transform); -/* - fz_bound_path: Return a bounding rectangle for a path. +/** + Return a bounding rectangle for a path. path: The path to bound. @@ -341,23 +353,32 @@ void fz_transform_path(fz_context *ctx, fz_path *path, const fz_matrix *transfor Returns r, updated to contain the bounding rectangle. */ -fz_rect *fz_bound_path(fz_context *ctx, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *r); -fz_rect *fz_adjust_rect_for_stroke(fz_context *ctx, fz_rect *r, const fz_stroke_state *stroke, const fz_matrix *ctm); +fz_rect fz_bound_path(fz_context *ctx, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm); -extern const fz_stroke_state fz_default_stroke_state; +/** + Given a rectangle (assumed to be the bounding box for a path), + expand it to allow for the expansion of the bbox that would be + seen by stroking the path with the given stroke state and + transform. +*/ +fz_rect fz_adjust_rect_for_stroke(fz_context *ctx, fz_rect rect, const fz_stroke_state *stroke, fz_matrix ctm); -/* - fz_new_stroke_state: Create a new (empty) stroke state - structure (with no dash data) and return a reference to it. +/** + A sane 'default' stroke state. +*/ +FZ_DATA extern const fz_stroke_state fz_default_stroke_state; + +/** + Create a new (empty) stroke state structure (with no dash + data) and return a reference to it. Throws exception on failure to allocate. */ fz_stroke_state *fz_new_stroke_state(fz_context *ctx); -/* - fz_new_stroke_state_with_dash_len: Create a new (empty) - stroke state structure, with room for dash data of the - given length, and return a reference to it. +/** + Create a new (empty) stroke state structure, with room for + dash data of the given length, and return a reference to it. len: The number of dash elements to allow room for. @@ -365,31 +386,24 @@ fz_stroke_state *fz_new_stroke_state(fz_context *ctx); */ fz_stroke_state *fz_new_stroke_state_with_dash_len(fz_context *ctx, int len); -/* - fz_keep_stroke_state: Take an additional reference to - a stroke state structure. +/** + Take an additional reference to a stroke state structure. No modifications should be carried out on a stroke state to which more than one reference is held, as this can cause race conditions. - - Never throws exceptions. */ fz_stroke_state *fz_keep_stroke_state(fz_context *ctx, const fz_stroke_state *stroke); -/* - fz_drop_stroke_state: Drop a reference to a stroke - state structure, destroying the structure if it is - the last reference. - - Never throws exceptions. +/** + Drop a reference to a stroke state structure, destroying the + structure if it is the last reference. */ void fz_drop_stroke_state(fz_context *ctx, const fz_stroke_state *stroke); -/* - fz_unshare_stroke_state: Given a reference to a - (possibly) shared stroke_state structure, return - a reference to an equivalent stroke_state structure +/** + Given a reference to a (possibly) shared stroke_state structure, + return a reference to an equivalent stroke_state structure that is guaranteed to be unshared (i.e. one that can safely be modified). @@ -403,12 +417,11 @@ void fz_drop_stroke_state(fz_context *ctx, const fz_stroke_state *stroke); */ fz_stroke_state *fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *shared); -/* - fz_unshare_stroke_state_with_dash_len: Given a reference to a - (possibly) shared stroke_state structure, return a reference - to a stroke_state structure (with room for a given amount of - dash data) that is guaranteed to be unshared (i.e. one that - can safely be modified). +/** + Given a reference to a (possibly) shared stroke_state structure, + return a reference to a stroke_state structure (with room for a + given amount of dash data) that is guaranteed to be unshared + (i.e. one that can safely be modified). shared: The reference to a (possibly) shared structure to unshare. Ownership of this reference is passed in @@ -420,9 +433,9 @@ fz_stroke_state *fz_unshare_stroke_state(fz_context *ctx, fz_stroke_state *share */ fz_stroke_state *fz_unshare_stroke_state_with_dash_len(fz_context *ctx, fz_stroke_state *shared, int len); -/* - fz_clone_stroke_state: Create an identical stroke_state - structure and return a reference to it. +/** + Create an identical stroke_state structure and return a + reference to it. stroke: The stroke state reference to clone. diff --git a/include/mupdf/fitz/pixmap.h b/include/mupdf/fitz/pixmap.h index fcf9d8b..e1c1fab 100644 --- a/include/mupdf/fitz/pixmap.h +++ b/include/mupdf/fitz/pixmap.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_PIXMAP_H #define MUPDF_FITZ_PIXMAP_H @@ -5,46 +27,51 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/store.h" -#include "mupdf/fitz/colorspace.h" #include "mupdf/fitz/separation.h" -/* - Pixmaps represent a set of pixels for a 2 dimensional region of a - plane. Each pixel has n components per pixel, the last of which is - always alpha. The data is in premultiplied alpha when rendering, but - non-premultiplied for colorspace conversions and rescaling. +/** + Pixmaps represent a set of pixels for a 2 dimensional region of + a plane. Each pixel has n components per pixel. The components + are in the order process-components, spot-colors, alpha, where + there can be 0 of any of those types. The data is in + premultiplied alpha when rendering, but non-premultiplied for + colorspace conversions and rescaling. */ -typedef struct fz_pixmap_s fz_pixmap; -typedef struct fz_overprint_s fz_overprint; +typedef struct fz_overprint fz_overprint; -/* - fz_pixmap_bbox: Return the bounding box for a pixmap. +/** + Return the bounding box for a pixmap. */ -fz_irect *fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix, fz_irect *bbox); +fz_irect fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_width: Return the width of the pixmap in pixels. +/** + Return the width of the pixmap in pixels. */ -int fz_pixmap_width(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_width(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_height: Return the height of the pixmap in pixels. +/** + Return the height of the pixmap in pixels. */ -int fz_pixmap_height(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_height(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_x: Return the x value of the pixmap in pixels. +/** + Return the x value of the pixmap in pixels. */ -int fz_pixmap_x(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_x(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_y: Return the y value of the pixmap in pixels. +/** + Return the y value of the pixmap in pixels. */ -int fz_pixmap_y(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_y(fz_context *ctx, const fz_pixmap *pix); -/* - fz_new_pixmap: Create a new pixmap, with its origin at (0,0) +/** + Return sizeof fz_pixmap plus size of data, in bytes. +*/ +size_t fz_pixmap_size(fz_context *ctx, fz_pixmap *pix); + +/** + Create a new pixmap, with its origin at (0,0) cs: The colorspace to use for the pixmap, or NULL for an alpha plane/mask. @@ -57,14 +84,13 @@ int fz_pixmap_y(fz_context *ctx, fz_pixmap *pix); alpha: 0 for no alpha, 1 for alpha. - Returns a pointer to the new pixmap. Throws exception on failure to - allocate. + Returns a pointer to the new pixmap. Throws exception on failure + to allocate. */ fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *cs, int w, int h, fz_separations *seps, int alpha); -/* - fz_new_pixmap_with_bbox: Create a pixmap of a given size, - location and pixel format. +/** + Create a pixmap of a given size, location and pixel format. The bounding box specifies the size of the created pixmap and where it will be located. The colorspace determines the number @@ -80,13 +106,13 @@ fz_pixmap *fz_new_pixmap(fz_context *ctx, fz_colorspace *cs, int w, int h, fz_se alpha: 0 for no alpha, 1 for alpha. - Returns a pointer to the new pixmap. Throws exception on failure to - allocate. + Returns a pointer to the new pixmap. Throws exception on failure + to allocate. */ -fz_pixmap *fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, const fz_irect *bbox, fz_separations *seps, int alpha); +fz_pixmap *fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha); -/* - fz_new_pixmap_with_data: Create a new pixmap, with its origin at +/** + Create a new pixmap, with its origin at (0,0) using the supplied data block. cs: The colorspace to use for the pixmap, or NULL for an alpha @@ -100,8 +126,8 @@ fz_pixmap *fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, c alpha: 0 for no alpha, 1 for alpha. - stride: The byte offset from the pixel data in a row to the pixel - data in the next row. + stride: The byte offset from the pixel data in a row to the + pixel data in the next row. samples: The data block to keep the samples in. @@ -110,9 +136,9 @@ fz_pixmap *fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, c */ fz_pixmap *fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha, int stride, unsigned char *samples); -/* - fz_new_pixmap_with_bbox_and_data: Create a pixmap of a given size, - location and pixel format, using the supplied data block. +/** + Create a pixmap of a given size, location and pixel format, + using the supplied data block. The bounding box specifies the size of the created pixmap and where it will be located. The colorspace determines the number @@ -130,111 +156,123 @@ fz_pixmap *fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, i samples: The data block to keep the samples in. - Returns a pointer to the new pixmap. Throws exception on failure to - allocate. + Returns a pointer to the new pixmap. Throws exception on failure + to allocate. */ -fz_pixmap *fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, const fz_irect *rect, fz_separations *seps, int alpha, unsigned char *samples); +fz_pixmap *fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_irect rect, fz_separations *seps, int alpha, unsigned char *samples); -/* - fz_new_pixmap_from_pixmap: Create a new pixmap that represents - a subarea of the specified pixmap. A reference is taken to his - pixmap that will be dropped on destruction. +/** + Create a new pixmap that represents a subarea of the specified + pixmap. A reference is taken to this pixmap that will be dropped + on destruction. - The supplied rectangle must be wholly contained within the original - pixmap. + The supplied rectangle must be wholly contained within the + original pixmap. - Returns a pointer to the new pixmap. Throws exception on failure to - allocate. + Returns a pointer to the new pixmap. Throws exception on failure + to allocate. */ fz_pixmap *fz_new_pixmap_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, const fz_irect *rect); -/* - fz_keep_pixmap: Take a reference to a pixmap. +/** + Clone a pixmap, copying the pixels and associated data to new + storage. - pix: The pixmap to increment the reference for. + The reference count of 'old' is unchanged. +*/ +fz_pixmap *fz_clone_pixmap(fz_context *ctx, const fz_pixmap *old); - Returns pix. +/** + Increment the reference count for the pixmap. The same pointer + is returned. + + Never throws exceptions. */ fz_pixmap *fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix); -/* - fz_drop_pixmap: Drop a reference and free a pixmap. +/** + Decrement the reference count for the pixmap. When the + reference count hits 0, the pixmap is freed. - Decrement the reference count for the pixmap. When no - references remain the pixmap will be freed. + Never throws exceptions. */ void fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix); -/* - fz_pixmap_colorspace: Return the colorspace of a pixmap +/** + Return the colorspace of a pixmap Returns colorspace. */ -fz_colorspace *fz_pixmap_colorspace(fz_context *ctx, fz_pixmap *pix); +fz_colorspace *fz_pixmap_colorspace(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_components: Return the number of components in a pixmap. +/** + Return the number of components in a pixmap. Returns the number of components (including spots and alpha). */ -int fz_pixmap_components(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_components(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_colorants: Return the number of colorants in a pixmap. +/** + Return the number of colorants in a pixmap. - Returns the number of colorants (components, less any spots and alpha). + Returns the number of colorants (components, less any spots and + alpha). */ -int fz_pixmap_colorants(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_colorants(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_spots: Return the number of spots in a pixmap. +/** + Return the number of spots in a pixmap. - Returns the number of spots (components, less colorants and alpha). Does not throw exceptions. + Returns the number of spots (components, less colorants and + alpha). Does not throw exceptions. */ -int fz_pixmap_spots(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_spots(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_alpha: Return the number of alpha planes in a pixmap. +/** + Return the number of alpha planes in a pixmap. Returns the number of alphas. Does not throw exceptions. */ -int fz_pixmap_alpha(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_alpha(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_samples: Returns a pointer to the pixel data of a pixmap. +/** + Returns a pointer to the pixel data of a pixmap. Returns the pointer. */ -unsigned char *fz_pixmap_samples(fz_context *ctx, fz_pixmap *pix); +unsigned char *fz_pixmap_samples(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_stride: Return the number of bytes in a row in the pixmap. +/** + Return the number of bytes in a row in the pixmap. */ -int fz_pixmap_stride(fz_context *ctx, fz_pixmap *pix); +int fz_pixmap_stride(fz_context *ctx, const fz_pixmap *pix); -/* - fz_pixmap_set_resolution: Set the pixels per inch resolution of the pixmap. +/** + Set the pixels per inch resolution of the pixmap. */ void fz_set_pixmap_resolution(fz_context *ctx, fz_pixmap *pix, int xres, int yres); -/* - fz_clear_pixmap_with_value: Clears a pixmap with the given value. +/** + Clears a pixmap with the given value. pix: The pixmap to clear. value: Values in the range 0 to 255 are valid. Each component sample for each pixel in the pixmap will be set to this value, while alpha will always be set to 255 (non-transparent). + + This function is horrible, and should be removed from the + API and replaced with a less magic one. */ void fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value); -/* +/** Fill pixmap with solid color. */ -void fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *colorspace, float *color, const fz_color_params *color_params); +void fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *colorspace, float *color, fz_color_params color_params); -/* - fz_clear_pixmap_with_value: Clears a subrect of a pixmap with the given value. +/** + Clears a subrect of a pixmap with the given value. pix: The pixmap to clear. @@ -244,78 +282,113 @@ void fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *c r: the rectangle. */ -void fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *pix, int value, const fz_irect *r); +void fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *pix, int value, fz_irect r); -/* - fz_clear_pixmap_with_value: Sets all components (including alpha) of +/** + Sets all components (including alpha) of all pixels in a pixmap to 0. pix: The pixmap to clear. */ void fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix); -/* - fz_invert_pixmap: Invert all the pixels in a pixmap. All components - of all pixels are inverted (except alpha, which is unchanged). +/** + Invert all the pixels in a pixmap. All components (process and + spots) of all pixels are inverted (except alpha, which is + unchanged). */ void fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix); -/* - fz_tint_pixmap: Tint all the pixels in an RGB or Gray pixmap. - - Multiplies all the samples with the input color argument. - - r,g,b: The color to tint with, in 0 to 255 range. +/** + Invert the alpha fo all the pixels in a pixmap. */ -void fz_tint_pixmap(fz_context *ctx, fz_pixmap *pix, int r, int g, int b); +void fz_invert_pixmap_alpha(fz_context *ctx, fz_pixmap *pix); -/* - fz_invert_pixmap: Invert all the pixels in a given rectangle of a - pixmap. All components of all pixels in the rectangle are inverted - (except alpha, which is unchanged). +/** + Transform the pixels in a pixmap so that luminance of each + pixel is inverted, and the chrominance remains unchanged (as + much as accuracy allows). + + All components of all pixels are inverted (except alpha, which + is unchanged). Only supports Grey and RGB bitmaps. */ -void fz_invert_pixmap_rect(fz_context *ctx, fz_pixmap *image, const fz_irect *rect); +void fz_invert_pixmap_luminance(fz_context *ctx, fz_pixmap *pix); -/* - fz_gamma_pixmap: Apply gamma correction to a pixmap. All components +/** + Tint all the pixels in an RGB, BGR, or Gray pixmap. + + black: Map black to this hexadecimal RGB color. + + white: Map white to this hexadecimal RGB color. +*/ +void fz_tint_pixmap(fz_context *ctx, fz_pixmap *pix, int black, int white); + +/** + Invert all the pixels in a given rectangle of a (premultiplied) + pixmap. All components of all pixels in the rectangle are + inverted (except alpha, which is unchanged). +*/ +void fz_invert_pixmap_rect(fz_context *ctx, fz_pixmap *image, fz_irect rect); + +/** + Invert all the pixels in a non-premultiplied pixmap in a + very naive manner. +*/ +void fz_invert_pixmap_raw(fz_context *ctx, fz_pixmap *pix); + +/** + Apply gamma correction to a pixmap. All components of all pixels are modified (except alpha, which is unchanged). gamma: The gamma value to apply; 1.0 for no change. */ void fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma); -/* - fz_unmultiply_pixmap: Convert a pixmap from premultiplied to - non-premultiplied format. -*/ -void fz_unmultiply_pixmap(fz_context *ctx, fz_pixmap *pix); - -/* - fz_convert_pixmap: Convert an existing pixmap to a desired +/** + Convert an existing pixmap to a desired colorspace. Other properties of the pixmap, such as resolution and position are copied to the converted pixmap. pix: The pixmap to convert. - default_cs: If NULL pix->colorspace is used. It is possible that the data - may need to be interpreted as one of the color spaces in default_cs. + default_cs: If NULL pix->colorspace is used. It is possible that + the data may need to be interpreted as one of the color spaces + in default_cs. cs_des: Desired colorspace, may be NULL to denote alpha-only. prf: Proofing color space through which we need to convert. - color_params: Parameters that may be used in conversion (e.g. ri). + color_params: Parameters that may be used in conversion (e.g. + ri). keep_alpha: If 0 any alpha component is removed, otherwise alpha is kept if present in the pixmap. */ -fz_pixmap *fz_convert_pixmap(fz_context *ctx, fz_pixmap *pix, fz_colorspace *cs_des, fz_colorspace *prf, fz_default_colorspaces *default_cs, const fz_color_params *color_params, int keep_alpha); +fz_pixmap *fz_convert_pixmap(fz_context *ctx, const fz_pixmap *pix, fz_colorspace *cs_des, fz_colorspace *prf, fz_default_colorspaces *default_cs, fz_color_params color_params, int keep_alpha); -/* - Pixmaps represent a set of pixels for a 2 dimensional region of a - plane. Each pixel has n components per pixel, the last of which is - always alpha. The data is in premultiplied alpha when rendering, but - non-premultiplied for colorspace conversions and rescaling. +/** + Check if the pixmap is a 1-channel image containing samples with + only values 0 and 255 +*/ +int fz_is_pixmap_monochrome(fz_context *ctx, fz_pixmap *pixmap); + +/* Implementation details: subject to change.*/ + +fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray); +void fz_decode_tile(fz_context *ctx, fz_pixmap *pix, const float *decode); +void fz_md5_pixmap(fz_context *ctx, fz_pixmap *pixmap, unsigned char digest[16]); + +fz_stream * +fz_unpack_stream(fz_context *ctx, fz_stream *src, int depth, int w, int h, int n, int indexed, int pad, int skip); + +/** + Pixmaps represent a set of pixels for a 2 dimensional region of + a plane. Each pixel has n components per pixel. The components + are in the order process-components, spot-colors, alpha, where + there can be 0 of any of those types. The data is in + premultiplied alpha when rendering, but non-premultiplied for + colorspace conversions and rescaling. x, y: The minimum x and y coord of the region in pixels. @@ -341,15 +414,20 @@ fz_pixmap *fz_convert_pixmap(fz_context *ctx, fz_pixmap *pix, fz_colorspace *cs_ xres, yres: Image resolution in dpi. Default is 96 dpi. - colorspace: Pointer to a colorspace object describing the colorspace - the pixmap is in. If NULL, the image is a mask. + colorspace: Pointer to a colorspace object describing the + colorspace the pixmap is in. If NULL, the image is a mask. - samples: A simple block of memory w * h * n bytes of memory in which - the components are stored. The first n bytes are components 0 to n-1 - for the pixel at (x,y). Each successive n bytes gives another pixel - in scanline order. Subsequent scanlines follow on with no padding. + samples: Pointer to the first byte of the pixmap sample data. + This is typically a simple block of memory w * h * n bytes of + memory in which the components are stored linearly, but with the + use of appropriate stride values, scanlines can be stored in + different orders, and have different amounts of padding. The + first n bytes are components 0 to n-1 for the pixel at (x,y). + Each successive n bytes gives another pixel in scanline order + as we move across the line. The start of each scanline is offset + the start of the previous one by stride bytes. */ -struct fz_pixmap_s +struct fz_pixmap { fz_storable storable; int x, y, w, h; @@ -371,56 +449,53 @@ enum FZ_PIXMAP_FLAG_FREE_SAMPLES = 2 }; -void fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix); +/* Create a new pixmap from a warped section of another. + * + * Colorspace, resolution etc are inherited from the original. + * points give the corner points within the original pixmap of a + * (convex) quadrilateral. These corner points will be 'warped' to be + * the corner points of the returned bitmap, which will have the given + * width/height. + */ +fz_pixmap * +fz_warp_pixmap(fz_context *ctx, fz_pixmap *src, const fz_point points[4], int width, int height); -void fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, const fz_irect *r, const fz_default_colorspaces *default_cs); -void fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix); -fz_pixmap *fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray); -size_t fz_pixmap_size(fz_context *ctx, fz_pixmap *pix); +/* + Convert between different separation results. +*/ +fz_pixmap *fz_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const fz_irect *bbox, fz_colorspace *dcs, fz_separations *seps, fz_color_params color_params, fz_default_colorspaces *default_cs); -fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, fz_irect *clip); +/* + * Extract alpha channel as a separate pixmap. + * Returns NULL if there is no alpha channel in the source. + */ +fz_pixmap *fz_new_pixmap_from_alpha_channel(fz_context *ctx, fz_pixmap *src); -typedef struct fz_scale_cache_s fz_scale_cache; +/* + * Combine a pixmap without an alpha channel with a soft mask. + */ +fz_pixmap *fz_new_pixmap_from_color_and_mask(fz_context *ctx, fz_pixmap *color, fz_pixmap *mask); -fz_scale_cache *fz_new_scale_cache(fz_context *ctx); -void fz_drop_scale_cache(fz_context *ctx, fz_scale_cache *cache); -fz_pixmap *fz_scale_pixmap_cached(fz_context *ctx, const fz_pixmap *src, float x, float y, float w, float h, const fz_irect *clip, fz_scale_cache *cache_x, fz_scale_cache *cache_y); +/* + * Scale the pixmap up or down in size to fit the rectangle. Will return `NULL` + * if the scaling factors are out of range. This applies fancy filtering and + * will anti-alias the edges for subpixel positioning if using non-integer + * coordinates. If the clip rectangle is set, the returned pixmap may be subset + * to fit the clip rectangle. Pass `NULL` to the clip if you want the whole + * pixmap scaled. + */ +fz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, const fz_irect *clip); +/* + * Reduces size to: + * tile->w => (tile->w + 2^factor-1) / 2^factor + * tile->h => (tile->h + 2^factor-1) / 2^factor + */ void fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor); -fz_irect *fz_pixmap_bbox_no_ctx(const fz_pixmap *src, fz_irect *bbox); - -void fz_decode_tile(fz_context *ctx, fz_pixmap *pix, const float *decode); -void fz_decode_indexed_tile(fz_context *ctx, fz_pixmap *pix, const float *decode, int maxval); -void fz_unpack_tile(fz_context *ctx, fz_pixmap *dst, unsigned char * restrict src, int n, int depth, size_t stride, int scale); - /* - fz_pixmap_converter: Color convert a pixmap. The passing of default_cs is needed due to the base cs of the image possibly - needing to be treated as being in one of the page default color spaces. -*/ -typedef void (fz_pixmap_converter)(fz_context *ctx, fz_pixmap *dp, fz_pixmap *sp, fz_colorspace *prf, const fz_default_colorspaces *default_cs, const fz_color_params *color_params, int copy_spots); -fz_pixmap_converter *fz_lookup_pixmap_converter(fz_context *ctx, fz_colorspace *ds, fz_colorspace *ss); - -/* - fz_md5_pixmap: Return the md5 digest for a pixmap -*/ -void fz_md5_pixmap(fz_context *ctx, fz_pixmap *pixmap, unsigned char digest[16]); - -fz_pixmap *fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span); -fz_pixmap *fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span); - -#ifdef HAVE_VALGRIND -int fz_valgrind_pixmap(const fz_pixmap *pix); -#else -#define fz_valgrind_pixmap(pix) do {} while (0) -#endif - -/* - fz_clone_pixmap_area_with_different_seps: Convert between - different separation results. -*/ -fz_pixmap *fz_clone_pixmap_area_with_different_seps(fz_context *ctx, fz_pixmap *src, const fz_irect *bbox, fz_colorspace *dcs, fz_separations *seps, const fz_color_params *color_params, fz_default_colorspaces *default_cs); - -fz_pixmap *fz_copy_pixmap_area_converting_seps(fz_context *ctx, fz_pixmap *dst, fz_pixmap *src, const fz_color_params *color_params, fz_colorspace *prf, fz_default_colorspaces *default_cs); + * Copies r (clipped to both src and dest) in src to dest. + */ +void fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_irect r, const fz_default_colorspaces *default_cs); #endif diff --git a/include/mupdf/fitz/pool.h b/include/mupdf/fitz/pool.h index 8cc7540..43bc6b2 100644 --- a/include/mupdf/fitz/pool.h +++ b/include/mupdf/fitz/pool.h @@ -1,14 +1,68 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_POOL_H #define MUPDF_FITZ_POOL_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" -typedef struct fz_pool_s fz_pool; +/** + Simple pool allocators. + Allocate from the pool, which can then be freed at once. +*/ +typedef struct fz_pool fz_pool; + +/** + Create a new pool to allocate from. +*/ fz_pool *fz_new_pool(fz_context *ctx); + +/** + Allocate a block of size bytes from the pool. +*/ void *fz_pool_alloc(fz_context *ctx, fz_pool *pool, size_t size); + +/** + strdup equivalent allocating from the pool. +*/ char *fz_pool_strdup(fz_context *ctx, fz_pool *pool, const char *s); + +/** + The current size of the pool. + + The number of bytes of storage currently allocated to the pool. + This is the total of the storage used for the blocks making + up the pool, rather then total of the allocated blocks so far, + so it will increase in 'lumps'. + from the pool, then the pool size may still be X +*/ +size_t fz_pool_size(fz_context *ctx, fz_pool *pool); + +/** + Drop a pool, freeing and invalidating all storage returned from + the pool. +*/ void fz_drop_pool(fz_context *ctx, fz_pool *pool); #endif diff --git a/include/mupdf/fitz/separation.h b/include/mupdf/fitz/separation.h index aa66b3b..0a6e2fd 100644 --- a/include/mupdf/fitz/separation.h +++ b/include/mupdf/fitz/separation.h @@ -1,10 +1,33 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_SEPARATION_H #define MUPDF_FITZ_SEPARATION_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" +#include "mupdf/fitz/color.h" -/* +/** A fz_separation structure holds details of a set of separations (such as might be used on within a page of the document). @@ -17,7 +40,7 @@ enum FZ_MAX_SEPARATIONS = 64 }; -typedef struct fz_separations_s fz_separations; +typedef struct fz_separations fz_separations; typedef enum { @@ -31,54 +54,85 @@ typedef enum FZ_SEPARATION_DISABLED = 2 } fz_separation_behavior; -/* Create a new separations structure (initially empty) */ +/** + Create a new separations structure (initially empty) +*/ fz_separations *fz_new_separations(fz_context *ctx, int controllable); -/* Keep a reference */ +/** + Increment the reference count for a separations structure. + Returns the same pointer. + + Never throws exceptions. +*/ fz_separations *fz_keep_separations(fz_context *ctx, fz_separations *sep); -/* Drop a reference */ +/** + Decrement the reference count for a separations structure. + When the reference count hits zero, the separations structure + is freed. + + Never throws exceptions. +*/ void fz_drop_separations(fz_context *ctx, fz_separations *sep); -/* Add a separation (null terminated name, colorspace) */ +/** + Add a separation (null terminated name, colorspace) +*/ void fz_add_separation(fz_context *ctx, fz_separations *sep, const char *name, fz_colorspace *cs, int cs_channel); -/* Add a separation with equivalents (null terminated name, colorspace) (old, deprecated) */ +/** + Add a separation with equivalents (null terminated name, + colorspace) + + (old, deprecated) +*/ void fz_add_separation_equivalents(fz_context *ctx, fz_separations *sep, uint32_t rgba, uint32_t cmyk, const char *name); -/* Control the rendering of a given separation */ +/** + Control the rendering of a given separation. +*/ void fz_set_separation_behavior(fz_context *ctx, fz_separations *sep, int separation, fz_separation_behavior behavior); -/* Test for the current behavior of a separation */ +/** + Test for the current behavior of a separation. +*/ fz_separation_behavior fz_separation_current_behavior(fz_context *ctx, const fz_separations *sep, int separation); -/* Quick test for all separations composite (the common case) */ -int fz_separations_all_composite(fz_context *ctx, const fz_separations *sep); - -/* Read separation name */ const char *fz_separation_name(fz_context *ctx, const fz_separations *sep, int separation); - -/* Count the number of separations */ int fz_count_separations(fz_context *ctx, const fz_separations *sep); -/* Find out if separations are controllable. */ -int fz_separations_controllable(fz_context *ctx, const fz_separations *seps); - -/* Return the number of active separations. */ +/** + Return the number of active separations. +*/ int fz_count_active_separations(fz_context *ctx, const fz_separations *seps); -/* Return a separations object with all the spots in the input - * separations object that are set to composite, reset to be - * enabled. If there ARE no spots in the object, this returns - * NULL. If the object already has all its spots enabled, then - * just returns another handle on the same object. */ +/** + Compare 2 separations structures (or NULLs). + + Return 0 if identical, non-zero if not identical. +*/ +int fz_compare_separations(fz_context *ctx, const fz_separations *sep1, const fz_separations *sep2); + + +/** + Return a separations object with all the spots in the input + separations object that are set to composite, reset to be + enabled. If there ARE no spots in the object, this returns + NULL. If the object already has all its spots enabled, then + just returns another handle on the same object. +*/ fz_separations *fz_clone_separations_for_overprint(fz_context *ctx, fz_separations *seps); -/* Convert a color given in terms of one colorspace, - * to a color in terms of another colorspace/separations. */ -void fz_convert_separation_colors(fz_context *ctx, const fz_color_params *color_params, const fz_colorspace *dst_cs, const fz_separations *dst_sep, float *dst_color, const fz_colorspace *src_cs, const float *src_color); +/** + Convert a color given in terms of one colorspace, + to a color in terms of another colorspace/separations. +*/ +void fz_convert_separation_colors(fz_context *ctx, fz_colorspace *src_cs, const float *src_color, fz_separations *dst_seps, fz_colorspace *dst_cs, float *dst_color, fz_color_params color_params); -/* Get the equivalent separation color in a given colorspace. */ -void fz_separation_equivalent(fz_context *ctx, const fz_separations *seps, int i, const fz_color_params *color_params, const fz_colorspace *dst_cs, const fz_colorspace *prf, float *convert); +/** + Get the equivalent separation color in a given colorspace. +*/ +void fz_separation_equivalent(fz_context *ctx, const fz_separations *seps, int idx, fz_colorspace *dst_cs, float *dst_color, fz_colorspace *prf, fz_color_params color_params); #endif diff --git a/include/mupdf/fitz/shade.h b/include/mupdf/fitz/shade.h index 24cb4cb..bb0d70f 100644 --- a/include/mupdf/fitz/shade.h +++ b/include/mupdf/fitz/shade.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_SHADE_H #define MUPDF_FITZ_SHADE_H @@ -5,11 +27,10 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/store.h" -#include "mupdf/fitz/colorspace.h" #include "mupdf/fitz/pixmap.h" #include "mupdf/fitz/compressed-buffer.h" -/* +/** * The shading code uses gouraud shaded triangle meshes. */ @@ -24,11 +45,11 @@ enum FZ_MESH_TYPE7 = 7 }; -/* +/** Structure is public to allow derived classes. Do not access the members directly. */ -typedef struct fz_shade_s +typedef struct { fz_storable storable; @@ -40,12 +61,14 @@ typedef struct fz_shade_s float background[FZ_MAX_COLORS]; /* Just to be confusing, PDF Shadings of Type 1 (Function Based - * Shadings), do NOT use_function, but all the others do. This + * Shadings), do NOT use function, but all the others do. This * is because Type 1 shadings take 2 inputs, whereas all the * others (when used with a function take 1 input. The type 1 * data is in the 'f' field of the union below. */ - int use_function; - float function[256][FZ_MAX_COLORS + 1]; + /* If function_stride = 0, then function is not used. Otherwise + * function points to 256*function_stride entries. */ + int function_stride; + float *function; int type; /* function, linear, radial, mesh */ union @@ -79,33 +102,24 @@ typedef struct fz_shade_s fz_compressed_buffer *buffer; } fz_shade; -/* - fz_keep_shade: Add a reference to a fz_shade. +/** + Increment the reference count for the shade structure. The + same pointer is returned. - shade: The reference to keep. - - Returns shade. + Never throws exceptions. */ fz_shade *fz_keep_shade(fz_context *ctx, fz_shade *shade); -/* - fz_drop_shade: Drop a reference to a fz_shade. +/** + Decrement the reference count for the shade structure. When + the reference count hits zero, the structure is freed. - shade: The reference to drop. If this is the last - reference, shade will be destroyed. + Never throws exceptions. */ void fz_drop_shade(fz_context *ctx, fz_shade *shade); -/* - fz_drop_shade_imp: Internal function to destroy a - shade. Only exposed for use with the fz_store. - - shade: The reference to destroy. -*/ -void fz_drop_shade_imp(fz_context *ctx, fz_storable *shade); - -/* - fz_bound_shade: Bound a given shading. +/** + Bound a given shading. shade: The shade to bound. @@ -115,10 +129,14 @@ void fz_drop_shade_imp(fz_context *ctx, fz_storable *shade); Returns r, updated to contain the bounds for the shading. */ -fz_rect *fz_bound_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, fz_rect *r); +fz_rect fz_bound_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm); -/* - fz_paint_shade: Render a shade to a given pixmap. +typedef struct fz_shade_color_cache fz_shade_color_cache; + +void fz_drop_shade_color_cache(fz_context *ctx, fz_shade_color_cache *cache); + +/** + Render a shade to a given pixmap. shade: The shade to paint. @@ -134,23 +152,25 @@ fz_rect *fz_bound_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, bbox: Pointer to a bounding box to limit the rendering of the shade. - op: NULL, or pointer to overprint bitmap. -*/ -void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_colorspace *override_cs, const fz_matrix *ctm, fz_pixmap *dest, const fz_color_params *color_params, const fz_irect *bbox, const fz_overprint *op); + eop: NULL, or pointer to overprint bitmap. -/* + cache: *cache is used to cache color information. If *cache is NULL it + is set to point to a new fz_shade_color_cache. If cache is NULL it is + ignored. +*/ +void fz_paint_shade(fz_context *ctx, fz_shade *shade, fz_colorspace *override_cs, fz_matrix ctm, fz_pixmap *dest, fz_color_params color_params, fz_irect bbox, const fz_overprint *eop, fz_shade_color_cache **cache); + +/** * Handy routine for processing mesh based shades */ -typedef struct fz_vertex_s fz_vertex; - -struct fz_vertex_s +typedef struct { fz_point p; float c[FZ_MAX_COLORS]; -}; +} fz_vertex; -/* - fz_shade_prepare_fn: Callback function type for use with +/** + Callback function type for use with fz_process_shade. arg: Opaque pointer from fz_process_shade caller. @@ -161,8 +181,8 @@ struct fz_vertex_s */ typedef void (fz_shade_prepare_fn)(fz_context *ctx, void *arg, fz_vertex *v, const float *c); -/* - fz_shade_process_fn: Callback function type for use with +/** + Callback function type for use with fz_process_shade. arg: Opaque pointer from fz_process_shade caller. @@ -173,11 +193,11 @@ typedef void (fz_shade_prepare_fn)(fz_context *ctx, void *arg, fz_vertex *v, con */ typedef void (fz_shade_process_fn)(fz_context *ctx, void *arg, fz_vertex *av, fz_vertex *bv, fz_vertex *cv); -/* - fz_process_shade: Process a shade, using supplied callback - functions. This decomposes the shading to a mesh (even ones - that are not natively meshes, such as linear or radial - shadings), and processes triangles from those meshes. +/** + Process a shade, using supplied callback functions. This + decomposes the shading to a mesh (even ones that are not + natively meshes, such as linear or radial shadings), and + processes triangles from those meshes. shade: The shade to process. @@ -194,9 +214,20 @@ typedef void (fz_shade_process_fn)(fz_context *ctx, void *arg, fz_vertex *av, fz process_arg: An opaque argument passed through from caller to callback functions. */ -void fz_process_shade(fz_context *ctx, fz_shade *shade, const fz_matrix *ctm, +void fz_process_shade(fz_context *ctx, fz_shade *shade, fz_matrix ctm, fz_rect scissor, fz_shade_prepare_fn *prepare, fz_shade_process_fn *process, void *process_arg); + +/* Implementation details: subject to change. */ + +/** + Internal function to destroy a + shade. Only exposed for use with the fz_store. + + shade: The reference to destroy. +*/ +void fz_drop_shade_imp(fz_context *ctx, fz_storable *shade); + #endif diff --git a/include/mupdf/fitz/store.h b/include/mupdf/fitz/store.h index 7dff6c3..452bb59 100644 --- a/include/mupdf/fitz/store.h +++ b/include/mupdf/fitz/store.h @@ -1,115 +1,220 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_STORE_H #define MUPDF_FITZ_STORE_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/output.h" +#include "mupdf/fitz/log.h" -/* +/** Resource store MuPDF stores decoded "objects" into a store for potential reuse. - If the size of the store gets too big, objects stored within it can - be evicted and freed to recover space. When MuPDF comes to decode - such an object, it will check to see if a version of this object is - already in the store - if it is, it will simply reuse it. If not, it - will decode it and place it into the store. + If the size of the store gets too big, objects stored within it + can be evicted and freed to recover space. When MuPDF comes to + decode such an object, it will check to see if a version of this + object is already in the store - if it is, it will simply reuse + it. If not, it will decode it and place it into the store. - All objects that can be placed into the store are derived from the - fz_storable type (i.e. this should be the first component of the - objects structure). This allows for consistent (thread safe) - reference counting, and includes a function that will be called to - free the object as soon as the reference count reaches zero. + All objects that can be placed into the store are derived from + the fz_storable type (i.e. this should be the first component of + the objects structure). This allows for consistent (thread safe) + reference counting, and includes a function that will be called + to free the object as soon as the reference count reaches zero. Most objects offer fz_keep_XXXX/fz_drop_XXXX functions derived from fz_keep_storable/fz_drop_storable. Creation of such objects - includes a call to FZ_INIT_STORABLE to set up the fz_storable header. + includes a call to FZ_INIT_STORABLE to set up the fz_storable + header. */ +typedef struct fz_storable fz_storable; -typedef struct fz_storable_s fz_storable; -typedef struct fz_key_storable_s fz_key_storable; +/** + Function type for a function to drop a storable object. + Objects within the store are identified by type by comparing + their drop_fn pointers. +*/ typedef void (fz_store_drop_fn)(fz_context *, fz_storable *); -struct fz_storable_s { +/** + Function type for a function to check whether a storable + object can be dropped at the moment. + + Return 0 for 'cannot be dropped', 1 otherwise. +*/ +typedef int (fz_store_droppable_fn)(fz_context *, fz_storable *); + +/** + Any storable object should include an fz_storable structure + at the start (by convention at least) of their structure. + (Unless it starts with an fz_key_storable, see below). +*/ +struct fz_storable { int refs; fz_store_drop_fn *drop; + fz_store_droppable_fn *droppable; }; -struct fz_key_storable_s { +/** + Any storable object that can appear in the key of another + storable object should include an fz_key_storable structure + at the start (by convention at least) of their structure. +*/ +typedef struct +{ fz_storable storable; short store_key_refs; -}; +} fz_key_storable; +/** + Macros to initialise a storable object. +*/ #define FZ_INIT_STORABLE(S_,RC,DROP) \ do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ - S->drop = (DROP); \ + S->drop = (DROP); S->droppable = NULL; \ } while (0) +#define FZ_INIT_AWKWARD_STORABLE(S_,RC,DROP,DROPPABLE) \ + do { fz_storable *S = &(S_)->storable; S->refs = (RC); \ + S->drop = (DROP); S->droppable = (DROPPABLE); \ + } while (0) + +/** + Macro to initialise a key storable object. +*/ #define FZ_INIT_KEY_STORABLE(KS_,RC,DROP) \ do { fz_key_storable *KS = &(KS_)->key_storable; KS->store_key_refs = 0;\ FZ_INIT_STORABLE(KS,RC,DROP); \ } while (0) +/** + Increment the reference count for a storable object. + Returns the same pointer. + + Never throws exceptions. +*/ void *fz_keep_storable(fz_context *, const fz_storable *); + +/** + Decrement the reference count for a storable object. When the + reference count hits zero, the drop function for that object + is called to free the object. + + Never throws exceptions. +*/ void fz_drop_storable(fz_context *, const fz_storable *); +/** + Increment the (normal) reference count for a key storable + object. Returns the same pointer. + + Never throws exceptions. +*/ void *fz_keep_key_storable(fz_context *, const fz_key_storable *); + +/** + Decrement the (normal) reference count for a storable object. + When the total reference count hits zero, the drop function for + that object is called to free the object. + + Never throws exceptions. +*/ void fz_drop_key_storable(fz_context *, const fz_key_storable *); +/** + Increment the (key) reference count for a key storable + object. Returns the same pointer. + + Never throws exceptions. +*/ void *fz_keep_key_storable_key(fz_context *, const fz_key_storable *); + +/** + Decrement the (key) reference count for a storable object. + When the total reference count hits zero, the drop function for + that object is called to free the object. + + Never throws exceptions. +*/ void fz_drop_key_storable_key(fz_context *, const fz_key_storable *); -/* - The store can be seen as a dictionary that maps keys to fz_storable - values. In order to allow keys of different types to be stored, we - have a structure full of functions for each key 'type'; this - fz_store_type pointer is stored with each key, and tells the store - how to perform certain operations (like taking/dropping a reference, - comparing two keys, outputting details for debugging etc). +/** + The store can be seen as a dictionary that maps keys to + fz_storable values. In order to allow keys of different types to + be stored, we have a structure full of functions for each key + 'type'; this fz_store_type pointer is stored with each key, and + tells the store how to perform certain operations (like taking/ + dropping a reference, comparing two keys, outputting details for + debugging etc). - The store uses a hash table internally for speed where possible. In - order for this to work, we need a mechanism for turning a generic - 'key' into 'a hashable string'. For this purpose the type structure - contains a make_hash_key function pointer that maps from a void * - to a fz_store_hash structure. If make_hash_key function returns 0, - then the key is determined not to be hashable, and the value is - not stored in the hash table. + The store uses a hash table internally for speed where possible. + In order for this to work, we need a mechanism for turning a + generic 'key' into 'a hashable string'. For this purpose the + type structure contains a make_hash_key function pointer that + maps from a void * to a fz_store_hash structure. If + make_hash_key function returns 0, then the key is determined not + to be hashable, and the value is not stored in the hash table. - Some objects can be used both as values within the store, and as a - component of keys within the store. We refer to these objects as - "key storable" objects. In this case, we need to take additional - care to ensure that we do not end up keeping an item within the - store, purely because its value is referred to by another key in - the store. + Some objects can be used both as values within the store, and as + a component of keys within the store. We refer to these objects + as "key storable" objects. In this case, we need to take + additional care to ensure that we do not end up keeping an item + within the store, purely because its value is referred to by + another key in the store. An example of this are fz_images in PDF files. Each fz_image is placed into the store to enable it to be easily reused. When the image is rendered, a pixmap is generated from the image, and the - pixmap is placed into the store so it can be reused on subsequent - renders. The image forms part of the key for the pixmap. + pixmap is placed into the store so it can be reused on + subsequent renders. The image forms part of the key for the + pixmap. When we close the pdf document (and any associated pages/display lists etc), we drop the images from the store. This may leave us in the position of the images having non-zero reference counts - purely because they are used as part of the keys for the pixmaps. + purely because they are used as part of the keys for the + pixmaps. We therefore use special reference counting functions to keep - track of these "key storable" items, and hence store the number of - references to these items that are used in keys. + track of these "key storable" items, and hence store the number + of references to these items that are used in keys. When the number of references to an object == the number of - references to an object from keys in the store, we know that we can - remove all the items which have that object as part of the key. - This is done by running a pass over the store, 'reaping' those - items. + references to an object from keys in the store, we know that we + can remove all the items which have that object as part of the + key. This is done by running a pass over the store, 'reaping' + those items. Reap passes are slower than we would like as they touch every item in the store. We therefore provide a way to 'batch' such - reap passes together, using fz_defer_reap_start/fz_defer_reap_end - to bracket a region in which many may be triggered. + reap passes together, using fz_defer_reap_start/ + fz_defer_reap_end to bracket a region in which many may be + triggered. */ -typedef struct fz_store_hash_s +typedef struct { fz_store_drop_fn *drop; union @@ -128,60 +233,76 @@ typedef struct fz_store_hash_s struct { int id; + char has_shape; + char has_group_alpha; float m[4]; void *ptr; - } im; /* 20 bytes */ + } im; /* 28 or 32 bytes */ struct { unsigned char src_md5[16]; unsigned char dst_md5[16]; unsigned int ri:2; unsigned int bp:1; - unsigned int bpp16:1; + unsigned int format:1; unsigned int proof:1; unsigned int src_extras:5; unsigned int dst_extras:5; unsigned int copy_spots:1; + unsigned int bgr:1; } link; /* 36 bytes */ } u; } fz_store_hash; /* 40 or 44 bytes */ -typedef struct fz_store_type_s +/** + Every type of object to be placed into the store defines an + fz_store_type. This contains the pointers to functions to + make hashes, manipulate keys, and check for needing reaping. +*/ +typedef struct { + const char *name; int (*make_hash_key)(fz_context *ctx, fz_store_hash *hash, void *key); void *(*keep_key)(fz_context *ctx, void *key); void (*drop_key)(fz_context *ctx, void *key); int (*cmp_key)(fz_context *ctx, void *a, void *b); - void (*format_key)(fz_context *ctx, char *buf, int size, void *key); + void (*format_key)(fz_context *ctx, char *buf, size_t size, void *key); int (*needs_reap)(fz_context *ctx, void *key); } fz_store_type; -/* - fz_store_new_context: Create a new store inside the context +/** + Create a new store inside the context - max: The maximum size (in bytes) that the store is allowed to grow - to. FZ_STORE_UNLIMITED means no limit. + max: The maximum size (in bytes) that the store is allowed to + grow to. FZ_STORE_UNLIMITED means no limit. */ void fz_new_store_context(fz_context *ctx, size_t max); -/* - fz_drop_store_context: Drop a reference to the store. -*/ -void fz_drop_store_context(fz_context *ctx); +/** + Increment the reference count for the store context. Returns + the same pointer. -/* - fz_keep_store_context: Take a reference to the store. + Never throws exceptions. */ fz_store *fz_keep_store_context(fz_context *ctx); -/* - fz_store_item: Add an item to the store. +/** + Decrement the reference count for the store context. When the + reference count hits zero, the store context is freed. - Add an item into the store, returning NULL for success. If an item - with the same key is found in the store, then our item will not be - inserted, and the function will return a pointer to that value - instead. This function takes its own reference to val, as required - (i.e. the caller maintains ownership of its own reference). + Never throws exceptions. +*/ +void fz_drop_store_context(fz_context *ctx); + +/** + Add an item to the store. + + Add an item into the store, returning NULL for success. If an + item with the same key is found in the store, then our item will + not be inserted, and the function will return a pointer to that + value instead. This function takes its own reference to val, as + required (i.e. the caller maintains ownership of its own + reference). key: The key used to index the item. @@ -194,28 +315,29 @@ fz_store *fz_keep_store_context(fz_context *ctx); */ void *fz_store_item(fz_context *ctx, void *key, void *val, size_t itemsize, const fz_store_type *type); -/* - fz_find_item: Find an item within the store. +/** + Find an item within the store. - drop: The function used to free the value (to ensure we get a value - of the correct type). + drop: The function used to free the value (to ensure we get a + value of the correct type). key: The key used to index the item. type: Functions used to manipulate the key. - Returns NULL for not found, otherwise returns a pointer to the value - indexed by key to which a reference has been taken. + Returns NULL for not found, otherwise returns a pointer to the + value indexed by key to which a reference has been taken. */ void *fz_find_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_store_type *type); -/* - fz_remove_item: Remove an item from the store. +/** + Remove an item from the store. - If an item indexed by the given key exists in the store, remove it. + If an item indexed by the given key exists in the store, remove + it. - drop: The function used to free the value (to ensure we get a value - of the correct type). + drop: The function used to free the value (to ensure we get a + value of the correct type). key: The key used to find the item to remove. @@ -223,16 +345,16 @@ void *fz_find_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_ */ void fz_remove_item(fz_context *ctx, fz_store_drop_fn *drop, void *key, const fz_store_type *type); -/* - fz_empty_store: Evict everything from the store. +/** + Evict every item from the store. */ void fz_empty_store(fz_context *ctx); -/* - fz_store_scavenge: Internal function used as part of the scavenging +/** + Internal function used as part of the scavenging allocator; when we fail to allocate memory, before returning a - failure to the caller, we try to scavenge space within the store by - evicting at least 'size' bytes. The allocator then retries. + failure to the caller, we try to scavenge space within the store + by evicting at least 'size' bytes. The allocator then retries. size: The number of bytes we are trying to have free. @@ -242,8 +364,8 @@ void fz_empty_store(fz_context *ctx); */ int fz_store_scavenge(fz_context *ctx, size_t size, int *phase); -/* - fz_store_scavenge_external: External function for callers to use +/** + External function for callers to use to scavenge while trying allocations. size: The number of bytes we are trying to have free. @@ -254,28 +376,42 @@ int fz_store_scavenge(fz_context *ctx, size_t size, int *phase); */ int fz_store_scavenge_external(fz_context *ctx, size_t size, int *phase); -/* - fz_shrink_store: Evict items from the store until the total size of +/** + Evict items from the store until the total size of the objects in the store is reduced to a given percentage of its current size. percent: %age of current size to reduce the store to. - Returns non zero if we managed to free enough memory, zero otherwise. + Returns non zero if we managed to free enough memory, zero + otherwise. */ int fz_shrink_store(fz_context *ctx, unsigned int percent); +/** + Callback function called by fz_filter_store on every item within + the store. + + Return 1 to drop the item from the store, 0 to retain. +*/ typedef int (fz_store_filter_fn)(fz_context *ctx, void *arg, void *key); +/** + Filter every element in the store with a matching type with the + given function. + + If the function returns 1 for an element, drop the element. +*/ void fz_filter_store(fz_context *ctx, fz_store_filter_fn *fn, void *arg, const fz_store_type *type); -/* - fz_debug_store: Dump the contents of the store for debugging. +/** + Output debugging information for the current state of the store + to the given output channel. */ -void fz_debug_store(fz_context *ctx); +void fz_debug_store(fz_context *ctx, fz_output *out); -/* - fz_defer_reap_start: Increment the defer reap count. +/** + Increment the defer reap count. No reap operations will take place (except for those triggered by an immediate failed malloc) until the @@ -289,8 +425,8 @@ void fz_debug_store(fz_context *ctx); */ void fz_defer_reap_start(fz_context *ctx); -/* - fz_defer_reap_end: Decrement the defer reap count. +/** + Decrement the defer reap count. If the defer reap count returns to 0, and the store has reapable objects in, a reap pass will begin. @@ -303,4 +439,18 @@ void fz_defer_reap_start(fz_context *ctx); */ void fz_defer_reap_end(fz_context *ctx); +#ifdef ENABLE_STORE_LOGGING + +void fz_log_dump_store(fz_context *ctx, const char *fmt, ...); + +#define FZ_LOG_STORE(CTX, ...) fz_log_module(CTX, "STORE", __VA_ARGS__) +#define FZ_LOG_DUMP_STORE(...) fz_log_dump_store(__VA_ARGS__) + +#else + +#define FZ_LOG_STORE(...) do {} while (0) +#define FZ_LOG_DUMP_STORE(...) do {} while (0) + +#endif + #endif diff --git a/include/mupdf/fitz/story-writer.h b/include/mupdf/fitz/story-writer.h new file mode 100644 index 0000000..70cbcd5 --- /dev/null +++ b/include/mupdf/fitz/story-writer.h @@ -0,0 +1,209 @@ +// Copyright (C) 2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_STORY_WRITER_H +#define MUPDF_FITZ_STORY_WRITER_H + +#include "mupdf/fitz/story.h" +#include "mupdf/fitz/writer.h" + +/* + * A fz_story_element_position plus page number information; used with + * fz_write_story() and fz_write_stabilized_story(). + */ +typedef struct +{ + fz_story_element_position element; + int page_num; +} fz_write_story_position; + +/* + * A set of fz_write_story_position items; used with + * fz_write_stabilized_story(). + */ +typedef struct +{ + fz_write_story_position *positions; + int num; +} fz_write_story_positions; + + +/* + * Callback type used by fz_write_story() and fz_write_stabilized_story(). + * + * Should set *rect to rect number . If this is on a new page should also + * set *mediabox and return 1, otherwise return 0. + * + * ref: + * As passed to fz_write_story() or fz_write_stabilized_story(). + * num: + * The rect number. Will typically increment by one each time, being reset + * to zero when fz_write_stabilized_story() starts a new iteration. + * filled: + * From earlier internal call to fz_place_story(). + * rect: + * Out param. + * ctm: + * Out param, defaults to fz_identity. + * mediabox: + * Out param, only used if we return 1. + */ +typedef int (fz_write_story_rectfn)(fz_context *ctx, void *ref, int num, fz_rect filled, fz_rect *rect, fz_matrix *ctm, fz_rect *mediabox); + +/* + * Callback used by fz_write_story() to report information about element + * positions. Slightly different from fz_story_position_callback() because + * also includes the page number. + * + * ref: + * As passed to fz_write_story() or fz_write_stabilized_story(). + * position: + * Called via internal call to fz_story_position_callback(). + */ +typedef void (fz_write_story_positionfn)(fz_context *ctx, void *ref, const fz_write_story_position *position); + +/* + * Callback for fz_write_story(), called twice for each page, before (after=0) + * and after (after=1) the story is written. + * + * ref: + * As passed to fz_write_story() or fz_write_stabilized_story(). + * page_num: + * Page number, starting from 1. + * mediabox: + * As returned from fz_write_story_rectfn(). + * dev: + * Created from the fz_writer passed to fz_write_story() or + * fz_write_stabilized_story(). + * after: + * 0 - before writing the story. + * 1 - after writing the story. + */ +typedef void (fz_write_story_pagefn)(fz_context *ctx, void *ref, int page_num, fz_rect mediabox, fz_device *dev, int after); + +/* + * Callback type for fz_write_stabilized_story(). + * + * Should populate the supplied buffer with html content for use with internal + * calls to fz_new_story(). This may include extra content derived from + * information in , for example a table of contents. + * + * ref: + * As passed to fz_write_stabilized_story(). + * positions: + * Information from previous iteration. + * buffer: + * Where to write the new content. Will be initially empty. + */ +typedef void (fz_write_story_contentfn)(fz_context *ctx, void *ref, const fz_write_story_positions *positions, fz_buffer *buffer); + + +/* + * Places and writes a story to a fz_document_writer. Avoids the need + * for calling code to implement a loop that calls fz_place_story() + * and fz_draw_story() etc, at the expense of having to provide a + * fz_write_story_rectfn() callback. + * + * story: + * The story to place and write. + * writer: + * Where to write the story; can be NULL. + * rectfn: + * Should return information about the rect to be used in the next + * internal call to fz_place_story(). + * rectfn_ref: + * Passed to rectfn(). + * positionfn: + * If not NULL, is called via internal calls to fz_story_positions(). + * positionfn_ref: + * Passed to positionfn(). + * pagefn: + * If not NULL, called at start and end of each page (before and after all + * story content has been written to the device). + * pagefn_ref: + * Passed to pagefn(). + */ +void fz_write_story( + fz_context *ctx, + fz_document_writer *writer, + fz_story *story, + fz_write_story_rectfn rectfn, + void *rectfn_ref, + fz_write_story_positionfn positionfn, + void *positionfn_ref, + fz_write_story_pagefn pagefn, + void *pagefn_ref + ); + + +/* + * Does iterative layout of html content to a fz_document_writer. For example + * this allows one to add a table of contents section while ensuring that page + * numbers are patched up until stable. + * + * Repeatedly creates new story from (contentfn(), contentfn_ref, user_css, em) + * and lays it out with internal call to fz_write_story(); uses a NULL writer + * and populates a fz_write_story_positions which is passed to the next call of + * contentfn(). + * + * When the html from contentfn() becomes unchanged, we do a final iteration + * using . + * + * writer: + * Where to write in the final iteration. + * user_css: + * Used in internal calls to fz_new_story(). + * em: + * Used in internal calls to fz_new_story(). + * contentfn: + * Should return html content for use with fz_new_story(), possibly + * including extra content such as a table-of-contents. + * contentfn_ref: + * Passed to contentfn(). + * rectfn: + * Should return information about the rect to be used in the next + * internal call to fz_place_story(). + * rectfn_ref: + * Passed to rectfn(). + * fz_write_story_pagefn: + * If not NULL, called at start and end of each page (before and after all + * story content has been written to the device). + * pagefn_ref: + * Passed to pagefn(). + * dir: + * NULL, or a directory context to load images etc from. + */ +void fz_write_stabilized_story( + fz_context *ctx, + fz_document_writer *writer, + const char *user_css, + float em, + fz_write_story_contentfn contentfn, + void *contentfn_ref, + fz_write_story_rectfn rectfn, + void *rectfn_ref, + fz_write_story_pagefn pagefn, + void *pagefn_ref, + fz_archive *dir + ); + +#endif diff --git a/include/mupdf/fitz/story.h b/include/mupdf/fitz/story.h new file mode 100644 index 0000000..248dd3b --- /dev/null +++ b/include/mupdf/fitz/story.h @@ -0,0 +1,232 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_STORY_H +#define MUPDF_FITZ_STORY_H + +#include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/buffer.h" +#include "mupdf/fitz/device.h" +#include "mupdf/fitz/xml.h" +#include "mupdf/fitz/archive.h" + +/* + This header file provides an API for laying out and placing styled + text on a page, or pages. + + First a text story is created from some styled HTML. + + Next, this story can be laid out into a given rectangle (possibly + retrying several times with updated rectangles as required). + + Next, the laid out story can be drawn to a given device. + + In the case where the text story cannot be fitted into the given + areas all at once, these two steps can be repeated multiple + times until the text story is completely consumed. + + Finally, the text story can be dropped in the usual fashion. +*/ + + +typedef struct fz_story fz_story; + +/* + Create a text story using styled html. + + Passing a NULL buffer will be treated as an empty document. + Passing a NULL user_css will be treated as an empty CSS string. + A non-NULL dir will allow images etc to be loaded. The + story keeps its own reference, so the caller can drop its + reference after this call. +*/ +fz_story *fz_new_story(fz_context *ctx, fz_buffer *buf, const char *user_css, float em, fz_archive *dir); + +/* + Retrieve the warnings given from parsing this story. + + If there are warnings, this will be returned as a NULL terminated + C string. If there are no warnings, this will return NULL. + + These warnings will not be complete until AFTER any DOM manipulations + have been completed. + + This function does not need to be called, but once it has been + the DOM is no longer accessible, and any fz_xml pointer + retrieved from fz_story_docment is no longer valid. +*/ +const char *fz_story_warnings(fz_context *ctx, fz_story *story); + +/* + Equivalent to fz_place_story_flags with flags being 0. +*/ +int fz_place_story(fz_context *ctx, fz_story *story, fz_rect where, fz_rect *filled); + +/* + Place (or continue placing) a story into the supplied rectangle + 'where', updating 'filled' with the actual area that was used. + Returns zero (FZ_PLACE_STORY_RETURN_ALL_FITTED) if all the + content fitted, non-zero if there is more to fit. + + If the FZ_PLACE_STORY_FLAG_NO_OVERFLOW flag is set, then a + return code of FZ_PLACE_STORY_RETURN_OVERFLOW_WIDTH will be + returned when the next item (word) to be placed would not fit + in a rectangle of that given width. + + Note, that filled may not be returned as a strict subset of + where, due to padding/margins at the bottom of pages, and + non-wrapping content extending to the right. + + Subsequent calls will attempt to place the same section of story + again and again, until the placed story is drawn using fz_draw_story, + whereupon subsequent calls to fz_place_story will attempt to place + the unused remainder of the story. + + After this function is called, the DOM is no longer accessible, + and any fz_xml pointer retrieved from fz_story_document is no + longer valid. + + flags: Additional flags controlling layout. Pass 0 if none + required. +*/ +int fz_place_story_flags(fz_context *ctx, fz_story *story, fz_rect where, fz_rect *filled, int flags); + +enum +{ + /* Avoid the usual HTML behaviour of overflowing the box horizontally + * in some circumstances. We now abort the place in such cases and + * return with */ + FZ_PLACE_STORY_FLAG_NO_OVERFLOW = 1, + + /* Specific return codes from fz_place_story_flags. Also + * "non-zero" for 'more to fit'. */ + FZ_PLACE_STORY_RETURN_ALL_FITTED = 0, + FZ_PLACE_STORY_RETURN_OVERFLOW_WIDTH = 2 +}; + +/* + Draw the placed story to the given device. + + This moves the point at which subsequent calls to fz_place_story + will restart placing to the end of what has just been output. +*/ +void fz_draw_story(fz_context *ctx, fz_story *story, fz_device *dev, fz_matrix ctm); + +/* + Reset the position within the story at which the next layout call + will continue to the start of the story. +*/ +void fz_reset_story(fz_context *ctx, fz_story *story); + +/* + Drop the html story. +*/ +void fz_drop_story(fz_context *ctx, fz_story *story); + +/* + Get a borrowed reference to the DOM document pointer for this + story. Do not destroy this reference, it will be destroyed + when the story is laid out. + + This only makes sense before the first placement of the story + or retrieval of the warnings. Once either of those things happen + the DOM representation is destroyed. +*/ +fz_xml *fz_story_document(fz_context *ctx, fz_story *story); + + +typedef struct +{ + /* The overall depth of this element in the box structure. + * This can be used to compare the relative depths of different + * elements, but shouldn't be relied upon not to change between + * different versions of MuPDF. */ + int depth; + + /* The heading level of this element. 0 if not a header, or 1-6 for h1-h6. */ + int heading; + + /* The id for this element. */ + const char *id; + + /* The href for this element. */ + const char *href; + + /* The rectangle for this element. */ + fz_rect rect; + + /* The immediate text for this element. */ + const char *text; + + /* This indicates whether this opens and/or closes this element. + * + * As we traverse the tree we do a depth first search. In order for + * the caller of fz_story_positions to know whether a given element + * is inside another element, we therefore announce 'start' and 'stop' + * for each element. For instance, with: + * + *
+ *

Chapter 1

... + *

Chapter 2

... + * ... + *
+ *
+ *

Chapter 10

... + *

Chapter 11

... + * ... + *
+ * + * We would announce: + * + id='part1' (open) + * + header=1 "Chapter 1" (open/close) + * + header=1 "Chapter 2" (open/close) + * ... + * + id='part1' (close) + * + id='part2' (open) + * + header=1 "Chapter 10" (open/close) + * + header=1 "Chapter 11" (open/close) + * ... + * + id='part2' (close) + * + * If bit 0 is set, then this 'opens' the element. + * If bit 1 is set, then this 'closes' the element. + */ + int open_close; + + /* A count of the number of rectangles that the layout code has split the + * story into so far. After the first layout, this will be 1. If a + * layout is repeated, this number is not incremented. */ + int rectangle_num; +} fz_story_element_position; + +typedef void (fz_story_position_callback)(fz_context *ctx, void *arg, const fz_story_element_position *); + +/* + Enumerate the positions for key blocks in the story. + + This will cause the supplied function to be called with details of each + element in the story that is either a header, or has an id. +*/ +void fz_story_positions(fz_context *ctx, fz_story *story, fz_story_position_callback *cb, void *arg); + +#endif diff --git a/include/mupdf/fitz/stream.h b/include/mupdf/fitz/stream.h index b0571e0..13d1c77 100644 --- a/include/mupdf/fitz/stream.h +++ b/include/mupdf/fitz/stream.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_STREAM_H #define MUPDF_FITZ_STREAM_H @@ -5,12 +27,12 @@ #include "mupdf/fitz/context.h" #include "mupdf/fitz/buffer.h" -/* - fz_file_exists: Return true if the named file exists and is readable. +/** + Return true if the named file exists and is readable. */ int fz_file_exists(fz_context *ctx, const char *path); -/* +/** fz_stream is a buffered reader capable of seeking in both directions. @@ -19,24 +41,37 @@ int fz_file_exists(fz_context *ctx, const char *path); Only the data between rp and wp is valid. */ -typedef struct fz_stream_s fz_stream; +typedef struct fz_stream fz_stream; -/* - fz_open_file: Open the named file and wrap it in a stream. +/** + Open the named file and wrap it in a stream. - filename: Path to a file. On non-Windows machines the filename should - be exactly as it would be passed to fopen(2). On Windows machines, the - path should be UTF-8 encoded so that non-ASCII characters can be - represented. Other platforms do the encoding as standard anyway (and - in most cases, particularly for MacOS and Linux, the encoding they - use is UTF-8 anyway). + filename: Path to a file. On non-Windows machines the filename + should be exactly as it would be passed to fopen(2). On Windows + machines, the path should be UTF-8 encoded so that non-ASCII + characters can be represented. Other platforms do the encoding + as standard anyway (and in most cases, particularly for MacOS + and Linux, the encoding they use is UTF-8 anyway). */ fz_stream *fz_open_file(fz_context *ctx, const char *filename); -fz_stream *fz_open_file_progressive(fz_context *ctx, const char *filename, int bps); +/** + Do the same as fz_open_file, but delete the file upon close. +*/ +fz_stream *fz_open_file_autodelete(fz_context *ctx, const char *filename); -/* - fz_open_file_w: Open the named file and wrap it in a stream. +/** + Open the named file and wrap it in a stream. + + Does the same as fz_open_file, but in the event the file + does not open, it will return NULL rather than throw an + exception. +*/ +fz_stream *fz_try_open_file(fz_context *ctx, const char *name); + +#ifdef _WIN32 +/** + Open the named file and wrap it in a stream. This function is only available when compiling for Win32. @@ -44,12 +79,21 @@ fz_stream *fz_open_file_progressive(fz_context *ctx, const char *filename, int b to _wfopen(). */ fz_stream *fz_open_file_w(fz_context *ctx, const wchar_t *filename); +#endif /* _WIN32 */ -/* - fz_open_memory: Open a block of memory as a stream. +/** + Return the filename (UTF-8 encoded) from which a stream was opened. - data: Pointer to start of data block. Ownership of the data block is - NOT passed in. + Returns NULL if the filename is not available (or the stream was + opened from a source other than a file). +*/ +const char *fz_stream_filename(fz_context *ctx, fz_stream *stm); + +/** + Open a block of memory as a stream. + + data: Pointer to start of data block. Ownership of the data + block is NOT passed in. len: Number of bytes in data block. @@ -58,19 +102,19 @@ fz_stream *fz_open_file_w(fz_context *ctx, const wchar_t *filename); */ fz_stream *fz_open_memory(fz_context *ctx, const unsigned char *data, size_t len); -/* - fz_open_buffer: Open a buffer as a stream. +/** + Open a buffer as a stream. - buf: The buffer to open. Ownership of the buffer is NOT passed in - (this function takes its own reference). + buf: The buffer to open. Ownership of the buffer is NOT passed + in (this function takes its own reference). Returns pointer to newly created stream. May throw exceptions on failure to allocate. */ fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf); -/* - fz_open_leecher: Attach a filter to a stream that will store any +/** + Attach a filter to a stream that will store any characters read from the stream into the supplied buffer. chain: The underlying stream to leech from. @@ -83,33 +127,46 @@ fz_stream *fz_open_buffer(fz_context *ctx, fz_buffer *buf); */ fz_stream *fz_open_leecher(fz_context *ctx, fz_stream *chain, fz_buffer *buf); -/* - fz_drop_stream: Close an open stream. +/** + Increments the reference count for a stream. Returns the same + pointer. - Drops a reference for the stream. Once no references remain - the stream will be closed, as will any file descriptor the - stream is using. + Never throws exceptions. +*/ +fz_stream *fz_keep_stream(fz_context *ctx, fz_stream *stm); + +/** + Decrements the reference count for a stream. + + When the reference count for the stream hits zero, frees the + storage used for the fz_stream itself, and (usually) + releases the underlying resources that the stream is based upon + (depends on the method used to open the stream initially). */ void fz_drop_stream(fz_context *ctx, fz_stream *stm); -/* - fz_tell: return the current reading position within a stream +/** + return the current reading position within a stream */ int64_t fz_tell(fz_context *ctx, fz_stream *stm); -/* - fz_seek: Seek within a stream. +/** + Seek within a stream. stm: The stream to seek within. offset: The offset to seek to. whence: From where the offset is measured (see fseek). + SEEK_SET - start of stream. + SEEK_CUR - current position. + SEEK_END - end of stream. + */ void fz_seek(fz_context *ctx, fz_stream *stm, int64_t offset, int whence); -/* - fz_read: Read from a stream into a given data block. +/** + Read from a stream into a given data block. stm: The stream to read from. @@ -121,8 +178,8 @@ void fz_seek(fz_context *ctx, fz_stream *stm, int64_t offset, int whence); */ size_t fz_read(fz_context *ctx, fz_stream *stm, unsigned char *data, size_t len); -/* - fz_skip: Read from a stream discarding data. +/** + Read from a stream discarding data. stm: The stream to read from. @@ -132,8 +189,8 @@ size_t fz_read(fz_context *ctx, fz_stream *stm, unsigned char *data, size_t len) */ size_t fz_skip(fz_context *ctx, fz_stream *stm, size_t len); -/* - fz_read_all: Read all of a stream into a buffer. +/** + Read all of a stream into a buffer. stm: The stream to read from @@ -144,12 +201,20 @@ size_t fz_skip(fz_context *ctx, fz_stream *stm, size_t len); */ fz_buffer *fz_read_all(fz_context *ctx, fz_stream *stm, size_t initial); -/* - fz_read_file: Read all the contents of a file into a buffer. +/** + Read all the contents of a file into a buffer. */ fz_buffer *fz_read_file(fz_context *ctx, const char *filename); -/* +/** + Read all the contents of a file into a buffer. + + Returns NULL if the file does not exist, otherwise + behaves exactly as fz_read_file. +*/ +fz_buffer *fz_try_read_file(fz_context *ctx, const char *filename); + +/** fz_read_[u]int(16|24|32|64)(_le)? Read a 16/32/64 bit signed/unsigned integer from stream, @@ -175,41 +240,40 @@ int16_t fz_read_int16_le(fz_context *ctx, fz_stream *stm); int32_t fz_read_int32_le(fz_context *ctx, fz_stream *stm); int64_t fz_read_int64_le(fz_context *ctx, fz_stream *stm); -/* - fz_read_string: Read a null terminated string from the stream into +float fz_read_float_le(fz_context *ctx, fz_stream *stm); +float fz_read_float(fz_context *ctx, fz_stream *stm); + +/** + Read a null terminated string from the stream into a buffer of a given length. The buffer will be null terminated. - Throws on failure (including the failure to fit the entire string - including the terminator into the buffer). + Throws on failure (including the failure to fit the entire + string including the terminator into the buffer). */ void fz_read_string(fz_context *ctx, fz_stream *stm, char *buffer, int len); -enum -{ - FZ_STREAM_META_PROGRESSIVE = 1, - FZ_STREAM_META_LENGTH = 2 -}; +/** + Read a utf-8 rune from a stream. -/* - fz_stream_meta: Perform a meta call on a stream (typically to - request meta information about a stream). - - stm: The stream to query. - - key: The meta request identifier. - - size: Meta request specific parameter - typically the size of - the data block pointed to by ptr. - - ptr: Meta request specific parameter - typically a pointer to - a block of data to be filled in. - - Returns -1 if this stream does not support this meta operation, - or a meta operation specific return value. + In the event of encountering badly formatted utf-8 codes + (such as a leading code with an unexpected number of following + codes) no error/exception is given, but undefined values may be + returned. */ -int fz_stream_meta(fz_context *ctx, fz_stream *stm, int key, int size, void *ptr); +int fz_read_rune(fz_context *ctx, fz_stream *in); -/* - fz_stream_next_fn: A function type for use when implementing +/** + Read a utf-16 rune from a stream. (little endian and + big endian respectively). + + In the event of encountering badly formatted utf-16 codes + (mismatched surrogates) no error/exception is given, but + undefined values may be returned. +*/ +int fz_read_utf16_le(fz_context *ctx, fz_stream *stm); +int fz_read_utf16_be(fz_context *ctx, fz_stream *stm); + +/** + A function type for use when implementing fz_streams. The supplied function of this type is called whenever data is required, and the current buffer is empty. @@ -226,8 +290,8 @@ int fz_stream_meta(fz_context *ctx, fz_stream *stm, int key, int size, void *ptr */ typedef int (fz_stream_next_fn)(fz_context *ctx, fz_stream *stm, size_t max); -/* - fz_stream_drop_fn: A function type for use when implementing +/** + A function type for use when implementing fz_streams. The supplied function of this type is called when the stream is dropped, to release the stream specific state information. @@ -236,8 +300,8 @@ typedef int (fz_stream_next_fn)(fz_context *ctx, fz_stream *stm, size_t max); */ typedef void (fz_stream_drop_fn)(fz_context *ctx, void *state); -/* - fz_stream_seek_fn: A function type for use when implementing +/** + A function type for use when implementing fz_streams. The supplied function of this type is called when fz_seek is requested, and the arguments are as defined for fz_seek. @@ -246,21 +310,12 @@ typedef void (fz_stream_drop_fn)(fz_context *ctx, void *state); */ typedef void (fz_stream_seek_fn)(fz_context *ctx, fz_stream *stm, int64_t offset, int whence); -/* - fz_stream_meta_fn: A function type for use when implementing - fz_streams. The supplied function of this type is called when - fz_meta is requested, and the arguments are as defined for - fz_meta. - - The stream can find it's private state in stm->state. -*/ -typedef int (fz_stream_meta_fn)(fz_context *ctx, fz_stream *stm, int key, int size, void *ptr); - -struct fz_stream_s +struct fz_stream { int refs; int error; int eof; + int progressive; int64_t pos; int avail; int bits; @@ -269,11 +324,10 @@ struct fz_stream_s fz_stream_next_fn *next; fz_stream_drop_fn *drop; fz_stream_seek_fn *seek; - fz_stream_meta_fn *meta; }; -/* - fz_new_stream: Create a new stream object with the given +/** + Create a new stream object with the given internal state and function pointers. state: Internal state (opaque to everything but implementation). @@ -287,10 +341,8 @@ struct fz_stream_s */ fz_stream *fz_new_stream(fz_context *ctx, void *state, fz_stream_next_fn *next, fz_stream_drop_fn *drop); -fz_stream *fz_keep_stream(fz_context *ctx, fz_stream *stm); - -/* - fz_read_best: Attempt to read a stream into a buffer. If truncated +/** + Attempt to read a stream into a buffer. If truncated is NULL behaves as fz_read_all, sets a truncated flag in case of error. @@ -300,21 +352,37 @@ fz_stream *fz_keep_stream(fz_context *ctx, fz_stream *stm); truncated: Flag to store success/failure indication in. + worst_case: 0 for unknown, otherwise an upper bound for the + size of the stream. + Returns a buffer created from reading from the stream. */ -fz_buffer *fz_read_best(fz_context *ctx, fz_stream *stm, size_t initial, int *truncated); +fz_buffer *fz_read_best(fz_context *ctx, fz_stream *stm, size_t initial, int *truncated, size_t worst_case); -/* - fz_read_line: Read a line from stream into the buffer until either a - terminating newline or EOF, which it replaces with a null byte ('\0'). +/** + Read a line from stream into the buffer until either a + terminating newline or EOF, which it replaces with a null byte + ('\0'). - Returns buf on success, and NULL when end of file occurs while no characters - have been read. + Returns buf on success, and NULL when end of file occurs while + no characters have been read. */ char *fz_read_line(fz_context *ctx, fz_stream *stm, char *buf, size_t max); -/* - fz_available: Ask how many bytes are available immediately from +/** + Skip over a given string in a stream. Return 0 if successfully + skipped, non-zero otherwise. As many characters will be skipped + over as matched in the string. +*/ +int fz_skip_string(fz_context *ctx, fz_stream *stm, const char *str); + +/** + Skip over whitespace (bytes <= 32) in a stream. +*/ +void fz_skip_space(fz_context *ctx, fz_stream *stm); + +/** + Ask how many bytes are available immediately from a given stream. stm: The stream to read from. @@ -343,6 +411,7 @@ static inline size_t fz_available(fz_context *ctx, fz_stream *stm, size_t max) fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); + fz_report_error(ctx); fz_warn(ctx, "read error; treating as end of file"); stm->error = 1; c = EOF; @@ -356,8 +425,8 @@ static inline size_t fz_available(fz_context *ctx, fz_stream *stm, size_t max) return stm->wp - stm->rp; } -/* - fz_read_byte: Read the next byte from a stream. +/** + Read the next byte from a stream. stm: The stream t read from. @@ -377,6 +446,7 @@ static inline int fz_read_byte(fz_context *ctx, fz_stream *stm) fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); + fz_report_error(ctx); fz_warn(ctx, "read error; treating as end of file"); stm->error = 1; c = EOF; @@ -386,8 +456,8 @@ static inline int fz_read_byte(fz_context *ctx, fz_stream *stm) return c; } -/* - fz_peek_byte: Peek at the next byte in a stream. +/** + Peek at the next byte in a stream. stm: The stream to peek at. @@ -411,6 +481,7 @@ static inline int fz_peek_byte(fz_context *ctx, fz_stream *stm) fz_catch(ctx) { fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); + fz_report_error(ctx); fz_warn(ctx, "read error; treating as end of file"); stm->error = 1; c = EOF; @@ -420,8 +491,8 @@ static inline int fz_peek_byte(fz_context *ctx, fz_stream *stm) return c; } -/* - fz_unread_byte: Unread the single last byte successfully +/** + Unread the single last byte successfully read from a stream. Do not call this without having successfully read a byte. @@ -432,6 +503,13 @@ static inline void fz_unread_byte(fz_context *ctx FZ_UNUSED, fz_stream *stm) stm->rp--; } +/** + Query if the stream has reached EOF (during normal bytewise + reading). + + See fz_is_eof_bits for the equivalent function for bitwise + reading. +*/ static inline int fz_is_eof(fz_context *ctx, fz_stream *stm) { if (stm->rp == stm->wp) @@ -443,8 +521,8 @@ static inline int fz_is_eof(fz_context *ctx, fz_stream *stm) return 0; } -/* - fz_read_bits: Read the next n bits from a stream (assumed to +/** + Read the next n bits from a stream (assumed to be packed most significant bit first). stm: The stream to read from. @@ -486,8 +564,8 @@ static inline unsigned int fz_read_bits(fz_context *ctx, fz_stream *stm, int n) return x; } -/* - fz_read_rbits: Read the next n bits from a stream (assumed to +/** + Read the next n bits from a stream (assumed to be packed least significant bit first). stm: The stream to read from. @@ -535,8 +613,8 @@ static inline unsigned int fz_read_rbits(fz_context *ctx, fz_stream *stm, int n) return x; } -/* - fz_sync_bits: Called after reading bits to tell the stream +/** + Called after reading bits to tell the stream that we are about to return to reading bytewise. Resyncs the stream to whole byte boundaries. */ @@ -545,9 +623,24 @@ static inline void fz_sync_bits(fz_context *ctx FZ_UNUSED, fz_stream *stm) stm->avail = 0; } +/** + Query if the stream has reached EOF (during bitwise + reading). + + See fz_is_eof for the equivalent function for bytewise + reading. +*/ static inline int fz_is_eof_bits(fz_context *ctx, fz_stream *stm) { return fz_is_eof(ctx, stm) && (stm->avail == 0 || stm->bits == EOF); } +/* Implementation details: subject to change. */ + +/** + Create a stream from a FILE * that will not be closed + when the stream is dropped. +*/ +fz_stream *fz_open_file_ptr_no_close(fz_context *ctx, FILE *file); + #endif diff --git a/include/mupdf/fitz/string-util.h b/include/mupdf/fitz/string-util.h index 13941d6..4acc644 100644 --- a/include/mupdf/fitz/string-util.h +++ b/include/mupdf/fitz/string-util.h @@ -1,33 +1,66 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_STRING_H #define MUPDF_FITZ_STRING_H #include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" -/* The Unicode character used to incoming character whose value is unknown or unrepresentable. */ +/* The Unicode character used to incoming character whose value is + * unknown or unrepresentable. */ #define FZ_REPLACEMENT_CHARACTER 0xFFFD -/* +/** Safe string functions */ -/* - fz_strsep: Given a pointer to a C string (or a pointer to NULL) break - it at the first occurrence of a delimiter char (from a given set). +/** + Return strlen(s), if that is less than maxlen, or maxlen if + there is no null byte ('\0') among the first maxlen bytes. +*/ +size_t fz_strnlen(const char *s, size_t maxlen); - stringp: Pointer to a C string pointer (or NULL). Updated on exit to - point to the first char of the string after the delimiter that was - found. The string pointed to by stringp will be corrupted by this - call (as the found delimiter will be overwritten by 0). +/** + Given a pointer to a C string (or a pointer to NULL) break + it at the first occurrence of a delimiter char (from a given + set). + + stringp: Pointer to a C string pointer (or NULL). Updated on + exit to point to the first char of the string after the + delimiter that was found. The string pointed to by stringp will + be corrupted by this call (as the found delimiter will be + overwritten by 0). delim: A C string of acceptable delimiter characters. - Returns a pointer to a C string containing the chars of stringp up - to the first delimiter char (or the end of the string), or NULL. + Returns a pointer to a C string containing the chars of stringp + up to the first delimiter char (or the end of the string), or + NULL. */ char *fz_strsep(char **stringp, const char *delim); -/* - fz_strlcpy: Copy at most n-1 chars of a string into a destination +/** + Copy at most n-1 chars of a string into a destination buffer with null termination, returning the real length of the initial string (excluding terminator). @@ -41,8 +74,8 @@ char *fz_strsep(char **stringp, const char *delim); */ size_t fz_strlcpy(char *dst, const char *src, size_t n); -/* - fz_strlcat: Concatenate 2 strings, with a maximum length. +/** + Concatenate 2 strings, with a maximum length. dst: pointer to first string in a buffer of n bytes. @@ -50,50 +83,108 @@ size_t fz_strlcpy(char *dst, const char *src, size_t n); n: Size (in bytes) of buffer that dst is in. - Returns the real length that a concatenated dst + src would have been - (not including terminator). + Returns the real length that a concatenated dst + src would have + been (not including terminator). */ size_t fz_strlcat(char *dst, const char *src, size_t n); -/* - fz_dirname: extract the directory component from a path. +/** + Find the start of the first occurrence of the substring needle in haystack. +*/ +void *fz_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); + +/** + extract the directory component from a path. */ void fz_dirname(char *dir, const char *path, size_t dirsize); -/* - fz_urldecode: decode url escapes. +/** + Find the filename component in a path. +*/ +const char *fz_basename(const char *path); + +/** + Like fz_decode_uri_component but in-place. */ char *fz_urldecode(char *url); -/* - fz_format_output_path: create output file name using a template. - If the path contains %[0-9]*d, the first such pattern will be replaced - with the page number. If the template does not contain such a pattern, the page - number will be inserted before the file suffix. If the template does not have - a file suffix, the page number will be added to the end. +/** + * Return a new string representing the unencoded version of the given URI. + * This decodes all escape sequences except those that would result in a reserved + * character that are part of the URI syntax (; / ? : @ & = + $ , #). + */ +char *fz_decode_uri(fz_context *ctx, const char *s); + +/** + * Return a new string representing the unencoded version of the given URI component. + * This decodes all escape sequences! + */ +char *fz_decode_uri_component(fz_context *ctx, const char *s); + +/** + * Return a new string representing the provided string encoded as a URI. + */ +char *fz_encode_uri(fz_context *ctx, const char *s); + +/** + * Return a new string representing the provided string encoded as an URI component. + * This also encodes the special reserved characters (; / ? : @ & = + $ , #). + */ +char *fz_encode_uri_component(fz_context *ctx, const char *s); + +/** + * Return a new string representing the provided string encoded as an URI path name. + * This also encodes the special reserved characters except /. + */ +char *fz_encode_uri_pathname(fz_context *ctx, const char *s); + +/** + create output file name using a template. + + If the path contains %[0-9]*d, the first such pattern will be + replaced with the page number. If the template does not contain + such a pattern, the page number will be inserted before the + filename extension. If the template does not have a filename + extension, the page number will be added to the end. */ void fz_format_output_path(fz_context *ctx, char *path, size_t size, const char *fmt, int page); -/* - fz_cleanname: rewrite path to the shortest string that names the same path. +/** + rewrite path to the shortest string that names the same path. - Eliminates multiple and trailing slashes, interprets "." and "..". - Overwrites the string in place. + Eliminates multiple and trailing slashes, interprets "." and + "..". Overwrites the string in place. */ char *fz_cleanname(char *name); -/* +/** + rewrite path to the shortest string that names the same path. + + Eliminates multiple and trailing slashes, interprets "." and + "..". Allocates a new string that the caller must free. +*/ +char *fz_cleanname_strdup(fz_context *ctx, const char *name); + +/** + Resolve a path to an absolute file name. + The resolved path buffer must be of at least PATH_MAX size. +*/ +char *fz_realpath(const char *path, char *resolved_path); + +/** Case insensitive (ASCII only) string comparison. */ int fz_strcasecmp(const char *a, const char *b); +int fz_strncasecmp(const char *a, const char *b, size_t n); -/* - FZ_UTFMAX: Maximum number of bytes in a decoded rune (maximum length returned by fz_chartorune). +/** + FZ_UTFMAX: Maximum number of bytes in a decoded rune (maximum + length returned by fz_chartorune). */ enum { FZ_UTFMAX = 4 }; -/* - fz_chartorune: UTF8 decode a single rune from a sequence of chars. +/** + UTF8 decode a single rune from a sequence of chars. rune: Pointer to an int to assign the decoded 'rune' to. @@ -103,8 +194,8 @@ enum { FZ_UTFMAX = 4 }; */ int fz_chartorune(int *rune, const char *str); -/* - fz_runetochar: UTF8 encode a rune to a sequence of chars. +/** + UTF8 encode a rune to a sequence of chars. str: Pointer to a place to put the UTF8 encoded character. @@ -114,17 +205,42 @@ int fz_chartorune(int *rune, const char *str); */ int fz_runetochar(char *str, int rune); -/* - fz_runelen: Count how many chars are required to represent a rune. +/** + Count how many chars are required to represent a rune. rune: The rune to encode. - Returns the number of bytes required to represent this run in UTF8. + Returns the number of bytes required to represent this run in + UTF8. */ int fz_runelen(int rune); -/* - fz_utflen: Count how many runes the UTF-8 encoded string +/** + Compute the index of a rune in a string. + + str: Pointer to beginning of a string. + + p: Pointer to a char in str. + + Returns the index of the rune pointed to by p in str. +*/ +int fz_runeidx(const char *str, const char *p); + +/** + Obtain a pointer to the char representing the rune + at a given index. + + str: Pointer to beginning of a string. + + idx: Index of a rune to return a char pointer to. + + Returns a pointer to the char where the desired rune starts, + or NULL if the string ends before the index is reached. +*/ +const char *fz_runeptr(const char *str, int idx); + +/** + Count how many runes the UTF-8 encoded string consists of. s: The UTF-8 encoded, NUL-terminated text string. @@ -134,33 +250,37 @@ int fz_runelen(int rune); int fz_utflen(const char *s); /* - fz_strtof: Locale-independent decimal to binary - conversion. On overflow return (-)INFINITY and set errno to ERANGE. On - underflow return 0 and set errno to ERANGE. Special inputs (case - insensitive): "NAN", "INF" or "INFINITY". + Convert a wchar string into a new heap allocated utf8 one. +*/ +char *fz_utf8_from_wchar(fz_context *ctx, const wchar_t *s); + +/* + Convert a utf8 string into a new heap allocated wchar one. +*/ +wchar_t *fz_wchar_from_utf8(fz_context *ctx, const char *path); + + +/** + Locale-independent decimal to binary conversion. On overflow + return (-)INFINITY and set errno to ERANGE. On underflow return + 0 and set errno to ERANGE. Special inputs (case insensitive): + "NAN", "INF" or "INFINITY". */ float fz_strtof(const char *s, char **es); -/* - fz_strtof_no_exp: Like fz_strtof, but does not recognize exponent - format. So fz_strtof_no_exp("1.5e20", &tail) will return 1.5 and tail - will point to "e20". -*/ - -float fz_strtof_no_exp(const char *string, char **tailptr); -/* - fz_grisu: Compute decimal integer m, exp such that: - f = m * 10^exp - m is as short as possible without losing exactness - Assumes special cases (0, NaN, +Inf, -Inf) have been handled. -*/ int fz_grisu(float f, char *s, int *exp); -/* +/** Check and parse string into page ranges: - ( ','? ([0-9]+|'N') ( '-' ([0-9]+|N) )? )+ + /,?(-?\d+|N)(-(-?\d+|N))?/ */ int fz_is_page_range(fz_context *ctx, const char *s); const char *fz_parse_page_range(fz_context *ctx, const char *s, int *a, int *b, int n); +/** + Unicode aware tolower and toupper functions. +*/ +int fz_tolower(int c); +int fz_toupper(int c); + #endif diff --git a/include/mupdf/fitz/structured-text.h b/include/mupdf/fitz/structured-text.h index b062813..ae108b4 100644 --- a/include/mupdf/fitz/structured-text.h +++ b/include/mupdf/fitz/structured-text.h @@ -1,59 +1,151 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_STRUCTURED_TEXT_H #define MUPDF_FITZ_STRUCTURED_TEXT_H #include "mupdf/fitz/system.h" +#include "mupdf/fitz/types.h" #include "mupdf/fitz/context.h" #include "mupdf/fitz/geometry.h" #include "mupdf/fitz/font.h" -#include "mupdf/fitz/colorspace.h" #include "mupdf/fitz/image.h" #include "mupdf/fitz/output.h" #include "mupdf/fitz/device.h" +#include "mupdf/fitz/pool.h" -/* +/** + Simple text layout (for use with annotation editing primarily). +*/ +typedef struct fz_layout_char +{ + float x, advance; + const char *p; /* location in source text of character */ + struct fz_layout_char *next; +} fz_layout_char; + +typedef struct fz_layout_line +{ + float x, y, font_size; + const char *p; /* location in source text of start of line */ + fz_layout_char *text; + struct fz_layout_line *next; +} fz_layout_line; + +typedef struct +{ + fz_pool *pool; + fz_matrix matrix; + fz_matrix inv_matrix; + fz_layout_line *head, **tailp; + fz_layout_char **text_tailp; +} fz_layout_block; + +/** + Create a new layout block, with new allocation pool, zero + matrices, and initialise linked pointers. +*/ +fz_layout_block *fz_new_layout(fz_context *ctx); + +/** + Drop layout block. Free the pool, and linked blocks. + + Never throws exceptions. +*/ +void fz_drop_layout(fz_context *ctx, fz_layout_block *block); + +/** + Add a new line to the end of the layout block. +*/ +void fz_add_layout_line(fz_context *ctx, fz_layout_block *block, float x, float y, float h, const char *p); + +/** + Add a new char to the line at the end of the layout block. +*/ +void fz_add_layout_char(fz_context *ctx, fz_layout_block *block, float x, float w, const char *p); + +/** Text extraction device: Used for searching, format conversion etc. (In development - Subject to change in future versions) */ -typedef struct fz_stext_char_s fz_stext_char; -typedef struct fz_stext_line_s fz_stext_line; -typedef struct fz_stext_block_s fz_stext_block; -typedef struct fz_stext_page_s fz_stext_page; +typedef struct fz_stext_char fz_stext_char; +typedef struct fz_stext_line fz_stext_line; +typedef struct fz_stext_block fz_stext_block; -/* - FZ_STEXT_PRESERVE_LIGATURES: If this option is activated ligatures - are passed through to the application in their original form. If - this option is deactivated ligatures are expanded into their - constituent parts, e.g. the ligature ffi is expanded into three - separate characters f, f and i. +/** + FZ_STEXT_PRESERVE_LIGATURES: If this option is activated + ligatures are passed through to the application in their + original form. If this option is deactivated ligatures are + expanded into their constituent parts, e.g. the ligature ffi is + expanded into three separate characters f, f and i. - FZ_STEXT_PRESERVE_WHITESPACE: If this option is activated whitespace - is passed through to the application in its original form. If this - option is deactivated any type of horizontal whitespace (including - horizontal tabs) will be replaced with space characters of variable - width. + FZ_STEXT_PRESERVE_WHITESPACE: If this option is activated + whitespace is passed through to the application in its original + form. If this option is deactivated any type of horizontal + whitespace (including horizontal tabs) will be replaced with + space characters of variable width. - FZ_STEXT_PRESERVE_IMAGES: If this option is set, then images will - be stored in the structured text structure. The default is to ignore - all images. + FZ_STEXT_PRESERVE_IMAGES: If this option is set, then images + will be stored in the structured text structure. The default is + to ignore all images. + + FZ_STEXT_INHIBIT_SPACES: If this option is set, we will not try + to add missing space characters where there are large gaps + between characters. + + FZ_STEXT_DEHYPHENATE: If this option is set, hyphens at the + end of a line will be removed and the lines will be merged. + + FZ_STEXT_PRESERVE_SPANS: If this option is set, spans on the same line + will not be merged. Each line will thus be a span of text with the same + font, colour, and size. + + FZ_STEXT_MEDIABOX_CLIP: If this option is set, characters entirely + outside each page's mediabox will be ignored. */ enum { FZ_STEXT_PRESERVE_LIGATURES = 1, FZ_STEXT_PRESERVE_WHITESPACE = 2, FZ_STEXT_PRESERVE_IMAGES = 4, + FZ_STEXT_INHIBIT_SPACES = 8, + FZ_STEXT_DEHYPHENATE = 16, + FZ_STEXT_PRESERVE_SPANS = 32, + FZ_STEXT_MEDIABOX_CLIP = 64, + FZ_STEXT_USE_CID_FOR_UNKNOWN_UNICODE = 128, }; -/* - A text page is a list of blocks, together with an overall bounding box. +/** + A text page is a list of blocks, together with an overall + bounding box. */ -struct fz_stext_page_s +typedef struct { fz_pool *pool; fz_rect mediabox; fz_stext_block *first_block, *last_block; -}; +} fz_stext_page; enum { @@ -61,10 +153,11 @@ enum FZ_STEXT_BLOCK_IMAGE = 1 }; -/* - A text block is a list of lines of text (typically a paragraph), or an image. +/** + A text block is a list of lines of text (typically a paragraph), + or an image. */ -struct fz_stext_block_s +struct fz_stext_block { int type; fz_rect bbox; @@ -75,10 +168,10 @@ struct fz_stext_block_s fz_stext_block *prev, *next; }; -/* +/** A text line is a list of characters that share a common baseline. */ -struct fz_stext_line_s +struct fz_stext_line { int wmode; /* 0 for horizontal, 1 for vertical */ fz_point dir; /* normalized direction of baseline */ @@ -87,111 +180,186 @@ struct fz_stext_line_s fz_stext_line *prev, *next; }; -/* - A text char is a unicode character, the style in which is appears, and - the point at which it is positioned. +/** + A text char is a unicode character, the style in which is + appears, and the point at which it is positioned. */ -struct fz_stext_char_s +struct fz_stext_char { - int c; + int c; /* unicode character value */ + int bidi; /* even for LTR, odd for RTL */ + int color; /* sRGB hex color */ fz_point origin; - fz_rect bbox; + fz_quad quad; float size; fz_font *font; fz_stext_char *next; }; -extern const char *fz_stext_options_usage; +FZ_DATA extern const char *fz_stext_options_usage; -int fz_stext_char_count(fz_context *ctx, fz_stext_page *page); -const fz_stext_char *fz_stext_char_at(fz_context *ctx, fz_stext_page *page, int idx); +/** + Create an empty text page. -/* - fz_new_stext_page: Create an empty text page. - - The text page is filled out by the text device to contain the blocks - and lines of text on the page. + The text page is filled out by the text device to contain the + blocks and lines of text on the page. mediabox: optional mediabox information. */ -fz_stext_page *fz_new_stext_page(fz_context *ctx, const fz_rect *mediabox); +fz_stext_page *fz_new_stext_page(fz_context *ctx, fz_rect mediabox); void fz_drop_stext_page(fz_context *ctx, fz_stext_page *page); -/* - fz_print_stext_page_as_html: Output a page to a file in HTML (visual) format. +/** + Output structured text to a file in HTML (visual) format. */ -void fz_print_stext_page_as_html(fz_context *ctx, fz_output *out, fz_stext_page *page); +void fz_print_stext_page_as_html(fz_context *ctx, fz_output *out, fz_stext_page *page, int id); void fz_print_stext_header_as_html(fz_context *ctx, fz_output *out); void fz_print_stext_trailer_as_html(fz_context *ctx, fz_output *out); -/* - fz_print_stext_page_as_xhtml: Output a page to a file in XHTML (semantic) format. +/** + Output structured text to a file in XHTML (semantic) format. */ -void fz_print_stext_page_as_xhtml(fz_context *ctx, fz_output *out, fz_stext_page *page); +void fz_print_stext_page_as_xhtml(fz_context *ctx, fz_output *out, fz_stext_page *page, int id); void fz_print_stext_header_as_xhtml(fz_context *ctx, fz_output *out); void fz_print_stext_trailer_as_xhtml(fz_context *ctx, fz_output *out); -/* - fz_print_stext_page_as_xml: Output a page to a file in XML format. +/** + Output structured text to a file in XML format. */ -void fz_print_stext_page_as_xml(fz_context *ctx, fz_output *out, fz_stext_page *page); +void fz_print_stext_page_as_xml(fz_context *ctx, fz_output *out, fz_stext_page *page, int id); -/* - fz_print_stext_page_as_text: Output a page to a file in UTF-8 format. +/** + Output structured text to a file in JSON format. +*/ +void fz_print_stext_page_as_json(fz_context *ctx, fz_output *out, fz_stext_page *page, float scale); + +/** + Output structured text to a file in plain-text UTF-8 format. */ void fz_print_stext_page_as_text(fz_context *ctx, fz_output *out, fz_stext_page *page); -/* - fz_search_stext_page: Search for occurrence of 'needle' in text page. +/** + Search for occurrence of 'needle' in text page. - Return the number of hits and store hit bboxes in the passed in array. + Return the number of hits and store hit quads in the passed in + array. - NOTE: This is an experimental interface and subject to change without notice. + NOTE: This is an experimental interface and subject to change + without notice. */ -int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, fz_rect *hit_bbox, int hit_max); +int fz_search_stext_page(fz_context *ctx, fz_stext_page *text, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max); -/* - fz_highlight_selection: Return a list of rectangles to highlight lines inside the selection points. +/** + Return a list of quads to highlight lines inside the selection + points. */ -int fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, fz_rect *hit_bbox, int hit_max); +int fz_highlight_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, fz_quad *quads, int max_quads); -/* - fz_copy_selection: Return a newly allocated UTF-8 string with the text for a given selection. +enum +{ + FZ_SELECT_CHARS, + FZ_SELECT_WORDS, + FZ_SELECT_LINES, +}; - crlf: If true, write "\r\n" style line endings (otherwise "\n" only). +fz_quad fz_snap_selection(fz_context *ctx, fz_stext_page *page, fz_point *ap, fz_point *bp, int mode); + +/** + Return a newly allocated UTF-8 string with the text for a given + selection. + + crlf: If true, write "\r\n" style line endings (otherwise "\n" + only). */ char *fz_copy_selection(fz_context *ctx, fz_stext_page *page, fz_point a, fz_point b, int crlf); -/* - struct fz_stext_options: Options for creating a pixmap and draw device. -*/ -typedef struct fz_stext_options_s fz_stext_options; +/** + Return a newly allocated UTF-8 string with the text for a given + selection rectangle. -struct fz_stext_options_s + crlf: If true, write "\r\n" style line endings (otherwise "\n" + only). +*/ +char *fz_copy_rectangle(fz_context *ctx, fz_stext_page *page, fz_rect area, int crlf); + +/** + Options for creating structured text. +*/ +typedef struct { int flags; -}; + float scale; +} fz_stext_options; -/* - fz_parse_stext_options: Parse stext device options from a comma separated key-value string. +/** + Parse stext device options from a comma separated key-value + string. */ fz_stext_options *fz_parse_stext_options(fz_context *ctx, fz_stext_options *opts, const char *string); -/* - fz_new_stext_device: Create a device to extract the text on a page. +/** + Create a device to extract the text on a page. Gather the text on a page into blocks and lines. - The reading order is taken from the order the text is drawn in the - source file, so may not be accurate. + The reading order is taken from the order the text is drawn in + the source file, so may not be accurate. page: The text page to which content should be added. This will usually be a newly created (empty) text page, but it can be one - containing data already (for example when merging multiple pages, - or watermarking). + containing data already (for example when merging multiple + pages, or watermarking). options: Options to configure the stext device. */ fz_device *fz_new_stext_device(fz_context *ctx, fz_stext_page *page, const fz_stext_options *options); +/** + Create a device to OCR the text on the page. + + Renders the page internally to a bitmap that is then OCRd. Text + is then forwarded onto the target device. + + target: The target device to receive the OCRd text. + + ctm: The transform to apply to the mediabox to get the size for + the rendered page image. Also used to calculate the resolution + for the page image. In general, this will be the same as the CTM + that you pass to fz_run_page (or fz_run_display_list) to feed + this device. + + mediabox: The mediabox (in points). Combined with the CTM to get + the bounds of the pixmap used internally for the rendered page + image. + + with_list: If with_list is false, then all non-text operations + are forwarded instantly to the target device. This results in + the target device seeing all NON-text operations, followed by + all the text operations (derived from OCR). + + If with_list is true, then all the marking operations are + collated into a display list which is then replayed to the + target device at the end. + + language: NULL (for "eng"), or a pointer to a string to describe + the languages/scripts that should be used for OCR (e.g. + "eng,ara"). + + datadir: NULL (for ""), or a pointer to a path string otherwise + provided to Tesseract in the TESSDATA_PREFIX environment variable. + + progress: NULL, or function to be called periodically to indicate + progress. Return 0 to continue, or 1 to cancel. progress_arg is + returned as the void *. The int is a value between 0 and 100 to + indicate progress. + + progress_arg: A void * value to be parrotted back to the progress + function. +*/ +fz_device *fz_new_ocr_device(fz_context *ctx, fz_device *target, fz_matrix ctm, fz_rect mediabox, int with_list, const char *language, + const char *datadir, int (*progress)(fz_context *, void *, int), void *progress_arg); + +fz_document *fz_open_reflowed_document(fz_context *ctx, fz_document *underdoc, const fz_stext_options *opts); + + #endif diff --git a/include/mupdf/fitz/system.h b/include/mupdf/fitz/system.h index c480bd7..6ca13ac 100644 --- a/include/mupdf/fitz/system.h +++ b/include/mupdf/fitz/system.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_SYSTEM_H #define MUPDF_FITZ_SYSTEM_H @@ -8,13 +30,16 @@ #endif #endif -/* +/** Include the standard libc headers. */ #include /* needed for size_t */ #include /* needed for va_list vararg functions */ #include /* needed for the try/catch macros */ +#include /* useful for debug printfs */ + +#include "export.h" #if defined(_MSC_VER) && (_MSC_VER < 1700) /* MSVC older than VS2012 */ typedef signed char int8_t; @@ -43,7 +68,7 @@ typedef unsigned __int64 uint64_t; #define FZ_SQRT2 1.41421356f #define FZ_LN2 0.69314718f -/* +/** Spot architectures where we have optimisations. */ @@ -53,32 +78,43 @@ typedef unsigned __int64 uint64_t; #endif #endif -/* +/** Some differences in libc can be smoothed over */ -#ifdef __APPLE__ -#define HAVE_SIGSETJMP -#elif defined(__unix) && !defined(__NACL__) -#define HAVE_SIGSETJMP +#ifndef __STRICT_ANSI__ +#if defined(__APPLE__) +#ifndef HAVE_SIGSETJMP +#define HAVE_SIGSETJMP 1 +#endif +#elif defined(__unix) +#ifndef __EMSCRIPTEN__ +#ifndef HAVE_SIGSETJMP +#define HAVE_SIGSETJMP 1 +#endif +#endif +#endif +#endif +#ifndef HAVE_SIGSETJMP +#define HAVE_SIGSETJMP 0 #endif -/* - Where possible (i.e. on platforms on which they are provided), use - sigsetjmp/siglongjmp in preference to setjmp/longjmp. We don't alter - signal handlers within mupdf, so there is no need for us to - store/restore them - hence we use the non-restoring variants. This - makes a large speed difference on MacOSX (and probably other - platforms too. +/** + Where possible (i.e. on platforms on which they are provided), + use sigsetjmp/siglongjmp in preference to setjmp/longjmp. We + don't alter signal handlers within mupdf, so there is no need + for us to store/restore them - hence we use the non-restoring + variants. This makes a large speed difference on MacOSX (and + probably other platforms too. */ -#ifdef HAVE_SIGSETJMP +#if HAVE_SIGSETJMP #define fz_setjmp(BUF) sigsetjmp(BUF, 0) #define fz_longjmp(BUF,VAL) siglongjmp(BUF, VAL) -#define fz_jmp_buf sigjmp_buf +typedef sigjmp_buf fz_jmp_buf; #else #define fz_setjmp(BUF) setjmp(BUF) #define fz_longjmp(BUF,VAL) longjmp(BUF,VAL) -#define fz_jmp_buf jmp_buf +typedef jmp_buf fz_jmp_buf; #endif /* these constants mirror the corresponding macros in stdio.h */ @@ -120,16 +156,15 @@ static __inline int signbit(double x) #define isinf(x) (!_finite(x)) #endif +#if _MSC_VER <= 1920 /* MSVC 2019 */ #define hypotf _hypotf +#endif #define atoll _atoi64 #endif #ifdef _WIN32 -char *fz_utf8_from_wchar(const wchar_t *s); -wchar_t *fz_wchar_from_utf8(const char *s); - /* really a FILE* but we don't want to include stdio.h here */ void *fz_fopen_utf8(const char *name, const char *mode); int fz_remove_utf8(const char *name); @@ -144,27 +179,41 @@ void fz_free_argv(int argc, char **argv); #define S_ISDIR(mode) ((mode) & S_IFDIR) #endif -/* inline is standard in C++. For some compilers we can enable it within C too. */ +int64_t fz_stat_ctime(const char *path); +int64_t fz_stat_mtime(const char *path); +int fz_mkdir(char *path); + + +/* inline is standard in C++. For some compilers we can enable it within + * C too. Some compilers think they know better than we do about when + * to actually honour inline (particularly for large functions); use + * fz_forceinline to kick them into really inlining. */ #ifndef __cplusplus -#if __STDC_VERSION__ == 199901L /* C99 */ -#elif _MSC_VER >= 1500 /* MSVC 9 or newer */ +#if defined (__STDC_VERSION_) && (__STDC_VERSION__ >= 199901L) /* C99 */ +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) /* MSVC 9 or newer */ #define inline __inline -#elif __GNUC__ >= 3 /* GCC 3 or newer */ +#define fz_forceinline __forceinline +#elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC 3 or newer */ #define inline __inline #else /* Unknown or ancient */ #define inline #endif #endif +#ifndef fz_forceinline +#define fz_forceinline inline +#endif + /* restrict is standard in C99, but not in all C++ compilers. */ -#if __STDC_VERSION__ == 199901L /* C99 */ -#elif _MSC_VER >= 1600 /* MSVC 10 or newer */ -#define restrict __restrict -#elif __GNUC__ >= 3 /* GCC 3 or newer */ -#define restrict __restrict +#if defined (__STDC_VERSION_) && (__STDC_VERSION__ >= 199901L) /* C99 */ +#define FZ_RESTRICT restrict +#elif defined(_MSC_VER) && (_MSC_VER >= 1600) /* MSVC 10 or newer */ +#define FZ_RESTRICT __restrict +#elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC 3 or newer */ +#define FZ_RESTRICT __restrict #else /* Unknown or ancient */ -#define restrict +#define FZ_RESTRICT #endif /* noreturn is a GCC extension */ @@ -178,8 +227,9 @@ void fz_free_argv(int argc, char **argv); #endif #endif -/* Flag unused parameters, for use with 'static inline' functions in headers. */ -#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 +/* Flag unused parameters, for use with 'static inline' functions in + * headers. */ +#if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7) #define FZ_UNUSED __attribute__((__unused__)) #else #define FZ_UNUSED @@ -189,7 +239,7 @@ void fz_free_argv(int argc, char **argv); #ifdef __printflike #define FZ_PRINTFLIKE(F,V) __printflike(F,V) #else -#if __GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7 +#if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7) #define FZ_PRINTFLIKE(F,V) __attribute__((__format__ (__printf__, F, V))) #else #define FZ_PRINTFLIKE(F,V) @@ -202,8 +252,8 @@ void fz_free_argv(int argc, char **argv); /* If we're compiling as thumb code, then we need to tell the compiler * to enter and exit ARM mode around our assembly sections. If we move - * the ARM functions to a separate file and arrange for it to be compiled - * without thumb mode, we can save some time on entry. + * the ARM functions to a separate file and arrange for it to be + * compiled without thumb mode, we can save some time on entry. */ /* This is slightly suboptimal; __thumb__ and __thumb2__ become defined * and undefined by #pragma arm/#pragma thumb - but we can't define a @@ -218,10 +268,47 @@ void fz_free_argv(int argc, char **argv); #endif +/* Memory block alignment */ + +/* Most architectures are happy with blocks being aligned to the size + * of void *'s. Some (notably sparc) are not. + * + * Some architectures (notably amd64) are happy for pointers to be 32bit + * aligned even on 64bit systems. By making use of this we can save lots + * of memory in data structures (notably the display list). + * + * We attempt to cope with these vagaries via the following definitions. + */ + +/* All blocks allocated by mupdf's allocators are expected to be + * returned aligned to FZ_MEMORY_BLOCK_ALIGN_MOD. This is sizeof(void *) + * unless overwritten by a predefinition, or by a specific architecture + * being detected. */ +#ifndef FZ_MEMORY_BLOCK_ALIGN_MOD +#if defined(sparc) || defined(__sparc) || defined(__sparc__) +#define FZ_MEMORY_BLOCK_ALIGN_MOD 8 +#else +#define FZ_MEMORY_BLOCK_ALIGN_MOD sizeof(void *) +#endif +#endif + +/* MuPDF will ensure that its use of pointers in packed structures + * (such as the display list) will be aligned to FZ_POINTER_ALIGN_MOD. + * This is the same as FZ_MEMORY_BLOCK_ALIGN_MOD unless overridden by + * a predefinition, or by a specific architecture being detected. */ +#ifndef FZ_POINTER_ALIGN_MOD +#if defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) +#define FZ_POINTER_ALIGN_MOD 4 +#else +#define FZ_POINTER_ALIGN_MOD FZ_MEMORY_BLOCK_ALIGN_MOD +#endif +#endif + #ifdef CLUSTER -/* Include this first so our defines don't clash with the system definitions */ +/* Include this first so our defines don't clash with the system + * definitions */ #include -/* +/** * Trig functions */ static float @@ -321,6 +408,10 @@ static inline float my_sinf(float x) x -= xn; xn *= x2 / 72.0f; x += xn; + if (x > 1) + x = 1; + else if (x < -1) + x = -1; return x; } @@ -360,4 +451,9 @@ static inline float my_atan2f(float o, float a) #define atan2f(x,y) my_atan2f((x),(y)) #endif +static inline int fz_is_pow2(int a) +{ + return (a != 0) && (a & (a-1)) == 0; +} + #endif diff --git a/include/mupdf/fitz/text.h b/include/mupdf/fitz/text.h index d7d7ffb..d7562f9 100644 --- a/include/mupdf/fitz/text.h +++ b/include/mupdf/fitz/text.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_TEXT_H #define MUPDF_FITZ_TEXT_H @@ -7,7 +29,7 @@ #include "mupdf/fitz/path.h" #include "mupdf/fitz/bidi.h" -/* +/** Text buffer. The trm field contains the a, b, c and d coefficients. @@ -19,21 +41,18 @@ with indexes into the glyph array. */ -typedef struct fz_text_s fz_text; -typedef struct fz_text_span_s fz_text_span; -typedef struct fz_text_item_s fz_text_item; - -struct fz_text_item_s +typedef struct { float x, y; int gid; /* -1 for one gid to many ucs mappings */ int ucs; /* -1 for one ucs to many gid mappings */ -}; + int cid; /* CID for CJK fonts, raw character code for other fonts; or unicode for non-PDF formats. */ +} fz_text_item; #define FZ_LANG_TAG2(c1,c2) ((c1-'a'+1) + ((c2-'a'+1)*27)) #define FZ_LANG_TAG3(c1,c2,c3) ((c1-'a'+1) + ((c2-'a'+1)*27) + ((c3-'a'+1)*27*27)) -typedef enum fz_text_language_e +typedef enum { FZ_LANG_UNSET = 0, FZ_LANG_ur = FZ_LANG_TAG2('u','r'), @@ -45,7 +64,7 @@ typedef enum fz_text_language_e FZ_LANG_zh_Hant = FZ_LANG_TAG3('z','h','t'), } fz_text_language; -struct fz_text_span_s +typedef struct fz_text_span { fz_font *font; fz_matrix trm; @@ -55,41 +74,40 @@ struct fz_text_span_s unsigned language : 15; /* The language as marked in the original document */ int len, cap; fz_text_item *items; - fz_text_span *next; -}; + struct fz_text_span *next; +} fz_text_span; -struct fz_text_s +typedef struct { int refs; fz_text_span *head, *tail; -}; +} fz_text; -/* - fz_new_text: Create a new empty fz_text object. +/** + Create a new empty fz_text object. Throws exception on failure to allocate. */ fz_text *fz_new_text(fz_context *ctx); -/* - fz_keep_text: Add a reference to a fz_text. +/** + Increment the reference count for the text object. The same + pointer is returned. - text: text object to keep a reference to. - - Return the same text pointer. + Never throws exceptions. */ fz_text *fz_keep_text(fz_context *ctx, const fz_text *text); -/* - fz_drop_text: Drop a reference to the object, freeing - if it is the last one. +/** + Decrement the reference count for the text object. When the + reference count hits zero, the text object is freed. - text: Object to drop the reference to. + Never throws exceptions. */ void fz_drop_text(fz_context *ctx, const fz_text *text); -/* - fz_show_glyph: Add a glyph/unicode value to a text object. +/** + Add a glyph/unicode value to a text object. text: Text object to add to. @@ -101,6 +119,8 @@ void fz_drop_text(fz_context *ctx, const fz_text *text); unicode: The unicode character for the glyph. + cid: The CJK CID value or raw character code. + wmode: 1 for vertical mode, 0 for horizontal. bidi_level: The bidirectional level for this glyph. @@ -113,17 +133,17 @@ void fz_drop_text(fz_context *ctx, const fz_text *text); Throws exception on failure to allocate. */ -void fz_show_glyph(fz_context *ctx, fz_text *text, fz_font *font, const fz_matrix *trm, int glyph, int unicode, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language); +void fz_show_glyph(fz_context *ctx, fz_text *text, fz_font *font, fz_matrix trm, int glyph, int unicode, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language); +void fz_show_glyph_aux(fz_context *ctx, fz_text *text, fz_font *font, fz_matrix trm, int glyph, int unicode, int cid, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language lang); -/* - fz_show_string: Add a UTF8 string to a text object. +/** + Add a UTF8 string to a text object. text: Text object to add to. font: The font the string should be added in. - trm: The transform to use. Will be updated according - to the advance of the string on exit. + trm: The transform to use. s: The utf-8 string to add. @@ -131,18 +151,27 @@ void fz_show_glyph(fz_context *ctx, fz_text *text, fz_font *font, const fz_matri bidi_level: The bidirectional level for this glyph. - markup_dir: The direction of the text as specified in the - markup. + markup_dir: The direction of the text as specified in the markup. language: The language in use (if known, 0 otherwise) - (e.g. FZ_LANG_zh_Hans). + (e.g. FZ_LANG_zh_Hans). - Throws exception on failure to allocate. + Returns the transform updated with the advance width of the + string. */ -void fz_show_string(fz_context *ctx, fz_text *text, fz_font *font, fz_matrix *trm, const char *s, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language); +fz_matrix fz_show_string(fz_context *ctx, fz_text *text, fz_font *font, fz_matrix trm, const char *s, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language); -/* - fz_bound_text: Find the bounds of a given text object. +/** + Measure the advance width of a UTF8 string should it be added to a text object. + + This uses the same layout algorithms as fz_show_string, and can be used + to calculate text alignment adjustments. +*/ +fz_matrix +fz_measure_string(fz_context *ctx, fz_font *user_font, fz_matrix trm, const char *s, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language); + +/** + Find the bounds of a given text object. text: The text object to find the bounds of. @@ -156,18 +185,9 @@ void fz_show_string(fz_context *ctx, fz_text *text, fz_font *font, fz_matrix *tr Returns a pointer to r, which is updated to contain the bounding box for the text object. */ -fz_rect *fz_bound_text(fz_context *ctx, const fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *r); +fz_rect fz_bound_text(fz_context *ctx, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm); -/* - fz_clone_text: Clone a text object. - - text: The text object to clone. - - Throws an exception on allocation failure. -*/ -fz_text *fz_clone_text(fz_context *ctx, const fz_text *text); - -/* +/** Convert ISO 639 (639-{1,2,3,5}) language specification strings losslessly to a 15 bit fz_text_language code. @@ -178,7 +198,7 @@ fz_text *fz_clone_text(fz_context *ctx, const fz_text *text); */ fz_text_language fz_text_language_from_string(const char *str); -/* +/** Recover ISO 639 (639-{1,2,3,5}) language specification strings losslessly from a 15 bit fz_text_language code. diff --git a/include/mupdf/fitz/track-usage.h b/include/mupdf/fitz/track-usage.h index 6c4409f..69e8425 100644 --- a/include/mupdf/fitz/track-usage.h +++ b/include/mupdf/fitz/track-usage.h @@ -1,29 +1,51 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef TRACK_USAGE_H #define TRACK_USAGE_H #ifdef TRACK_USAGE -typedef struct track_usage_data_s { +typedef struct track_usage_data { int count; const char *function; int line; const char *desc; - struct track_usage_data_s *next; -} track_usage_data_t; + struct track_usage_data *next; +} track_usage_data; #define TRACK_LABEL(A) \ do { \ - static track_usage_data_t USAGE_DATA = { 0 };\ + static track_usage_data USAGE_DATA = { 0 };\ track_usage(&USAGE_DATA, __FILE__, __LINE__, A);\ } while (0) #define TRACK_FN() \ do { \ - static track_usage_data_t USAGE_DATA = { 0 };\ + static track_usage_data USAGE_DATA = { 0 };\ track_usage(&USAGE_DATA, __FILE__, __LINE__, __FUNCTION__);\ } while (0) -void track_usage(track_usage_data_t *data, const char *function, int line, const char *desc); +void track_usage(track_usage_data *data, const char *function, int line, const char *desc); #else diff --git a/include/mupdf/fitz/transition.h b/include/mupdf/fitz/transition.h index 65d170d..89a8087 100644 --- a/include/mupdf/fitz/transition.h +++ b/include/mupdf/fitz/transition.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_TRANSITION_H #define MUPDF_FITZ_TRANSITION_H @@ -5,8 +27,6 @@ #include "mupdf/fitz/pixmap.h" /* Transition support */ -typedef struct fz_transition_s fz_transition; - enum { FZ_TRANSITION_NONE = 0, /* aka 'R' or 'REPLACE' */ FZ_TRANSITION_SPLIT, @@ -22,7 +42,7 @@ enum { FZ_TRANSITION_FADE }; -struct fz_transition_s +typedef struct { int type; float duration; /* Effect duration (seconds) */ @@ -36,10 +56,10 @@ struct fz_transition_s /* State variables for use of the transition code */ int state0; int state1; -}; +} fz_transition; -/* - fz_generate_transition: Generate a frame of a transition. +/** + Generate a frame of a transition. tpix: Target pixmap opix: Old pixmap @@ -48,6 +68,8 @@ struct fz_transition_s trans: Transition details Returns 1 if successfully generated a frame. + + Note: Pixmaps must include alpha. */ int fz_generate_transition(fz_context *ctx, fz_pixmap *tpix, fz_pixmap *opix, fz_pixmap *npix, int time, fz_transition *trans); diff --git a/include/mupdf/fitz/tree.h b/include/mupdf/fitz/tree.h index 92f45d3..b4d7ac6 100644 --- a/include/mupdf/fitz/tree.h +++ b/include/mupdf/fitz/tree.h @@ -1,24 +1,62 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_TREE_H #define MUPDF_FITZ_TREE_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" -/* +/** AA-tree to look up things by strings. */ -typedef struct fz_tree_s fz_tree; +typedef struct fz_tree fz_tree; +/** + Look for the value of a node in the tree with the given key. + + Simple pointer equivalence is used for key. + + Returns NULL for no match. +*/ void *fz_tree_lookup(fz_context *ctx, fz_tree *node, const char *key); -/* +/** Insert a new key/value pair and rebalance the tree. Return the new root of the tree after inserting and rebalancing. May be called with a NULL root to create a new tree. + + No data is copied into the tree structure; key and value are + merely kept as pointers. */ fz_tree *fz_tree_insert(fz_context *ctx, fz_tree *root, const char *key, void *value); +/** + Drop the tree. + + The storage used by the tree is freed, and each value has + dropfunc called on it. +*/ void fz_drop_tree(fz_context *ctx, fz_tree *node, void (*dropfunc)(fz_context *ctx, void *value)); #endif diff --git a/include/mupdf/fitz/types.h b/include/mupdf/fitz/types.h new file mode 100644 index 0000000..1299d2a --- /dev/null +++ b/include/mupdf/fitz/types.h @@ -0,0 +1,41 @@ +// Copyright (C) 2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_TYPES_H +#define MUPDF_FITZ_TYPES_H + +typedef struct fz_document fz_document; + +/** + Locations within the document are referred to in terms of + chapter and page, rather than just a page number. For some + documents (such as epub documents with large numbers of pages + broken into many chapters) this can make navigation much faster + as only the required chapter needs to be decoded at a time. +*/ +typedef struct +{ + int chapter; + int page; +} fz_location; + +#endif diff --git a/include/mupdf/fitz/util.h b/include/mupdf/fitz/util.h index 49409cb..0048508 100644 --- a/include/mupdf/fitz/util.h +++ b/include/mupdf/fitz/util.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_UTIL_H #define MUPDF_FITZ_UTIL_H @@ -8,70 +30,122 @@ #include "mupdf/fitz/pixmap.h" #include "mupdf/fitz/structured-text.h" #include "mupdf/fitz/buffer.h" +#include "mupdf/fitz/xml.h" +#include "mupdf/fitz/archive.h" +#include "mupdf/fitz/display-list.h" -/* - fz_new_display_list_from_page: Create a display list with the contents of a page. +/** + Create a display list. + + Ownership of the display list is returned to the caller. */ fz_display_list *fz_new_display_list_from_page(fz_context *ctx, fz_page *page); fz_display_list *fz_new_display_list_from_page_number(fz_context *ctx, fz_document *doc, int number); + +/** + Create a display list from page contents (no annotations). + + Ownership of the display list is returned to the caller. +*/ fz_display_list *fz_new_display_list_from_page_contents(fz_context *ctx, fz_page *page); -fz_display_list *fz_new_display_list_from_annot(fz_context *ctx, fz_annot *annot); -/* - fz_new_pixmap_from_page: Render the page to a pixmap using the transform and colorspace. +/** + Render the page to a pixmap using the transform and colorspace. + + Ownership of the pixmap is returned to the caller. */ -fz_pixmap *fz_new_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, const fz_matrix *ctm, fz_colorspace *cs, int alpha); -fz_pixmap *fz_new_pixmap_from_page(fz_context *ctx, fz_page *page, const fz_matrix *ctm, fz_colorspace *cs, int alpha); -fz_pixmap *fz_new_pixmap_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_matrix *ctm, fz_colorspace *cs, int alpha); +fz_pixmap *fz_new_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_colorspace *cs, int alpha); +fz_pixmap *fz_new_pixmap_from_page(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha); +fz_pixmap *fz_new_pixmap_from_page_number(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, int alpha); -/* - fz_new_pixmap_from_page_contents: Render the page contents without annotations. +/** + Render the page contents without annotations. + + Ownership of the pixmap is returned to the caller. */ -fz_pixmap *fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, const fz_matrix *ctm, fz_colorspace *cs, int alpha); +fz_pixmap *fz_new_pixmap_from_page_contents(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, int alpha); -/* - fz_new_pixmap_from_annot: Render an annotation suitable for blending on top of the opaque - pixmap returned by fz_new_pixmap_from_page_contents. +/** + Render the page contents with control over spot colors. + + Ownership of the pixmap is returned to the caller. */ -fz_pixmap *fz_new_pixmap_from_annot(fz_context *ctx, fz_annot *annot, const fz_matrix *ctm, fz_colorspace *cs, int alpha); +fz_pixmap *fz_new_pixmap_from_display_list_with_separations(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha); +fz_pixmap *fz_new_pixmap_from_page_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha); +fz_pixmap *fz_new_pixmap_from_page_number_with_separations(fz_context *ctx, fz_document *doc, int number, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha); +fz_pixmap *fz_new_pixmap_from_page_contents_with_separations(fz_context *ctx, fz_page *page, fz_matrix ctm, fz_colorspace *cs, fz_separations *seps, int alpha); -/* - fz_new_stext_page_from_page: Extract structured text from a page. +fz_pixmap *fz_fill_pixmap_from_display_list(fz_context *ctx, fz_display_list *list, fz_matrix ctm, fz_pixmap *pix); + +/** + Extract text from page. + + Ownership of the fz_stext_page is returned to the caller. */ fz_stext_page *fz_new_stext_page_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options); fz_stext_page *fz_new_stext_page_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options); +fz_stext_page *fz_new_stext_page_from_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int number, const fz_stext_options *options); fz_stext_page *fz_new_stext_page_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options); -/* - fz_new_buffer_from_stext_page: Convert structured text into plain text. +/** + Convert structured text into plain text. */ fz_buffer *fz_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *text); fz_buffer *fz_new_buffer_from_page(fz_context *ctx, fz_page *page, const fz_stext_options *options); fz_buffer *fz_new_buffer_from_page_number(fz_context *ctx, fz_document *doc, int number, const fz_stext_options *options); fz_buffer *fz_new_buffer_from_display_list(fz_context *ctx, fz_display_list *list, const fz_stext_options *options); -/* - fz_search_page: Search for the 'needle' text on the page. - Record the hits in the hit_bbox array and return the number of hits. - Will stop looking once it has filled hit_max rectangles. +/** + Search for the 'needle' text on the page. + Record the hits in the hit_bbox array and return the number of + hits. Will stop looking once it has filled hit_max rectangles. */ -int fz_search_page(fz_context *ctx, fz_page *page, const char *needle, fz_rect *hit_bbox, int hit_max); -int fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, fz_rect *hit_bbox, int hit_max); -int fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, fz_rect *hit_bbox, int hit_max); +int fz_search_page(fz_context *ctx, fz_page *page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max); +int fz_search_page_number(fz_context *ctx, fz_document *doc, int number, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max); +int fz_search_chapter_page_number(fz_context *ctx, fz_document *doc, int chapter, int page, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max); +int fz_search_display_list(fz_context *ctx, fz_display_list *list, const char *needle, int *hit_mark, fz_quad *hit_bbox, int hit_max); -/* +/** Parse an SVG document into a display-list. */ -fz_display_list *fz_new_display_list_from_svg(fz_context *ctx, fz_buffer *buf, float *w, float *h); +fz_display_list *fz_new_display_list_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *dir, float *w, float *h); -/* +/** Create a scalable image from an SVG document. */ -fz_image *fz_new_image_from_svg(fz_context *ctx, fz_buffer *buf); +fz_image *fz_new_image_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *dir); -/* +/** + Parse an SVG document into a display-list. +*/ +fz_display_list *fz_new_display_list_from_svg_xml(fz_context *ctx, fz_xml_doc *xmldoc, fz_xml *xml, const char *base_uri, fz_archive *dir, float *w, float *h); + +/** + Create a scalable image from an SVG document. +*/ +fz_image *fz_new_image_from_svg_xml(fz_context *ctx, fz_xml_doc *xmldoc, fz_xml *xml, const char *base_uri, fz_archive *dir); + +/** Write image as a data URI (for HTML and SVG output). */ void fz_write_image_as_data_uri(fz_context *ctx, fz_output *out, fz_image *image); +void fz_write_pixmap_as_data_uri(fz_context *ctx, fz_output *out, fz_pixmap *pixmap); +void fz_append_image_as_data_uri(fz_context *ctx, fz_buffer *out, fz_image *image); +void fz_append_pixmap_as_data_uri(fz_context *ctx, fz_buffer *out, fz_pixmap *pixmap); + +/** + Use text extraction to convert the input document into XHTML, + then open the result as a new document that can be reflowed. +*/ +fz_document *fz_new_xhtml_document_from_document(fz_context *ctx, fz_document *old_doc, const fz_stext_options *opts); + +/** + Returns an fz_buffer containing a page after conversion to specified format. + + page: The page to convert. + format, options: Passed to fz_new_document_writer_with_output() internally. + transform, cookie: Passed to fz_run_page() internally. +*/ +fz_buffer *fz_new_buffer_from_page_with_format(fz_context *ctx, fz_page *page, const char *format, const char *options, fz_matrix transform, fz_cookie *cookie); #endif diff --git a/include/mupdf/fitz/vendor.go b/include/mupdf/fitz/vendor.go new file mode 100644 index 0000000..4a5fffb --- /dev/null +++ b/include/mupdf/fitz/vendor.go @@ -0,0 +1,3 @@ +//go:build required + +package vendor diff --git a/include/mupdf/fitz/version.h b/include/mupdf/fitz/version.h index 20a8e85..8bf080b 100644 --- a/include/mupdf/fitz/version.h +++ b/include/mupdf/fitz/version.h @@ -1,9 +1,31 @@ +// Copyright (C) 2004-2024 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_VERSION_H #define MUPDF_FITZ_VERSION_H #ifndef FZ_VERSION -#define FZ_VERSION "1.13.0" +#define FZ_VERSION "1.24.9" #define FZ_VERSION_MAJOR 1 -#define FZ_VERSION_MINOR 13 -#define FZ_VERSION_PATCH 0 +#define FZ_VERSION_MINOR 24 +#define FZ_VERSION_PATCH 9 #endif #endif diff --git a/include/mupdf/fitz/write-pixmap.h b/include/mupdf/fitz/write-pixmap.h new file mode 100644 index 0000000..8ddb1ef --- /dev/null +++ b/include/mupdf/fitz/write-pixmap.h @@ -0,0 +1,499 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#ifndef MUPDF_FITZ_WRITE_PIXMAP_H +#define MUPDF_FITZ_WRITE_PIXMAP_H + +#include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/output.h" +#include "mupdf/fitz/band-writer.h" +#include "mupdf/fitz/pixmap.h" +#include "mupdf/fitz/bitmap.h" +#include "mupdf/fitz/buffer.h" +#include "mupdf/fitz/image.h" +#include "mupdf/fitz/writer.h" + +/** + PCL output +*/ +typedef struct +{ + /* Features of a particular printer */ + int features; + const char *odd_page_init; + const char *even_page_init; + + /* Options for this job */ + int tumble; + int duplex_set; + int duplex; + int paper_size; + int manual_feed_set; + int manual_feed; + int media_position_set; + int media_position; + int orientation; + + /* Updated as we move through the job */ + int page_count; +} fz_pcl_options; + +/** + Initialize PCL option struct for a given preset. + + Currently defined presets include: + + generic Generic PCL printer + ljet4 HP DeskJet + dj500 HP DeskJet 500 + fs600 Kyocera FS-600 + lj HP LaserJet, HP LaserJet Plus + lj2 HP LaserJet IIp, HP LaserJet IId + lj3 HP LaserJet III + lj3d HP LaserJet IIId + lj4 HP LaserJet 4 + lj4pl HP LaserJet 4 PL + lj4d HP LaserJet 4d + lp2563b HP 2563B line printer + oce9050 Oce 9050 Line printer +*/ +void fz_pcl_preset(fz_context *ctx, fz_pcl_options *opts, const char *preset); + +/** + Parse PCL options. + + Currently defined options and values are as follows: + + preset=X Either "generic" or one of the presets as for fz_pcl_preset. + spacing=0 No vertical spacing capability + spacing=1 PCL 3 spacing (*p+Y) + spacing=2 PCL 4 spacing (*bY) + spacing=3 PCL 5 spacing (*bY and clear seed row) + mode2 Disable/Enable mode 2 graphics compression + mode3 Disable/Enable mode 3 graphics compression + eog_reset End of graphics (*rB) resets all parameters + has_duplex Duplex supported (&lS) + has_papersize Papersize setting supported (&lA) + has_copies Number of copies supported (&lX) + is_ljet4pjl Disable/Enable HP 4PJL model-specific output + is_oce9050 Disable/Enable Oce 9050 model-specific output +*/ +fz_pcl_options *fz_parse_pcl_options(fz_context *ctx, fz_pcl_options *opts, const char *args); + +/** + Create a new band writer, outputing monochrome pcl. +*/ +fz_band_writer *fz_new_mono_pcl_band_writer(fz_context *ctx, fz_output *out, const fz_pcl_options *options); + +/** + Write a bitmap as mono PCL. +*/ +void fz_write_bitmap_as_pcl(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pcl_options *pcl); + +/** + Save a bitmap as mono PCL. +*/ +void fz_save_bitmap_as_pcl(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pcl_options *pcl); + +/** + Create a new band writer, outputing color pcl. +*/ +fz_band_writer *fz_new_color_pcl_band_writer(fz_context *ctx, fz_output *out, const fz_pcl_options *options); + +/** + Write an (RGB) pixmap as color PCL. +*/ +void fz_write_pixmap_as_pcl(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pcl_options *pcl); + +/** + Save an (RGB) pixmap as color PCL. +*/ +void fz_save_pixmap_as_pcl(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pcl_options *pcl); + +/** + PCLm output +*/ +typedef struct +{ + int compress; + int strip_height; + + /* Updated as we move through the job */ + int page_count; +} fz_pclm_options; + +/** + Parse PCLm options. + + Currently defined options and values are as follows: + + compression=none: No compression + compression=flate: Flate compression + strip-height=n: Strip height (default 16) +*/ +fz_pclm_options *fz_parse_pclm_options(fz_context *ctx, fz_pclm_options *opts, const char *args); + +/** + Create a new band writer, outputing pclm +*/ +fz_band_writer *fz_new_pclm_band_writer(fz_context *ctx, fz_output *out, const fz_pclm_options *options); + +/** + Write a (Greyscale or RGB) pixmap as pclm. +*/ +void fz_write_pixmap_as_pclm(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pclm_options *options); + +/** + Save a (Greyscale or RGB) pixmap as pclm. +*/ +void fz_save_pixmap_as_pclm(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pclm_options *options); + +/** + PDFOCR output +*/ +typedef struct +{ + int compress; + int strip_height; + char language[256]; + char datadir[1024]; + + /* Updated as we move through the job */ + int page_count; +} fz_pdfocr_options; + +/** + Parse PDFOCR options. + + Currently defined options and values are as follows: + + compression=none: No compression + compression=flate: Flate compression + strip-height=n: Strip height (default 16) + ocr-language=: OCR Language (default eng) + ocr-datadir=: OCR data path (default rely on TESSDATA_PREFIX) +*/ +fz_pdfocr_options *fz_parse_pdfocr_options(fz_context *ctx, fz_pdfocr_options *opts, const char *args); + +/** + Create a new band writer, outputing pdfocr. + + Ownership of output stays with the caller, the band writer + borrows the reference. The caller must keep the output around + for the duration of the band writer, and then close/drop as + appropriate. +*/ +fz_band_writer *fz_new_pdfocr_band_writer(fz_context *ctx, fz_output *out, const fz_pdfocr_options *options); + +/** + Set the progress callback for a pdfocr bandwriter. +*/ +void fz_pdfocr_band_writer_set_progress(fz_context *ctx, fz_band_writer *writer, fz_pdfocr_progress_fn *progress_fn, void *progress_arg); + +/** + Write a (Greyscale or RGB) pixmap as pdfocr. +*/ +void fz_write_pixmap_as_pdfocr(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pdfocr_options *options); + +/** + Save a (Greyscale or RGB) pixmap as pdfocr. +*/ +void fz_save_pixmap_as_pdfocr(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pdfocr_options *options); + +/** + Save a (Greyscale or RGB) pixmap as a png. +*/ +void fz_save_pixmap_as_png(fz_context *ctx, fz_pixmap *pixmap, const char *filename); + +/** + Write a pixmap as a JPEG. +*/ +void fz_write_pixmap_as_jpeg(fz_context *ctx, fz_output *out, fz_pixmap *pix, int quality, int invert_cmyk); + +/** + Save a pixmap as a JPEG. +*/ +void fz_save_pixmap_as_jpeg(fz_context *ctx, fz_pixmap *pixmap, const char *filename, int quality); + +/** + Write a (Greyscale or RGB) pixmap as a png. +*/ +void fz_write_pixmap_as_png(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap); + +/** + Pixmap data as JP2K with no subsampling. + + quality = 100 = lossless + otherwise for a factor of x compression use 100-x. (so 80 is 1:20 compression) +*/ +void fz_write_pixmap_as_jpx(fz_context *ctx, fz_output *out, fz_pixmap *pix, int quality); + +/** + Save pixmap data as JP2K with no subsampling. + + quality = 100 = lossless + otherwise for a factor of x compression use 100-x. (so 80 is 1:20 compression) +*/ +void fz_save_pixmap_as_jpx(fz_context *ctx, fz_pixmap *pixmap, const char *filename, int q); + +/** + Create a new png band writer (greyscale or RGB, with or without + alpha). +*/ +fz_band_writer *fz_new_png_band_writer(fz_context *ctx, fz_output *out); + +/** + Reencode a given image as a PNG into a buffer. + + Ownership of the buffer is returned. +*/ +fz_buffer *fz_new_buffer_from_image_as_png(fz_context *ctx, fz_image *image, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_image_as_pnm(fz_context *ctx, fz_image *image, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_image_as_pam(fz_context *ctx, fz_image *image, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_image_as_psd(fz_context *ctx, fz_image *image, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_image_as_jpeg(fz_context *ctx, fz_image *image, fz_color_params color_params, int quality, int invert_cmyk); +fz_buffer *fz_new_buffer_from_image_as_jpx(fz_context *ctx, fz_image *image, fz_color_params color_params, int quality); + +/** + Reencode a given pixmap as a PNG into a buffer. + + Ownership of the buffer is returned. +*/ +fz_buffer *fz_new_buffer_from_pixmap_as_png(fz_context *ctx, fz_pixmap *pixmap, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_pixmap_as_pnm(fz_context *ctx, fz_pixmap *pixmap, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_pixmap_as_pam(fz_context *ctx, fz_pixmap *pixmap, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_pixmap_as_psd(fz_context *ctx, fz_pixmap *pix, fz_color_params color_params); +fz_buffer *fz_new_buffer_from_pixmap_as_jpeg(fz_context *ctx, fz_pixmap *pixmap, fz_color_params color_params, int quality, int invert_cmyk); +fz_buffer *fz_new_buffer_from_pixmap_as_jpx(fz_context *ctx, fz_pixmap *pix, fz_color_params color_params, int quality); + +/** + Save a pixmap as a pnm (greyscale or rgb, no alpha). +*/ +void fz_save_pixmap_as_pnm(fz_context *ctx, fz_pixmap *pixmap, const char *filename); + +/** + Write a pixmap as a pnm (greyscale or rgb, no alpha). +*/ +void fz_write_pixmap_as_pnm(fz_context *ctx, fz_output *out, fz_pixmap *pixmap); + +/** + Create a band writer targetting pnm (greyscale or rgb, no + alpha). +*/ +fz_band_writer *fz_new_pnm_band_writer(fz_context *ctx, fz_output *out); + +/** + Save a pixmap as a pnm (greyscale, rgb or cmyk, with or without + alpha). +*/ +void fz_save_pixmap_as_pam(fz_context *ctx, fz_pixmap *pixmap, const char *filename); + +/** + Write a pixmap as a pnm (greyscale, rgb or cmyk, with or without + alpha). +*/ +void fz_write_pixmap_as_pam(fz_context *ctx, fz_output *out, fz_pixmap *pixmap); + +/** + Create a band writer targetting pnm (greyscale, rgb or cmyk, + with or without alpha). +*/ +fz_band_writer *fz_new_pam_band_writer(fz_context *ctx, fz_output *out); + +/** + Save a bitmap as a pbm. +*/ +void fz_save_bitmap_as_pbm(fz_context *ctx, fz_bitmap *bitmap, const char *filename); + +/** + Write a bitmap as a pbm. +*/ +void fz_write_bitmap_as_pbm(fz_context *ctx, fz_output *out, fz_bitmap *bitmap); + +/** + Create a new band writer, targetting pbm. +*/ +fz_band_writer *fz_new_pbm_band_writer(fz_context *ctx, fz_output *out); + +/** + Save a pixmap as a pbm. (Performing halftoning). +*/ +void fz_save_pixmap_as_pbm(fz_context *ctx, fz_pixmap *pixmap, const char *filename); + +/** + Save a CMYK bitmap as a pkm. +*/ +void fz_save_bitmap_as_pkm(fz_context *ctx, fz_bitmap *bitmap, const char *filename); + +/** + Write a CMYK bitmap as a pkm. +*/ +void fz_write_bitmap_as_pkm(fz_context *ctx, fz_output *out, fz_bitmap *bitmap); + +/** + Create a new pkm band writer for CMYK pixmaps. +*/ +fz_band_writer *fz_new_pkm_band_writer(fz_context *ctx, fz_output *out); + +/** + Save a CMYK pixmap as a pkm. (Performing halftoning). +*/ +void fz_save_pixmap_as_pkm(fz_context *ctx, fz_pixmap *pixmap, const char *filename); + +/** + Write a (gray, rgb, or cmyk, no alpha) pixmap out as postscript. +*/ +void fz_write_pixmap_as_ps(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap); + +/** + Save a (gray, rgb, or cmyk, no alpha) pixmap out as postscript. +*/ +void fz_save_pixmap_as_ps(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append); + +/** + Create a postscript band writer for gray, rgb, or cmyk, no + alpha. +*/ +fz_band_writer *fz_new_ps_band_writer(fz_context *ctx, fz_output *out); + +/** + Write the file level header for ps band writer output. +*/ +void fz_write_ps_file_header(fz_context *ctx, fz_output *out); + +/** + Write the file level trailer for ps band writer output. +*/ +void fz_write_ps_file_trailer(fz_context *ctx, fz_output *out, int pages); + +/** + Save a pixmap as a PSD file. +*/ +void fz_save_pixmap_as_psd(fz_context *ctx, fz_pixmap *pixmap, const char *filename); + +/** + Write a pixmap as a PSD file. +*/ +void fz_write_pixmap_as_psd(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap); + +/** + Open a PSD band writer. +*/ +fz_band_writer *fz_new_psd_band_writer(fz_context *ctx, fz_output *out); + +typedef struct +{ + /* These are not interpreted as CStrings by the writing code, + * but are rather copied directly out. */ + char media_class[64]; + char media_color[64]; + char media_type[64]; + char output_type[64]; + + unsigned int advance_distance; + int advance_media; + int collate; + int cut_media; + int duplex; + int insert_sheet; + int jog; + int leading_edge; + int manual_feed; + unsigned int media_position; + unsigned int media_weight; + int mirror_print; + int negative_print; + unsigned int num_copies; + int orientation; + int output_face_up; + unsigned int PageSize[2]; + int separations; + int tray_switch; + int tumble; + + int media_type_num; + int compression; + unsigned int row_count; + unsigned int row_feed; + unsigned int row_step; + + /* These are not interpreted as CStrings by the writing code, but + * are rather copied directly out. */ + char rendering_intent[64]; + char page_size_name[64]; +} fz_pwg_options; + +/** + Save a pixmap as a PWG. +*/ +void fz_save_pixmap_as_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pwg_options *pwg); + +/** + Save a bitmap as a PWG. +*/ +void fz_save_bitmap_as_pwg(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pwg_options *pwg); + +/** + Write a pixmap as a PWG. +*/ +void fz_write_pixmap_as_pwg(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg); + +/** + Write a bitmap as a PWG. +*/ +void fz_write_bitmap_as_pwg(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg); + +/** + Write a pixmap as a PWG page. + + Caller should provide a file header by calling + fz_write_pwg_file_header, but can then write several pages to + the same file. +*/ +void fz_write_pixmap_as_pwg_page(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg); + +/** + Write a bitmap as a PWG page. + + Caller should provide a file header by calling + fz_write_pwg_file_header, but can then write several pages to + the same file. +*/ +void fz_write_bitmap_as_pwg_page(fz_context *ctx, fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg); + +/** + Create a new monochrome pwg band writer. +*/ +fz_band_writer *fz_new_mono_pwg_band_writer(fz_context *ctx, fz_output *out, const fz_pwg_options *pwg); + +/** + Create a new color pwg band writer. +*/ +fz_band_writer *fz_new_pwg_band_writer(fz_context *ctx, fz_output *out, const fz_pwg_options *pwg); + +/** + Output the file header to a pwg stream, ready for pages to follow it. +*/ +void fz_write_pwg_file_header(fz_context *ctx, fz_output *out); /* for use by mudraw.c */ + +#endif diff --git a/include/mupdf/fitz/writer.h b/include/mupdf/fitz/writer.h index 1ce5164..23b78fa 100644 --- a/include/mupdf/fitz/writer.h +++ b/include/mupdf/fitz/writer.h @@ -1,3 +1,25 @@ +// Copyright (C) 2004-2023 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_WRITER_H #define MUPDF_FITZ_WRITER_H @@ -7,28 +29,28 @@ #include "mupdf/fitz/document.h" #include "mupdf/fitz/device.h" -typedef struct fz_document_writer_s fz_document_writer; +typedef struct fz_document_writer fz_document_writer; -/* - fz_document_writer_begin_page_fn: Function type to start +/** + Function type to start the process of writing a page to a document. mediabox: page size rectangle in points. Returns a fz_device to write page contents to. */ -typedef fz_device *(fz_document_writer_begin_page_fn)(fz_context *ctx, fz_document_writer *wri, const fz_rect *mediabox); +typedef fz_device *(fz_document_writer_begin_page_fn)(fz_context *ctx, fz_document_writer *wri, fz_rect mediabox); -/* - fz_document_writer_end_page_fn: Function type to end the +/** + Function type to end the process of writing a page to a document. dev: The device created by the begin_page function. */ typedef void (fz_document_writer_end_page_fn)(fz_context *ctx, fz_document_writer *wri, fz_device *dev); -/* - fz_document_writer_close_writer_fn: Function type to end +/** + Function type to end the process of writing pages to a document. This writes any file level trailers required. After this @@ -36,8 +58,8 @@ typedef void (fz_document_writer_end_page_fn)(fz_context *ctx, fz_document_write */ typedef void (fz_document_writer_close_writer_fn)(fz_context *ctx, fz_document_writer *wri); -/* - fz_document_writer_drop_writer_fn: Function type to discard +/** + Function type to discard an fz_document_writer. This may be called at any time during the process to release all the resources owned by the writer. @@ -47,63 +69,111 @@ typedef void (fz_document_writer_close_writer_fn)(fz_context *ctx, fz_document_w */ typedef void (fz_document_writer_drop_writer_fn)(fz_context *ctx, fz_document_writer *wri); -/* - Structure is public to allow other structures to - be derived from it. Do not access members directly. -*/ -struct fz_document_writer_s -{ - fz_document_writer_begin_page_fn *begin_page; - fz_document_writer_end_page_fn *end_page; - fz_document_writer_close_writer_fn *close_writer; - fz_document_writer_drop_writer_fn *drop_writer; - fz_device *dev; -}; - -/* - fz_new_document_writer_of_size: Internal function to allocate a - block for a derived document_writer structure, with the base - structure's function pointers populated correctly, and the extra - space zero initialised. -*/ -fz_document_writer *fz_new_document_writer_of_size(fz_context *ctx, size_t size, - fz_document_writer_begin_page_fn *begin_page, - fz_document_writer_end_page_fn *end_page, - fz_document_writer_close_writer_fn *close, - fz_document_writer_drop_writer_fn *drop); - #define fz_new_derived_document_writer(CTX,TYPE,BEGIN_PAGE,END_PAGE,CLOSE,DROP) \ ((TYPE *)Memento_label(fz_new_document_writer_of_size(CTX,sizeof(TYPE),BEGIN_PAGE,END_PAGE,CLOSE,DROP),#TYPE)) +/** + Look for a given option (key) in the opts string. Return 1 if + it has it, and update *val to point to the value within opts. +*/ int fz_has_option(fz_context *ctx, const char *opts, const char *key, const char **val); + +/** + Check to see if an option, a, from a string matches a reference + option, b. + + (i.e. a could be 'foo' or 'foo,bar...' etc, but b can only be + 'foo'.) +*/ int fz_option_eq(const char *a, const char *b); -/* - fz_new_document_writer: Create a new fz_document_writer, for a +/** + Copy an option (val) into a destination buffer (dest), of maxlen + bytes. + + Returns the number of bytes (including terminator) that did not + fit. If val is maxlen or greater bytes in size, it will be left + unterminated. +*/ +size_t fz_copy_option(fz_context *ctx, const char *val, char *dest, size_t maxlen); + +/** + Create a new fz_document_writer, for a file of the given type. path: The document name to write (or NULL for default) - format: Which format to write (currently cbz, html, pdf, pam, pbm, - pgm, pkm, png, ppm, pnm, svg, text, tga, xhtml) + format: Which format to write (currently cbz, html, pdf, pam, + pbm, pgm, pkm, png, ppm, pnm, svg, text, xhtml, docx, odt) options: NULL, or pointer to comma separated string to control file generation. */ fz_document_writer *fz_new_document_writer(fz_context *ctx, const char *path, const char *format, const char *options); +/** + Like fz_new_document_writer but takes a fz_output for writing + the result. Only works for multi-page formats. +*/ +fz_document_writer * +fz_new_document_writer_with_output(fz_context *ctx, fz_output *out, const char *format, const char *options); + +fz_document_writer * +fz_new_document_writer_with_buffer(fz_context *ctx, fz_buffer *buf, const char *format, const char *options); + +/** + Document writers for various possible output formats. + + All of the "_with_output" variants pass the ownership of out in + immediately upon calling. The writers are responsible for + dropping the fz_output when they are finished with it (even + if they throw an exception during creation). +*/ fz_document_writer *fz_new_pdf_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_pdf_writer_with_output(fz_context *ctx, fz_output *out, const char *options); fz_document_writer *fz_new_svg_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_svg_writer_with_output(fz_context *ctx, fz_output *out, const char *options); fz_document_writer *fz_new_text_writer(fz_context *ctx, const char *format, const char *path, const char *options); +fz_document_writer *fz_new_text_writer_with_output(fz_context *ctx, const char *format, fz_output *out, const char *options); + +fz_document_writer *fz_new_odt_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_odt_writer_with_output(fz_context *ctx, fz_output *out, const char *options); +fz_document_writer *fz_new_docx_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_docx_writer_with_output(fz_context *ctx, fz_output *out, const char *options); fz_document_writer *fz_new_ps_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_ps_writer_with_output(fz_context *ctx, fz_output *out, const char *options); fz_document_writer *fz_new_pcl_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_pcl_writer_with_output(fz_context *ctx, fz_output *out, const char *options); +fz_document_writer *fz_new_pclm_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_pclm_writer_with_output(fz_context *ctx, fz_output *out, const char *options); fz_document_writer *fz_new_pwg_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_pwg_writer_with_output(fz_context *ctx, fz_output *out, const char *options); fz_document_writer *fz_new_cbz_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_cbz_writer_with_output(fz_context *ctx, fz_output *out, const char *options); + +/** + Used to report progress of the OCR operation. + + page: Current page being processed. + + percent: Progress of the OCR operation for the + current page in percent. Whether it reaches 100 + once a page is finished, depends on the OCR engine. + + Return 0 to continue progress, return 1 to cancel the + operation. +*/ +typedef int (fz_pdfocr_progress_fn)(fz_context *ctx, void *progress_arg, int page, int percent); + +fz_document_writer *fz_new_pdfocr_writer(fz_context *ctx, const char *path, const char *options); +fz_document_writer *fz_new_pdfocr_writer_with_output(fz_context *ctx, fz_output *out, const char *options); +void fz_pdfocr_writer_set_progress(fz_context *ctx, fz_document_writer *writer, fz_pdfocr_progress_fn *progress, void *); + +fz_document_writer *fz_new_jpeg_pixmap_writer(fz_context *ctx, const char *path, const char *options); fz_document_writer *fz_new_png_pixmap_writer(fz_context *ctx, const char *path, const char *options); -fz_document_writer *fz_new_tga_pixmap_writer(fz_context *ctx, const char *path, const char *options); fz_document_writer *fz_new_pam_pixmap_writer(fz_context *ctx, const char *path, const char *options); fz_document_writer *fz_new_pnm_pixmap_writer(fz_context *ctx, const char *path, const char *options); fz_document_writer *fz_new_pgm_pixmap_writer(fz_context *ctx, const char *path, const char *options); @@ -111,24 +181,31 @@ fz_document_writer *fz_new_ppm_pixmap_writer(fz_context *ctx, const char *path, fz_document_writer *fz_new_pbm_pixmap_writer(fz_context *ctx, const char *path, const char *options); fz_document_writer *fz_new_pkm_pixmap_writer(fz_context *ctx, const char *path, const char *options); -/* - fz_begin_page: Called to start the process of writing a page to +/** + Called to start the process of writing a page to a document. mediabox: page size rectangle in points. - Returns a fz_device to write page contents to. + Returns a borrowed fz_device to write page contents to. This + should be kept if required, and only dropped if it was kept. */ -fz_device *fz_begin_page(fz_context *ctx, fz_document_writer *wri, const fz_rect *mediabox); +fz_device *fz_begin_page(fz_context *ctx, fz_document_writer *wri, fz_rect mediabox); -/* - fz_end_page: Called to end the process of writing a page to a +/** + Called to end the process of writing a page to a document. */ void fz_end_page(fz_context *ctx, fz_document_writer *wri); -/* - fz_close_document_writer: Called to end the process of writing +/** + Convenience function to feed all the pages of a document to + fz_begin_page/fz_run_page/fz_end_page. +*/ +void fz_write_document(fz_context *ctx, fz_document_writer *wri, fz_document *doc); + +/** + Called to end the process of writing pages to a document. This writes any file level trailers required. After this @@ -136,8 +213,8 @@ void fz_end_page(fz_context *ctx, fz_document_writer *wri); */ void fz_close_document_writer(fz_context *ctx, fz_document_writer *wri); -/* - fz_drop_document_writer: Called to discard a fz_document_writer. +/** + Called to discard a fz_document_writer. This may be called at any time during the process to release all the resources owned by the writer. @@ -149,11 +226,41 @@ void fz_drop_document_writer(fz_context *ctx, fz_document_writer *wri); fz_document_writer *fz_new_pixmap_writer(fz_context *ctx, const char *path, const char *options, const char *default_path, int n, void (*save)(fz_context *ctx, fz_pixmap *pix, const char *filename)); -extern const char *fz_pdf_write_options_usage; -extern const char *fz_svg_write_options_usage; +FZ_DATA extern const char *fz_pdf_write_options_usage; +FZ_DATA extern const char *fz_svg_write_options_usage; + +FZ_DATA extern const char *fz_pcl_write_options_usage; +FZ_DATA extern const char *fz_pclm_write_options_usage; +FZ_DATA extern const char *fz_pwg_write_options_usage; +FZ_DATA extern const char *fz_pdfocr_write_options_usage; + +/* Implementation details: subject to change. */ + +/** + Structure is public to allow other structures to + be derived from it. Do not access members directly. +*/ +struct fz_document_writer +{ + fz_document_writer_begin_page_fn *begin_page; + fz_document_writer_end_page_fn *end_page; + fz_document_writer_close_writer_fn *close_writer; + fz_document_writer_drop_writer_fn *drop_writer; + fz_device *dev; +}; + +/** + Internal function to allocate a + block for a derived document_writer structure, with the base + structure's function pointers populated correctly, and the extra + space zero initialised. +*/ +fz_document_writer *fz_new_document_writer_of_size(fz_context *ctx, size_t size, + fz_document_writer_begin_page_fn *begin_page, + fz_document_writer_end_page_fn *end_page, + fz_document_writer_close_writer_fn *close, + fz_document_writer_drop_writer_fn *drop); + -extern const char *fz_pcl_write_options_usage; -extern const char *fz_pclm_write_options_usage; -extern const char *fz_pwg_write_options_usage; #endif diff --git a/include/mupdf/fitz/xml.h b/include/mupdf/fitz/xml.h index d3cbd64..7792f4a 100644 --- a/include/mupdf/fitz/xml.h +++ b/include/mupdf/fitz/xml.h @@ -1,88 +1,397 @@ +// Copyright (C) 2004-2022 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + #ifndef MUPDF_FITZ_XML_H #define MUPDF_FITZ_XML_H #include "mupdf/fitz/system.h" #include "mupdf/fitz/context.h" +#include "mupdf/fitz/buffer.h" +#include "mupdf/fitz/pool.h" +#include "mupdf/fitz/archive.h" -/* +/** XML document model */ -typedef struct fz_xml_doc_s fz_xml_doc; -typedef struct fz_xml_s fz_xml; +typedef struct fz_xml fz_xml; -/* - fz_parse_xml: Parse the contents of buffer into a tree of xml nodes. +/* For backwards compatibility */ +typedef fz_xml fz_xml_doc; + +/** + Parse the contents of buffer into a tree of xml nodes. preserve_white: whether to keep or delete all-whitespace nodes. */ -fz_xml_doc *fz_parse_xml(fz_context *ctx, fz_buffer *buf, int preserve_white); +fz_xml *fz_parse_xml(fz_context *ctx, fz_buffer *buf, int preserve_white); -/* - fz_drop_xml: Free the XML node and all its children and siblings. +/** + Parse the contents of buffer into a tree of xml nodes. + + preserve_white: whether to keep or delete all-whitespace nodes. */ -void fz_drop_xml(fz_context *ctx, fz_xml_doc *xml); +fz_xml *fz_parse_xml_stream(fz_context *ctx, fz_stream *stream, int preserve_white); -/* - fz_detach_xml: Detach a node from the tree, unlinking it from its parent, +/** + Parse the contents of an archive entry into a tree of xml nodes. + + preserve_white: whether to keep or delete all-whitespace nodes. +*/ +fz_xml *fz_parse_xml_archive_entry(fz_context *ctx, fz_archive *dir, const char *filename, int preserve_white); + +/** + Try and parse the contents of an archive entry into a tree of xml nodes. + + preserve_white: whether to keep or delete all-whitespace nodes. + + Will return NULL if the archive entry can't be found. Otherwise behaves + the same as fz_parse_xml_archive_entry. May throw exceptions. +*/ +fz_xml *fz_try_parse_xml_archive_entry(fz_context *ctx, fz_archive *dir, const char *filename, int preserve_white); + +/** + Parse the contents of a buffer into a tree of XML nodes, + using the HTML5 parsing algorithm. +*/ +fz_xml *fz_parse_xml_from_html5(fz_context *ctx, fz_buffer *buf); + +/** + Add a reference to the XML. +*/ +fz_xml *fz_keep_xml(fz_context *ctx, fz_xml *xml); + +/** + Drop a reference to the XML. When the last reference is + dropped, the node and all its children and siblings will + be freed. +*/ +void fz_drop_xml(fz_context *ctx, fz_xml *xml); + +/** + Detach a node from the tree, unlinking it from its parent, and setting the document root to the node. */ -void fz_detach_xml(fz_context *ctx, fz_xml_doc *xml, fz_xml *node); +void fz_detach_xml(fz_context *ctx, fz_xml *node); -/* - fz_xml_root: Get the root node for the document. +/** + Return the topmost XML node of a document. */ fz_xml *fz_xml_root(fz_xml_doc *xml); -/* - fz_xml_prev: Return previous sibling of XML node. +/** + Return previous sibling of XML node. */ fz_xml *fz_xml_prev(fz_xml *item); -/* - fz_xml_next: Return next sibling of XML node. +/** + Return next sibling of XML node. */ fz_xml *fz_xml_next(fz_xml *item); -/* - fz_xml_up: Return parent of XML node. +/** + Return parent of XML node. */ fz_xml *fz_xml_up(fz_xml *item); -/* - fz_xml_down: Return first child of XML node. +/** + Return first child of XML node. */ fz_xml *fz_xml_down(fz_xml *item); -/* - fz_xml_is_tag: Return true if the tag name matches. +/** + Return true if the tag name matches. */ int fz_xml_is_tag(fz_xml *item, const char *name); -/* - fz_xml_tag: Return tag of XML node. Return NULL for text nodes. +/** + Return tag of XML node. Return NULL for text nodes. */ char *fz_xml_tag(fz_xml *item); -/* - fz_xml_att: Return the value of an attribute of an XML node. +/** + Return the value of an attribute of an XML node. NULL if the attribute doesn't exist. */ char *fz_xml_att(fz_xml *item, const char *att); -/* - fz_xml_text: Return the text content of an XML node. +/** + Return the value of an attribute of an XML node. + If the first attribute doesn't exist, try the second. + NULL if neither attribute exists. +*/ +char *fz_xml_att_alt(fz_xml *item, const char *one, const char *two); + +/** + Check for a matching attribute on an XML node. + + If the node has the requested attribute (name), and the value + matches (match) then return 1. Otherwise, 0. +*/ +int fz_xml_att_eq(fz_xml *item, const char *name, const char *match); + +/** + Add an attribute to an XML node. +*/ +void fz_xml_add_att(fz_context *ctx, fz_pool *pool, fz_xml *node, const char *key, const char *val); + +/** + Return the text content of an XML node. Return NULL if the node is a tag. */ char *fz_xml_text(fz_xml *item); -/* - fz_debug_xml: Pretty-print an XML tree to stdout. +/** + Pretty-print an XML tree to given output. +*/ +void fz_output_xml(fz_context *ctx, fz_output *out, fz_xml *item, int level); + +/** + Pretty-print an XML tree to stdout. (Deprecated, use + fz_output_xml in preference). */ void fz_debug_xml(fz_xml *item, int level); +/** + Search the siblings of XML nodes starting with item looking for + the first with the given tag. + + Return NULL if none found. +*/ fz_xml *fz_xml_find(fz_xml *item, const char *tag); + +/** + Search the siblings of XML nodes starting with the first sibling + of item looking for the first with the given tag. + + Return NULL if none found. +*/ fz_xml *fz_xml_find_next(fz_xml *item, const char *tag); + +/** + Search the siblings of XML nodes starting with the first child + of item looking for the first with the given tag. + + Return NULL if none found. +*/ fz_xml *fz_xml_find_down(fz_xml *item, const char *tag); +/** + Search the siblings of XML nodes starting with item looking for + the first with the given tag (or any tag if tag is NULL), and + with a matching attribute. + + Return NULL if none found. +*/ +fz_xml *fz_xml_find_match(fz_xml *item, const char *tag, const char *att, const char *match); + +/** + Search the siblings of XML nodes starting with the first sibling + of item looking for the first with the given tag (or any tag if tag + is NULL), and with a matching attribute. + + Return NULL if none found. +*/ +fz_xml *fz_xml_find_next_match(fz_xml *item, const char *tag, const char *att, const char *match); + +/** + Search the siblings of XML nodes starting with the first child + of item looking for the first with the given tag (or any tag if + tag is NULL), and with a matching attribute. + + Return NULL if none found. +*/ +fz_xml *fz_xml_find_down_match(fz_xml *item, const char *tag, const char *att, const char *match); + +/** + Perform a depth first search from item, returning the first + child that matches the given tag (or any tag if tag is NULL), + with the given attribute (if att is non NULL), that matches + match (if match is non NULL). +*/ +fz_xml *fz_xml_find_dfs(fz_xml *item, const char *tag, const char *att, const char *match); + +/** + Perform a depth first search from item, returning the first + child that matches the given tag (or any tag if tag is NULL), + with the given attribute (if att is non NULL), that matches + match (if match is non NULL). The search stops if it ever + reaches the top of the tree, or the declared 'top' item. +*/ +fz_xml *fz_xml_find_dfs_top(fz_xml *item, const char *tag, const char *att, const char *match, fz_xml *top); + +/** + Perform a depth first search onwards from item, returning the first + child that matches the given tag (or any tag if tag is NULL), + with the given attribute (if att is non NULL), that matches + match (if match is non NULL). +*/ +fz_xml *fz_xml_find_next_dfs(fz_xml *item, const char *tag, const char *att, const char *match); + +/** + Perform a depth first search onwards from item, returning the first + child that matches the given tag (or any tag if tag is NULL), + with the given attribute (if att is non NULL), that matches + match (if match is non NULL). The search stops if it ever reaches + the top of the tree, or the declared 'top' item. +*/ +fz_xml *fz_xml_find_next_dfs_top(fz_xml *item, const char *tag, const char *att, const char *match, fz_xml *top); + +/** + DOM-like functions for html in xml. +*/ + +/** + Return a borrowed reference for the 'body' element of + the given DOM. +*/ +fz_xml *fz_dom_body(fz_context *ctx, fz_xml *dom); + +/** + Return a borrowed reference for the document (the top + level element) of the DOM. +*/ +fz_xml *fz_dom_document_element(fz_context *ctx, fz_xml *dom); + +/** + Create an element of a given tag type for the given DOM. + + The element is not linked into the DOM yet. +*/ +fz_xml *fz_dom_create_element(fz_context *ctx, fz_xml *dom, const char *tag); + +/** + Create a text node for the given DOM. + + The element is not linked into the DOM yet. +*/ +fz_xml *fz_dom_create_text_node(fz_context *ctx, fz_xml *dom, const char *text); + +/** + Find the first element matching the requirements in a depth first traversal from elt. + + The tagname must match tag, unless tag is NULL, when all tag names are considered to match. + + If att is NULL, then all tags match. + Otherwise: + If match is NULL, then only nodes that have an att attribute match. + If match is non-NULL, then only nodes that have an att attribute that matches match match. + + Returns NULL (if no match found), or a borrowed reference to the first matching element. +*/ +fz_xml *fz_dom_find(fz_context *ctx, fz_xml *elt, const char *tag, const char *att, const char *match); + +/** + Find the next element matching the requirements. +*/ +fz_xml *fz_dom_find_next(fz_context *ctx, fz_xml *elt, const char *tag, const char *att, const char *match); + +/** + Insert an element as the last child of a parent, unlinking the + child from its current position if required. +*/ +void fz_dom_append_child(fz_context *ctx, fz_xml *parent, fz_xml *child); + +/** + Insert an element (new_elt), before another element (node), + unlinking the new_elt from its current position if required. +*/ +void fz_dom_insert_before(fz_context *ctx, fz_xml *node, fz_xml *new_elt); + +/** + Insert an element (new_elt), after another element (node), + unlinking the new_elt from its current position if required. +*/ +void fz_dom_insert_after(fz_context *ctx, fz_xml *node, fz_xml *new_elt); + +/** + Remove an element from the DOM. The element can be added back elsewhere + if required. + + No reference counting changes for the element. +*/ +void fz_dom_remove(fz_context *ctx, fz_xml *elt); + +/** + Clone an element (and its children). + + A borrowed reference to the clone is returned. The clone is not + yet linked into the DOM. +*/ +fz_xml *fz_dom_clone(fz_context *ctx, fz_xml *elt); + +/** + Return a borrowed reference to the first child of a node, + or NULL if there isn't one. +*/ +fz_xml *fz_dom_first_child(fz_context *ctx, fz_xml *elt); + +/** + Return a borrowed reference to the parent of a node, + or NULL if there isn't one. +*/ +fz_xml *fz_dom_parent(fz_context *ctx, fz_xml *elt); + +/** + Return a borrowed reference to the next sibling of a node, + or NULL if there isn't one. +*/ +fz_xml *fz_dom_next(fz_context *ctx, fz_xml *elt); + +/** + Return a borrowed reference to the previous sibling of a node, + or NULL if there isn't one. +*/ +fz_xml *fz_dom_previous(fz_context *ctx, fz_xml *elt); + +/** + Add an attribute to an element. + + Ownership of att and value remain with the caller. +*/ +void fz_dom_add_attribute(fz_context *ctx, fz_xml *elt, const char *att, const char *value); + +/** + Remove an attribute from an element. +*/ +void fz_dom_remove_attribute(fz_context *ctx, fz_xml *elt, const char *att); + +/** + Retrieve the value of a given attribute from a given element. + + Returns a borrowed pointer to the value or NULL if not found. +*/ +const char *fz_dom_attribute(fz_context *ctx, fz_xml *elt, const char *att); + +/** + Enumerate through the attributes of an element. + + Call with i=0,1,2,3... to enumerate attributes. + + On return *att and the return value will be NULL if there are not + that many attributes to read. Otherwise, *att will be filled in + with a borrowed pointer to the attribute name, and the return + value will be a borrowed pointer to the value. +*/ +const char *fz_dom_get_attribute(fz_context *ctx, fz_xml *elt, int i, const char **att); + #endif diff --git a/include/mupdf/memento.h b/include/mupdf/memento.h index 0776860..b2d01b9 100644 --- a/include/mupdf/memento.h +++ b/include/mupdf/memento.h @@ -1,14 +1,16 @@ -/* Copyright (C) 2009-2017 Artifex Software, Inc. +/* Copyright (C) 2009-2022 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. - This software is distributed under license and may not be copied, modified - or distributed except as expressly authorized under the terms of that - license. Refer to licensing information at http://www.artifex.com - or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, - San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file COPYING in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, + CA 94129, USA, for further information. */ /* Memento: A library to aid debugging of memory leaks/heap corruption. @@ -75,8 +77,7 @@ * An example: * Suppose we have a gs invocation that crashes with memory corruption. * * Build with -DMEMENTO. - * * In your debugger put breakpoints on Memento_inited and - * Memento_Breakpoint. + * * In your debugger put a breakpoint on Memento_breakpoint. * * Run the program. It will stop in Memento_inited. * * Execute Memento_setParanoia(1); (In VS use Ctrl-Alt-Q). (Note #1) * * Continue execution. @@ -92,9 +93,9 @@ * and 1458 - so if we rerun and stop the program at 1457, we can then * step through, possibly with a data breakpoint at 0x172e710 and see * when it occurs. - * * So restart the program from the beginning. When we hit Memento_inited - * execute Memento_breakAt(1457); (and maybe Memento_setParanoia(1), or - * Memento_setParanoidAt(1457)) + * * So restart the program from the beginning. When we stop after + * initialisation execute Memento_breakAt(1457); (and maybe + * Memento_setParanoia(1), or Memento_setParanoidAt(1457)) * * Continue execution until we hit Memento_breakpoint. * * Now you can step through and watch the memory corruption happen. * @@ -140,30 +141,99 @@ * Memento has some experimental code in it to trap new/delete (and * new[]/delete[] if required) calls. * - * In order for this to work, either: + * In all cases, Memento will provide a C API that new/delete + * operators can be built upon: + * void *Memento_cpp_new(size_t size); + * void Memento_cpp_delete(void *pointer); + * void *Memento_cpp_new_array(size_t size); + * void Memento_cpp_delete_array(void *pointer); * - * 1) Build memento.c with the c++ compiler. + * There are various ways that actual operator definitions can be + * provided: + * + * 1) If memento.c is built with the c++ compiler, then global new + * and delete operators will be built in to memento by default. + * + * 2) If memento.c is built as normal with the C compiler, then + * no such veneers will be built in. The caller must provide them + * themselves. This can be done either by: + * + * a) Copying the lines between: + * // C++ Operator Veneers - START + * and + * // C++ Operator Veneers - END + * from memento.c into a C++ file within their own project. * * or * - * 2) Build memento.c as normal with the C compiler, then from any - * one of your .cpp files, do: + * b) Add the following lines to a C++ file in the project: + * #define MEMENTO_CPP_EXTRAS_ONLY + * #include "memento.c" * - * #define MEMENTO_CPP_EXTRAS_ONLY - * #include "memento.c" + * 3) For those people that would like to be able to compile memento.c + * with a C compiler, and provide new/delete veneers globally + * within their own C++ code (so avoiding the need for memento.h to + * be included from every file), define MEMENTO_NO_CPLUSPLUS as you + * build, and Memento will not provide any veneers itself, instead + * relying on the library user to provide them. * - * In the case where MEMENTO is not defined, this will not do anything. + * For convenience the lines to implement such veneers can be found + * at the end of memento.c between: + * // C++ Operator Veneers - START + * and + * // C++ Operator Veneers - END + * + * Memento's interception of new/delete can be disabled at runtime + * by using Memento_setIgnoreNewDelete(1). Alternatively the + * MEMENTO_IGNORENEWDELETE environment variable can be set to 1 to + * achieve the same result. * * Both Windows and GCC provide separate new[] and delete[] operators * for arrays. Apparently some systems do not. If this is the case for * your system, define MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS. + * + * "libbacktrace.so failed to load" + * + * In order to give nice backtraces on unix, Memento will try to use + * a libbacktrace dynamic library. If it can't find it, you'll see + * that warning, and your backtraces won't include file/line information. + * + * To fix this you'll need to build your own libbacktrace. Don't worry + * it's really easy: + * git clone git://github.com/ianlancetaylor/libbacktrace + * cd libbacktrace + * ./configure --enable-shared + * make + * + * This leaves the build .so as .libs/libbacktrace.so + * + * Memento will look for this on LD_LIBRARY_PATH, or in /opt/lib/, + * or in /lib/, or in /usr/lib/, or in /usr/local/lib/. I recommend + * using /opt/lib/ as this won't conflict with anything that you + * get via a package manager like apt. + * + * sudo mkdir /opt + * sudo mkdir /opt/lib + * sudo cp .libs/libbacktrace.so /opt/lib/ */ +#ifdef __cplusplus + +// Avoids problems with strdup()'s throw() attribute on Linux. +#include + +extern "C" { +#endif + #ifndef MEMENTO_H -#define MEMENTO_H +/* Include all these first, so our definitions below do + * not conflict with them. */ +#include +#include +#include -#include /* for size_t */ +#define MEMENTO_H #ifndef MEMENTO_UNDERLYING_MALLOC #define MEMENTO_UNDERLYING_MALLOC malloc @@ -187,8 +257,6 @@ #define MEMENTO_ALLOCFILL 0xa8 #define MEMENTO_FREEFILL 0xa9 -#define MEMENTO_FREELIST_MAX 0x2000000 - int Memento_checkBlock(void *); int Memento_checkAllMemory(void); int Memento_check(void); @@ -205,18 +273,36 @@ int Memento_failAt(int); int Memento_failThisEvent(void); void Memento_listBlocks(void); void Memento_listNewBlocks(void); +void Memento_listPhasedBlocks(void); size_t Memento_setMax(size_t); void Memento_stats(void); void *Memento_label(void *, const char *); void Memento_tick(void); +int Memento_setVerbose(int); + +/* Terminate backtraces if we see specified function name. E.g. +'cfunction_call' will exclude Python interpreter functions when Python calls C +code. Returns 0 on success, -1 on failure (out of memory). */ +int Memento_addBacktraceLimitFnname(const char *fnname); + +/* If is 0, we do not call Memento_fin() in an atexit() handler. */ +int Memento_setAtexitFin(int atexitfin); + +int Memento_setIgnoreNewDelete(int ignore); void *Memento_malloc(size_t s); void *Memento_realloc(void *, size_t s); void Memento_free(void *); void *Memento_calloc(size_t, size_t); +char *Memento_strdup(const char*); +#if !defined(MEMENTO_GS_HACKS) && !defined(MEMENTO_MUPDF_HACKS) +int Memento_asprintf(char **ret, const char *format, ...); +int Memento_vasprintf(char **ret, const char *format, va_list ap); +#endif void Memento_info(void *addr); void Memento_listBlockInfo(void); +void Memento_blockInfo(void *blk); void *Memento_takeByteRef(void *blk); void *Memento_dropByteRef(void *blk); void *Memento_takeShortRef(void *blk); @@ -236,23 +322,48 @@ int Memento_checkIntPointerOrNull(void *blk); void Memento_startLeaking(void); void Memento_stopLeaking(void); +/* Returns number of allocation events so far. */ +int Memento_sequence(void); + +/* Returns non-zero if our process was forked by Memento squeeze. */ +int Memento_squeezing(void); + void Memento_fin(void); +void Memento_bt(void); + +void *Memento_cpp_new(size_t size); +void Memento_cpp_delete(void *pointer); +void *Memento_cpp_new_array(size_t size); +void Memento_cpp_delete_array(void *pointer); + +void Memento_showHash(unsigned int hash); + #ifdef MEMENTO #ifndef COMPILING_MEMENTO_C -#define malloc Memento_malloc -#define free Memento_free -#define realloc Memento_realloc -#define calloc Memento_calloc +#define malloc Memento_malloc +#define free Memento_free +#define realloc Memento_realloc +#define calloc Memento_calloc +#define strdup Memento_strdup +#if !defined(MEMENTO_GS_HACKS) && !defined(MEMENTO_MUPDF_HACKS) +#define asprintf Memento_asprintf +#define vasprintf Memento_vasprintf +#endif #endif #else -#define Memento_malloc MEMENTO_UNDERLYING_MALLOC -#define Memento_free MEMENTO_UNDERLYING_FREE -#define Memento_realloc MEMENTO_UNDERLYING_REALLOC -#define Memento_calloc MEMENTO_UNDERLYING_CALLOC +#define Memento_malloc MEMENTO_UNDERLYING_MALLOC +#define Memento_free MEMENTO_UNDERLYING_FREE +#define Memento_realloc MEMENTO_UNDERLYING_REALLOC +#define Memento_calloc MEMENTO_UNDERLYING_CALLOC +#define Memento_strdup strdup +#if !defined(MEMENTO_GS_HACKS) && !defined(MEMENTO_MUPDF_HACKS) +#define Memento_asprintf asprintf +#define Memento_vasprintf vasprintf +#endif #define Memento_checkBlock(A) 0 #define Memento_checkAllMemory() 0 @@ -269,11 +380,13 @@ void Memento_fin(void); #define Memento_failThisEvent() 0 #define Memento_listBlocks() do {} while (0) #define Memento_listNewBlocks() do {} while (0) +#define Memento_listPhasedBlocks() do {} while (0) #define Memento_setMax(A) 0 #define Memento_stats() do {} while (0) #define Memento_label(A,B) (A) #define Memento_info(A) do {} while (0) #define Memento_listBlockInfo() do {} while (0) +#define Memento_blockInfo(A) do {} while (0) #define Memento_takeByteRef(A) (A) #define Memento_dropByteRef(A) (A) #define Memento_takeShortRef(A) (A) @@ -288,12 +401,23 @@ void Memento_fin(void); #define Memento_checkBytePointerOrNull(A) 0 #define Memento_checkShortPointerOrNull(A) 0 #define Memento_checkIntPointerOrNull(A) 0 +#define Memento_setIgnoreNewDelete(v) 0 #define Memento_tick() do {} while (0) #define Memento_startLeaking() do {} while (0) #define Memento_stopLeaking() do {} while (0) #define Memento_fin() do {} while (0) +#define Memento_bt() do {} while (0) +#define Memento_sequence() (0) +#define Memento_squeezing() (0) +#define Memento_setVerbose(A) (A) +#define Memento_addBacktraceLimitFnname(A) (0) +#define Memento_setAtexitFin(atexitfin) (0) #endif /* MEMENTO */ +#ifdef __cplusplus +} +#endif + #endif /* MEMENTO_H */ diff --git a/include/mupdf/vendor.go b/include/mupdf/vendor.go new file mode 100644 index 0000000..4a5fffb --- /dev/null +++ b/include/mupdf/vendor.go @@ -0,0 +1,3 @@ +//go:build required + +package vendor diff --git a/include/vendor.go b/include/vendor.go new file mode 100644 index 0000000..4a5fffb --- /dev/null +++ b/include/vendor.go @@ -0,0 +1,3 @@ +//go:build required + +package vendor diff --git a/libs/libmupdf_android_arm.a b/libs/libmupdf_android_arm.a deleted file mode 100644 index ae1fc31..0000000 Binary files a/libs/libmupdf_android_arm.a and /dev/null differ diff --git a/libs/libmupdf_android_arm64.a b/libs/libmupdf_android_arm64.a index 834d0ff..634ba8a 100644 Binary files a/libs/libmupdf_android_arm64.a and b/libs/libmupdf_android_arm64.a differ diff --git a/libs/libmupdf_darwin_amd64.a b/libs/libmupdf_darwin_amd64.a index 4cc736a..de8b642 100644 Binary files a/libs/libmupdf_darwin_amd64.a and b/libs/libmupdf_darwin_amd64.a differ diff --git a/libs/libmupdf_darwin_arm64.a b/libs/libmupdf_darwin_arm64.a new file mode 100644 index 0000000..8dfab9b Binary files /dev/null and b/libs/libmupdf_darwin_arm64.a differ diff --git a/libs/libmupdf_linux_386.a b/libs/libmupdf_linux_386.a deleted file mode 100644 index 425e438..0000000 Binary files a/libs/libmupdf_linux_386.a and /dev/null differ diff --git a/libs/libmupdf_linux_amd64.a b/libs/libmupdf_linux_amd64.a index 9272ac0..1a639a5 100644 Binary files a/libs/libmupdf_linux_amd64.a and b/libs/libmupdf_linux_amd64.a differ diff --git a/libs/libmupdf_linux_amd64_musl.a b/libs/libmupdf_linux_amd64_musl.a new file mode 100644 index 0000000..7aa9373 Binary files /dev/null and b/libs/libmupdf_linux_amd64_musl.a differ diff --git a/libs/libmupdf_linux_amd64_nopie.a b/libs/libmupdf_linux_amd64_nopie.a deleted file mode 100644 index 56daddd..0000000 Binary files a/libs/libmupdf_linux_amd64_nopie.a and /dev/null differ diff --git a/libs/libmupdf_linux_arm.a b/libs/libmupdf_linux_arm.a deleted file mode 100644 index 0bb614f..0000000 Binary files a/libs/libmupdf_linux_arm.a and /dev/null differ diff --git a/libs/libmupdf_linux_arm64.a b/libs/libmupdf_linux_arm64.a index 8984667..c542191 100644 Binary files a/libs/libmupdf_linux_arm64.a and b/libs/libmupdf_linux_arm64.a differ diff --git a/libs/libmupdf_linux_arm64_musl.a b/libs/libmupdf_linux_arm64_musl.a new file mode 100644 index 0000000..5180435 Binary files /dev/null and b/libs/libmupdf_linux_arm64_musl.a differ diff --git a/libs/libmupdf_windows_386.a b/libs/libmupdf_windows_386.a deleted file mode 100644 index 5ed6a5e..0000000 Binary files a/libs/libmupdf_windows_386.a and /dev/null differ diff --git a/libs/libmupdf_windows_amd64.a b/libs/libmupdf_windows_amd64.a index c495944..2070f9f 100644 Binary files a/libs/libmupdf_windows_amd64.a and b/libs/libmupdf_windows_amd64.a differ diff --git a/libs/libmupdf_windows_arm64.a b/libs/libmupdf_windows_arm64.a new file mode 100644 index 0000000..4244e07 Binary files /dev/null and b/libs/libmupdf_windows_arm64.a differ diff --git a/libs/libmupdfthird_android_arm.a b/libs/libmupdfthird_android_arm.a deleted file mode 100644 index b9df955..0000000 Binary files a/libs/libmupdfthird_android_arm.a and /dev/null differ diff --git a/libs/libmupdfthird_android_arm64.a b/libs/libmupdfthird_android_arm64.a index 408bc12..b3e58e6 100644 Binary files a/libs/libmupdfthird_android_arm64.a and b/libs/libmupdfthird_android_arm64.a differ diff --git a/libs/libmupdfthird_darwin_amd64.a b/libs/libmupdfthird_darwin_amd64.a index 563d7b4..6d75616 100644 Binary files a/libs/libmupdfthird_darwin_amd64.a and b/libs/libmupdfthird_darwin_amd64.a differ diff --git a/libs/libmupdfthird_darwin_arm64.a b/libs/libmupdfthird_darwin_arm64.a new file mode 100644 index 0000000..571215a Binary files /dev/null and b/libs/libmupdfthird_darwin_arm64.a differ diff --git a/libs/libmupdfthird_linux_386.a b/libs/libmupdfthird_linux_386.a deleted file mode 100644 index 9f064d4..0000000 Binary files a/libs/libmupdfthird_linux_386.a and /dev/null differ diff --git a/libs/libmupdfthird_linux_amd64.a b/libs/libmupdfthird_linux_amd64.a index de3f6f6..e4d29dc 100644 Binary files a/libs/libmupdfthird_linux_amd64.a and b/libs/libmupdfthird_linux_amd64.a differ diff --git a/libs/libmupdfthird_linux_amd64_musl.a b/libs/libmupdfthird_linux_amd64_musl.a new file mode 100644 index 0000000..95d0244 Binary files /dev/null and b/libs/libmupdfthird_linux_amd64_musl.a differ diff --git a/libs/libmupdfthird_linux_amd64_nopie.a b/libs/libmupdfthird_linux_amd64_nopie.a deleted file mode 100644 index ecc8773..0000000 Binary files a/libs/libmupdfthird_linux_amd64_nopie.a and /dev/null differ diff --git a/libs/libmupdfthird_linux_arm.a b/libs/libmupdfthird_linux_arm.a deleted file mode 100644 index 6bea90b..0000000 Binary files a/libs/libmupdfthird_linux_arm.a and /dev/null differ diff --git a/libs/libmupdfthird_linux_arm64.a b/libs/libmupdfthird_linux_arm64.a index 2efd5ab..9e5ea94 100644 Binary files a/libs/libmupdfthird_linux_arm64.a and b/libs/libmupdfthird_linux_arm64.a differ diff --git a/libs/libmupdfthird_linux_arm64_musl.a b/libs/libmupdfthird_linux_arm64_musl.a new file mode 100644 index 0000000..5f0cf17 Binary files /dev/null and b/libs/libmupdfthird_linux_arm64_musl.a differ diff --git a/libs/libmupdfthird_windows_386.a b/libs/libmupdfthird_windows_386.a deleted file mode 100644 index be8d3c7..0000000 Binary files a/libs/libmupdfthird_windows_386.a and /dev/null differ diff --git a/libs/libmupdfthird_windows_amd64.a b/libs/libmupdfthird_windows_amd64.a index 96cd3d6..cf33623 100644 Binary files a/libs/libmupdfthird_windows_amd64.a and b/libs/libmupdfthird_windows_amd64.a differ diff --git a/libs/libmupdfthird_windows_arm64.a b/libs/libmupdfthird_windows_arm64.a new file mode 100644 index 0000000..52a8cb7 Binary files /dev/null and b/libs/libmupdfthird_windows_arm64.a differ diff --git a/libs/vendor.go b/libs/vendor.go new file mode 100644 index 0000000..4a5fffb --- /dev/null +++ b/libs/vendor.go @@ -0,0 +1,3 @@ +//go:build required + +package vendor diff --git a/purego_darwin.go b/purego_darwin.go new file mode 100644 index 0000000..419cd86 --- /dev/null +++ b/purego_darwin.go @@ -0,0 +1,33 @@ +//go:build (!cgo || nocgo) && darwin + +package fitz + +import ( + "fmt" + + "github.com/ebitengine/purego" +) + +const ( + libname = "libmupdf.dylib" +) + +// loadLibrary loads the so and panics on error. +func loadLibrary() uintptr { + handle, err := purego.Dlopen(libname, purego.RTLD_NOW|purego.RTLD_GLOBAL) + if err != nil { + panic(fmt.Errorf("cannot load library: %w", err)) + } + + return handle +} + +// procAddress returns the address of symbol name. +func procAddress(handle uintptr, procName string) uintptr { + addr, err := purego.Dlsym(handle, procName) + if err != nil { + panic(fmt.Errorf("cannot get proc address for %s: %w", procName, err)) + } + + return addr +} diff --git a/purego_linux.go b/purego_linux.go new file mode 100644 index 0000000..d69686f --- /dev/null +++ b/purego_linux.go @@ -0,0 +1,32 @@ +//go:build (!cgo || nocgo) && unix && !darwin + +package fitz + +import ( + "fmt" + "github.com/ebitengine/purego" +) + +const ( + libname = "libmupdf.so" +) + +// loadLibrary loads the so and panics on error. +func loadLibrary() uintptr { + handle, err := purego.Dlopen(libname, purego.RTLD_NOW|purego.RTLD_GLOBAL) + if err != nil { + panic(fmt.Errorf("cannot load library: %w", err)) + } + + return handle +} + +// procAddress returns the address of symbol name. +func procAddress(handle uintptr, procName string) uintptr { + addr, err := purego.Dlsym(handle, procName) + if err != nil { + panic(fmt.Errorf("cannot get proc address for %s: %w", procName, err)) + } + + return addr +} diff --git a/purego_windows.go b/purego_windows.go new file mode 100644 index 0000000..7585968 --- /dev/null +++ b/purego_windows.go @@ -0,0 +1,34 @@ +//go:build (!cgo || nocgo) && windows + +package fitz + +import ( + "fmt" + "syscall" + + "golang.org/x/sys/windows" +) + +const ( + libname = "libmupdf.dll" +) + +// loadLibrary loads the dll and panics on error. +func loadLibrary() uintptr { + handle, err := syscall.LoadLibrary(libname) + if err != nil { + panic(fmt.Errorf("cannot load library %s: %w", libname, err)) + } + + return uintptr(handle) +} + +// procAddress returns the address of symbol name. +func procAddress(handle uintptr, procName string) uintptr { + addr, err := windows.GetProcAddress(windows.Handle(handle), procName) + if err != nil { + panic(fmt.Errorf("cannot get proc address for %s: %w", procName, err)) + } + + return addr +} diff --git a/testdata/test.bmp b/testdata/test.bmp new file mode 100644 index 0000000..02dc6d6 Binary files /dev/null and b/testdata/test.bmp differ diff --git a/testdata/test.cbz b/testdata/test.cbz new file mode 100644 index 0000000..168f6f5 Binary files /dev/null and b/testdata/test.cbz differ diff --git a/testdata/test.docx b/testdata/test.docx new file mode 100644 index 0000000..1bac61d Binary files /dev/null and b/testdata/test.docx differ diff --git a/testdata/test.epub b/testdata/test.epub new file mode 100644 index 0000000..9ccf430 Binary files /dev/null and b/testdata/test.epub differ diff --git a/testdata/test.fb2 b/testdata/test.fb2 new file mode 100644 index 0000000..f1292bf --- /dev/null +++ b/testdata/test.fb2 @@ -0,0 +1,11 @@ + + + + + Hello World + + + +
Hello World
+ +
diff --git a/testdata/test.gif b/testdata/test.gif new file mode 100644 index 0000000..d5e923d Binary files /dev/null and b/testdata/test.gif differ diff --git a/testdata/test.jb2 b/testdata/test.jb2 new file mode 100644 index 0000000..ae48d91 Binary files /dev/null and b/testdata/test.jb2 differ diff --git a/testdata/test.jp2 b/testdata/test.jp2 new file mode 100644 index 0000000..63714f9 Binary files /dev/null and b/testdata/test.jp2 differ diff --git a/testdata/test.jpg b/testdata/test.jpg new file mode 100644 index 0000000..3219d31 Binary files /dev/null and b/testdata/test.jpg differ diff --git a/testdata/test.jxr b/testdata/test.jxr new file mode 100644 index 0000000..3e4fc35 Binary files /dev/null and b/testdata/test.jxr differ diff --git a/testdata/test.mobi b/testdata/test.mobi new file mode 100644 index 0000000..2ac34e9 Binary files /dev/null and b/testdata/test.mobi differ diff --git a/testdata/test.pam b/testdata/test.pam new file mode 100644 index 0000000..1653f1f --- /dev/null +++ b/testdata/test.pam @@ -0,0 +1,10 @@ +P7 +WIDTH 3 +HEIGHT 3 +DEPTH 1 +MAXVAL 1 +TUPLETYPE blackandwhite +ENDHDR +1 0 1 +0 1 0 +1 0 1 \ No newline at end of file diff --git a/testdata/test.pbm b/testdata/test.pbm new file mode 100644 index 0000000..fbcb39d --- /dev/null +++ b/testdata/test.pbm @@ -0,0 +1,5 @@ +P1 +3 3 +1 0 1 +0 1 0 +1 0 1 \ No newline at end of file diff --git a/testdata/test.pfm b/testdata/test.pfm new file mode 100644 index 0000000..4b51ce6 Binary files /dev/null and b/testdata/test.pfm differ diff --git a/testdata/test.pgm b/testdata/test.pgm new file mode 100644 index 0000000..d2728b9 --- /dev/null +++ b/testdata/test.pgm @@ -0,0 +1,6 @@ +P2 +3 3 +2 +0 1 2 +0 1 2 +0 1 2 \ No newline at end of file diff --git a/testdata/test.png b/testdata/test.png new file mode 100644 index 0000000..a7045ed Binary files /dev/null and b/testdata/test.png differ diff --git a/testdata/test.ppm b/testdata/test.ppm new file mode 100644 index 0000000..63b65ad --- /dev/null +++ b/testdata/test.ppm @@ -0,0 +1,12 @@ +P3 +3 3 +255 +255 0 0 + 0 255 0 + 0 0 255 +255 255 0 + 0 255 0 +255 0 255 +255 255 255 + 0 255 0 + 0 255 255 \ No newline at end of file diff --git a/testdata/test.pptx b/testdata/test.pptx new file mode 100644 index 0000000..ea72794 Binary files /dev/null and b/testdata/test.pptx differ diff --git a/testdata/test.psd b/testdata/test.psd new file mode 100644 index 0000000..908f0e0 Binary files /dev/null and b/testdata/test.psd differ diff --git a/testdata/test.svg b/testdata/test.svg new file mode 100644 index 0000000..0555bfe --- /dev/null +++ b/testdata/test.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/testdata/test.tif b/testdata/test.tif new file mode 100644 index 0000000..c131b8f Binary files /dev/null and b/testdata/test.tif differ diff --git a/testdata/test.xlsx b/testdata/test.xlsx new file mode 100644 index 0000000..04ac8ab Binary files /dev/null and b/testdata/test.xlsx differ diff --git a/testdata/test.xps b/testdata/test.xps new file mode 100644 index 0000000..d82f61e Binary files /dev/null and b/testdata/test.xps differ