forked from unidoc/unipdf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic image rendering support (unidoc#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
- Loading branch information
Showing
16 changed files
with
3,257 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,12 @@ | ||
module github.com/unidoc/unipdf/v3 | ||
|
||
require ( | ||
github.com/adrg/sysfont v0.1.0 | ||
github.com/boombuler/barcode v1.0.0 | ||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 | ||
github.com/gunnsth/pkcs7 v0.0.0-20181213175627-3cffc6fbfe83 | ||
github.com/stretchr/testify v1.3.0 | ||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 | ||
golang.org/x/image v0.0.0-20181116024801-cd38e8056d9b | ||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 // indirect | ||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f // indirect | ||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444 // indirect | ||
golang.org/x/text v0.3.2 | ||
golang.org/x/tools v0.0.0-20190606174628-0139d5756a7d // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* | ||
* 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}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
* This file is subject to the terms and conditions defined in | ||
* file 'LICENSE.md', which is part of this source code package. | ||
*/ | ||
|
||
package context | ||
|
||
import "image/color" | ||
|
||
// FillRule represents the fill style used by a context instance. | ||
type FillRule int | ||
|
||
// Fill rules. | ||
const ( | ||
FillRuleWinding FillRule = iota | ||
FillRuleEvenOdd | ||
) | ||
|
||
// LineCap represents the line cap style used by a context instance. | ||
type LineCap int | ||
|
||
// Line cap styles. | ||
const ( | ||
LineCapRound LineCap = iota | ||
LineCapButt | ||
LineCapSquare | ||
) | ||
|
||
// LineJoin represents the line join style used by a context instance. | ||
type LineJoin int | ||
|
||
// Line join styles. | ||
const ( | ||
LineJoinRound LineJoin = iota | ||
LineJoinBevel | ||
) | ||
|
||
// Pattern represents a pattern which can be rendered by a context instance. | ||
type Pattern interface { | ||
ColorAt(x, y int) color.Color | ||
} | ||
|
||
// Gradient represents a gradient pattern which can be rendered by a context instance. | ||
type Gradient interface { | ||
Pattern | ||
AddColorStop(offset float64, color color.Color) | ||
} |
Oops, something went wrong.