unipdf/render/image_device.go
Adrian-George Bostan d961079c5d
Add basic image rendering support (#266)
* Add render package
* Add text state
* Add more text operators
* Remove unnecessary files
* Add text font
* Add custom text render method
* Improve text rendering method
* Rename text state methods
* Refactor and document context interface
* Refact text begin/end operators
* Fix graphics state transformations
* Keep original font when doing font substitution
* Take page cropbox into account
* Revert to substitution font if original font measurement is 0
* Add font substitution package
* Implement addition transform.Point methods
* Use transform.Point in the image context package
* Remove unneeded functionality from the render image package
* Fix golint notices in the image rendering package
* Fix go vet notices in the render package
* Fix golint notices in the top-level render package
* Improve render context package documentation
* Document context text state struct.
* Document context text font struct.
* Minor logging improvements
* Add license disclaimer to the render package files
* Avoid using package aliases where possible
* Change style of section comments
* Adapt render package import style to follow the developer guide
* Improve documentation for the internal matrix implementation
* Update render package dependency versions
* Apply crop box post render
* Account for offseted media boxes
* Improve metrics of rendered characters
* Fix text matrix translation
* Change priority of fonts used for measuring rendered characters
* Skip invalid m and l operators on image rendering
* Small fix for v operator
* Fix rendered characters spacing issues
* Refactor naming of internal render packages
2020-03-02 21:22:54 +00:00

107 lines
2.4 KiB
Go

/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package render
import (
"errors"
"fmt"
"image"
"image/draw"
"image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"
"github.com/unidoc/unipdf/v3/model"
"github.com/unidoc/unipdf/v3/render/internal/context/imagerender"
)
// ImageDevice is used to render PDF pages to image targets.
type ImageDevice struct {
renderer
}
// NewImageDevice returns a new image device.
func NewImageDevice() *ImageDevice {
return &ImageDevice{}
}
// Render converts the specified PDF page into an image and returns the result.
func (d *ImageDevice) Render(page *model.PdfPage) (image.Image, error) {
// Get page dimensions.
mbox, err := page.GetMediaBox()
if err != nil {
return nil, err
}
// Render page.
width, height := mbox.Llx+mbox.Width(), mbox.Lly+mbox.Height()
ctx := imagerender.NewContext(int(width), int(height))
if err := d.renderPage(ctx, page); err != nil {
return nil, err
}
// Apply crop box, if one exists.
img := ctx.Image()
if box := page.CropBox; box != nil {
// Calculate crop bounds and crop start position.
cropBounds := image.Rect(0, 0, int(box.Width()), int(box.Height()))
cropStart := image.Pt(int(box.Llx), int(height-box.Ury))
// Crop image.
cropImg := image.NewRGBA(cropBounds)
draw.Draw(cropImg, cropBounds, img, cropStart, draw.Src)
img = cropImg
}
return img, nil
}
// RenderToPath converts the specified PDF page into an image and saves the
// result at the specified location.
func (d *ImageDevice) RenderToPath(page *model.PdfPage, outputPath string) error {
image, err := d.Render(page)
if err != nil {
return err
}
extension := strings.ToLower(filepath.Ext(outputPath))
if extension == "" {
return errors.New("could not recognize output file type")
}
switch extension {
case ".png":
return savePNG(outputPath, image)
case ".jpg", ".jpeg":
return saveJPG(outputPath, image, 100)
}
return fmt.Errorf("unrecognized output file type: %s", extension)
}
func savePNG(path string, image image.Image) error {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
return png.Encode(file, image)
}
func saveJPG(path string, image image.Image, quality int) error {
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
return jpeg.Encode(file, image, &jpeg.Options{Quality: quality})
}