unipdf/render/image_device.go

107 lines
2.4 KiB
Go
Raw Normal View History

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 23:22:54 +02:00
/*
* 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})
}