2017-02-22 21:10:57 +00:00
|
|
|
/*
|
|
|
|
* This file is subject to the terms and conditions defined in
|
|
|
|
* file 'LICENSE.md', which is part of this source code package.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package model
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
|
2017-03-01 16:02:53 +00:00
|
|
|
"github.com/unidoc/unidoc/common"
|
2017-02-22 21:10:57 +00:00
|
|
|
. "github.com/unidoc/unidoc/pdf/core"
|
|
|
|
)
|
|
|
|
|
2017-03-01 16:02:53 +00:00
|
|
|
// XObjectForm (Table 95 in 8.10.2).
|
|
|
|
type XObjectForm struct {
|
|
|
|
Filter StreamEncoder
|
|
|
|
|
|
|
|
FormType PdfObject
|
|
|
|
BBox PdfObject
|
|
|
|
Matrix PdfObject
|
2017-04-04 12:09:26 +00:00
|
|
|
Resources *PdfPageResources
|
2017-03-01 16:02:53 +00:00
|
|
|
Group PdfObject
|
|
|
|
Ref PdfObject
|
|
|
|
MetaData PdfObject
|
|
|
|
PieceInfo PdfObject
|
|
|
|
LastModified PdfObject
|
|
|
|
StructParent PdfObject
|
|
|
|
StructParents PdfObject
|
|
|
|
OPI PdfObject
|
|
|
|
OC PdfObject
|
|
|
|
Name PdfObject
|
2017-03-04 17:27:23 +00:00
|
|
|
|
2017-03-01 16:02:53 +00:00
|
|
|
// Stream data.
|
|
|
|
Stream []byte
|
|
|
|
// Primitive
|
|
|
|
primitive *PdfObjectStream
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a brand new XObject Form. Creates a new underlying PDF object stream primitive.
|
|
|
|
func NewXObjectForm() *XObjectForm {
|
|
|
|
xobj := &XObjectForm{}
|
|
|
|
stream := &PdfObjectStream{}
|
|
|
|
stream.PdfObjectDictionary = &PdfObjectDictionary{}
|
|
|
|
xobj.primitive = stream
|
|
|
|
return xobj
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the Form XObject from a stream object.
|
|
|
|
// XXX: Should this be exposed? Consider different access points.
|
|
|
|
func NewXObjectFormFromStream(stream *PdfObjectStream) (*XObjectForm, error) {
|
|
|
|
form := &XObjectForm{}
|
|
|
|
form.primitive = stream
|
|
|
|
|
|
|
|
dict := *(stream.PdfObjectDictionary)
|
|
|
|
|
|
|
|
encoder, err := NewEncoderFromStream(stream)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
form.Filter = encoder
|
|
|
|
|
|
|
|
if obj, isDefined := dict["Subtype"]; isDefined {
|
|
|
|
name, ok := obj.(*PdfObjectName)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("Type error")
|
|
|
|
}
|
|
|
|
if *name != "Form" {
|
|
|
|
common.Log.Debug("Invalid form subtype")
|
|
|
|
return nil, errors.New("Invalid form subtype")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if obj, isDefined := dict["FormType"]; isDefined {
|
|
|
|
form.FormType = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["BBox"]; isDefined {
|
|
|
|
form.BBox = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Matrix"]; isDefined {
|
|
|
|
form.Matrix = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Resources"]; isDefined {
|
2017-03-04 17:27:23 +00:00
|
|
|
obj = TraceToDirectObject(obj)
|
|
|
|
d, ok := obj.(*PdfObjectDictionary)
|
|
|
|
if !ok {
|
|
|
|
common.Log.Debug("Invalid XObject Form Resources object, pointing to non-dictionary")
|
|
|
|
return nil, errors.New("Type check error")
|
|
|
|
}
|
|
|
|
res, err := NewPdfPageResourcesFromDict(d)
|
|
|
|
if err != nil {
|
|
|
|
common.Log.Debug("Failed getting form resources")
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-04-04 12:09:26 +00:00
|
|
|
form.Resources = res
|
|
|
|
common.Log.Trace("Form resources: %#v", form.Resources)
|
2017-03-01 16:02:53 +00:00
|
|
|
}
|
2017-03-04 17:27:23 +00:00
|
|
|
|
2017-03-01 16:02:53 +00:00
|
|
|
if obj, isDefined := dict["Group"]; isDefined {
|
|
|
|
form.Group = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Ref"]; isDefined {
|
|
|
|
form.Ref = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["MetaData"]; isDefined {
|
|
|
|
form.MetaData = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["PieceInfo"]; isDefined {
|
|
|
|
form.PieceInfo = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["LastModified"]; isDefined {
|
|
|
|
form.LastModified = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["StructParent"]; isDefined {
|
|
|
|
form.StructParent = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["StructParents"]; isDefined {
|
|
|
|
form.StructParents = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["OPI"]; isDefined {
|
|
|
|
form.OPI = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["OC"]; isDefined {
|
|
|
|
form.OC = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Name"]; isDefined {
|
|
|
|
form.Name = obj
|
|
|
|
}
|
|
|
|
|
|
|
|
form.Stream = stream.Stream
|
|
|
|
|
|
|
|
return form, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (xform *XObjectForm) GetContainingPdfObject() PdfObject {
|
|
|
|
return xform.primitive
|
|
|
|
}
|
|
|
|
|
|
|
|
func (xform *XObjectForm) GetContentStream() ([]byte, error) {
|
|
|
|
decoded, err := DecodeStream(xform.primitive)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoded, nil
|
|
|
|
}
|
|
|
|
|
2017-04-09 16:49:15 +00:00
|
|
|
// Update the content stream with specified encoding. If encoding is null, will use the xform.Filter object
|
|
|
|
// or Raw encoding if not set.
|
|
|
|
func (xform *XObjectForm) SetContentStream(content []byte, encoder StreamEncoder) error {
|
2017-03-14 13:04:51 +00:00
|
|
|
encoded := content
|
2017-04-09 16:49:15 +00:00
|
|
|
|
|
|
|
if encoder == nil {
|
|
|
|
if xform.Filter != nil {
|
|
|
|
encoder = xform.Filter
|
|
|
|
} else {
|
|
|
|
encoder = NewRawEncoder()
|
2017-03-14 13:04:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-09 16:49:15 +00:00
|
|
|
enc, err := encoder.EncodeBytes(encoded)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
encoded = enc
|
|
|
|
|
2017-04-04 12:09:26 +00:00
|
|
|
xform.Stream = encoded
|
2017-03-14 13:04:51 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-03-01 16:02:53 +00:00
|
|
|
// Return a stream object.
|
|
|
|
func (xform *XObjectForm) ToPdfObject() PdfObject {
|
|
|
|
stream := xform.primitive
|
|
|
|
|
|
|
|
dict := stream.PdfObjectDictionary
|
|
|
|
if xform.Filter != nil {
|
2017-04-04 12:09:26 +00:00
|
|
|
// Pre-populate the stream dictionary with the encoding related fields.
|
2017-03-01 16:02:53 +00:00
|
|
|
dict = xform.Filter.MakeStreamDict()
|
|
|
|
stream.PdfObjectDictionary = dict
|
|
|
|
}
|
|
|
|
dict.Set("Type", MakeName("XObject"))
|
|
|
|
dict.Set("Subtype", MakeName("Form"))
|
|
|
|
|
|
|
|
dict.SetIfNotNil("FormType", xform.FormType)
|
|
|
|
dict.SetIfNotNil("BBox", xform.BBox)
|
|
|
|
dict.SetIfNotNil("Matrix", xform.Matrix)
|
2017-04-04 12:09:26 +00:00
|
|
|
if xform.Resources != nil {
|
|
|
|
dict.SetIfNotNil("Resources", xform.Resources.ToPdfObject())
|
|
|
|
}
|
2017-03-01 16:02:53 +00:00
|
|
|
dict.SetIfNotNil("Group", xform.Group)
|
|
|
|
dict.SetIfNotNil("Ref", xform.Ref)
|
|
|
|
dict.SetIfNotNil("MetaData", xform.MetaData)
|
|
|
|
dict.SetIfNotNil("PieceInfo", xform.PieceInfo)
|
|
|
|
dict.SetIfNotNil("LastModified", xform.LastModified)
|
|
|
|
dict.SetIfNotNil("StructParent", xform.StructParent)
|
|
|
|
dict.SetIfNotNil("StructParents", xform.StructParents)
|
|
|
|
dict.SetIfNotNil("OPI", xform.OPI)
|
|
|
|
dict.SetIfNotNil("OC", xform.OC)
|
|
|
|
dict.SetIfNotNil("Name", xform.Name)
|
|
|
|
|
|
|
|
dict.Set("Length", MakeInteger(int64(len(xform.Stream))))
|
|
|
|
stream.Stream = xform.Stream
|
|
|
|
|
|
|
|
return stream
|
|
|
|
}
|
|
|
|
|
2017-02-22 21:10:57 +00:00
|
|
|
// XObjectImage (Table 89 in 8.9.5.1).
|
|
|
|
// Implements PdfModel interface.
|
|
|
|
type XObjectImage struct {
|
|
|
|
//ColorSpace PdfObject
|
|
|
|
Width *int64
|
|
|
|
Height *int64
|
|
|
|
ColorSpace PdfColorspace
|
|
|
|
BitsPerComponent *int64
|
2017-03-01 16:02:53 +00:00
|
|
|
Filter StreamEncoder
|
|
|
|
|
2017-02-24 17:38:41 +00:00
|
|
|
Intent PdfObject
|
|
|
|
ImageMask PdfObject
|
|
|
|
Mask PdfObject
|
|
|
|
Decode PdfObject
|
|
|
|
Interpolate PdfObject
|
|
|
|
Alternatives PdfObject
|
|
|
|
SMask PdfObject
|
|
|
|
SMaskInData PdfObject
|
|
|
|
Name PdfObject
|
|
|
|
StructParent PdfObject
|
|
|
|
ID PdfObject
|
|
|
|
OPI PdfObject
|
|
|
|
Metadata PdfObject
|
|
|
|
OC PdfObject
|
|
|
|
Stream []byte
|
2017-02-22 21:10:57 +00:00
|
|
|
// Primitive
|
|
|
|
primitive *PdfObjectStream
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewXObjectImage() *XObjectImage {
|
|
|
|
xobj := &XObjectImage{}
|
|
|
|
stream := &PdfObjectStream{}
|
|
|
|
stream.PdfObjectDictionary = &PdfObjectDictionary{}
|
|
|
|
xobj.primitive = stream
|
|
|
|
return xobj
|
|
|
|
}
|
|
|
|
|
2017-04-19 11:46:53 +00:00
|
|
|
// Creates a new XObject Image from an image object with default options.
|
|
|
|
// If encoder is nil, uses raw encoding (none).
|
|
|
|
func NewXObjectImageFromImage(name PdfObjectName, img *Image, cs PdfColorspace, encoder StreamEncoder) (*XObjectImage, error) {
|
2017-02-22 21:10:57 +00:00
|
|
|
xobj := NewXObjectImage()
|
|
|
|
|
2017-04-19 11:46:53 +00:00
|
|
|
if encoder == nil {
|
|
|
|
encoder = NewRawEncoder()
|
|
|
|
}
|
|
|
|
|
|
|
|
encoded, err := encoder.EncodeBytes(img.Data)
|
|
|
|
if err != nil {
|
|
|
|
common.Log.Debug("Error with encoding: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-02-22 21:10:57 +00:00
|
|
|
xobj.Name = &name
|
2017-04-19 11:46:53 +00:00
|
|
|
xobj.Filter = encoder
|
|
|
|
xobj.Stream = encoded
|
2017-02-22 21:10:57 +00:00
|
|
|
|
|
|
|
// Width and height.
|
|
|
|
imWidth := img.Width
|
|
|
|
imHeight := img.Height
|
|
|
|
xobj.Width = &imWidth
|
|
|
|
xobj.Height = &imHeight
|
|
|
|
|
|
|
|
// Bits.
|
|
|
|
xobj.BitsPerComponent = &img.BitsPerComponent
|
|
|
|
|
2017-03-14 13:04:51 +00:00
|
|
|
// Guess colorspace if not explicitly set.
|
|
|
|
if cs == nil {
|
|
|
|
if img.ColorComponents == 1 {
|
|
|
|
xobj.ColorSpace = NewPdfColorspaceDeviceGray()
|
|
|
|
} else if img.ColorComponents == 3 {
|
|
|
|
xobj.ColorSpace = NewPdfColorspaceDeviceRGB()
|
|
|
|
} else if img.ColorComponents == 4 {
|
|
|
|
xobj.ColorSpace = NewPdfColorspaceDeviceCMYK()
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("Colorspace undefined")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
xobj.ColorSpace = cs
|
2017-06-06 21:16:55 +00:00
|
|
|
}
|
2017-02-22 21:10:57 +00:00
|
|
|
|
2017-06-06 21:16:55 +00:00
|
|
|
if img.hasAlpha {
|
|
|
|
// Add the alpha channel information as a stencil mask (SMask).
|
|
|
|
// Has same width and height as original and stored in same
|
|
|
|
// bits per component (1 component, hence the DeviceGray channel).
|
|
|
|
smask := NewXObjectImage()
|
|
|
|
smask.Filter = encoder
|
|
|
|
encoded, err := encoder.EncodeBytes(img.alphaData)
|
|
|
|
if err != nil {
|
|
|
|
common.Log.Debug("Error with encoding: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
smask.Stream = encoded
|
|
|
|
smask.BitsPerComponent = &img.BitsPerComponent
|
|
|
|
smask.Width = &img.Width
|
|
|
|
smask.Height = &img.Height
|
|
|
|
smask.ColorSpace = NewPdfColorspaceDeviceGray()
|
|
|
|
xobj.SMask = smask.ToPdfObject()
|
2017-03-14 13:04:51 +00:00
|
|
|
}
|
2017-02-22 21:10:57 +00:00
|
|
|
|
|
|
|
return xobj, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the image xobject from a stream object.
|
|
|
|
// An image dictionary is the dictionary portion of a stream object representing an image XObject.
|
|
|
|
func NewXObjectImageFromStream(stream *PdfObjectStream) (*XObjectImage, error) {
|
|
|
|
img := &XObjectImage{}
|
|
|
|
img.primitive = stream
|
|
|
|
|
|
|
|
dict := *(stream.PdfObjectDictionary)
|
|
|
|
|
2017-02-24 17:38:41 +00:00
|
|
|
encoder, err := NewEncoderFromStream(stream)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2017-02-22 21:10:57 +00:00
|
|
|
}
|
2017-02-24 17:38:41 +00:00
|
|
|
img.Filter = encoder
|
2017-02-22 21:10:57 +00:00
|
|
|
|
|
|
|
if obj, isDefined := dict["Width"]; isDefined {
|
|
|
|
iObj, ok := obj.(*PdfObjectInteger)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("Invalid image width object")
|
|
|
|
}
|
|
|
|
iVal := int64(*iObj)
|
|
|
|
img.Width = &iVal
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("Width missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
if obj, isDefined := dict["Height"]; isDefined {
|
|
|
|
iObj, ok := obj.(*PdfObjectInteger)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("Invalid image height object")
|
|
|
|
}
|
|
|
|
iVal := int64(*iObj)
|
|
|
|
img.Height = &iVal
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("Height missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
if obj, isDefined := dict["ColorSpace"]; isDefined {
|
|
|
|
//img.ColorSpace = obj
|
|
|
|
cs, err := newPdfColorspaceFromPdfObject(obj)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
img.ColorSpace = cs
|
2017-03-05 22:41:38 +00:00
|
|
|
} else {
|
|
|
|
// If not specified, assume gray..
|
|
|
|
common.Log.Debug("XObject Image colorspace not specified - assuming 1 color component")
|
|
|
|
img.ColorSpace = NewPdfColorspaceDeviceGray()
|
2017-02-22 21:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if obj, isDefined := dict["BitsPerComponent"]; isDefined {
|
|
|
|
iObj, ok := obj.(*PdfObjectInteger)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("Invalid image height object")
|
|
|
|
}
|
|
|
|
iVal := int64(*iObj)
|
|
|
|
img.BitsPerComponent = &iVal
|
|
|
|
}
|
|
|
|
|
|
|
|
if obj, isDefined := dict["Intent"]; isDefined {
|
|
|
|
img.Intent = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["ImageMask"]; isDefined {
|
|
|
|
img.ImageMask = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Mask"]; isDefined {
|
|
|
|
img.Mask = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Decode"]; isDefined {
|
|
|
|
img.Decode = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Interpolate"]; isDefined {
|
|
|
|
img.Interpolate = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Alternatives"]; isDefined {
|
|
|
|
img.Alternatives = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["SMask"]; isDefined {
|
|
|
|
img.SMask = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["SMaskInData"]; isDefined {
|
|
|
|
img.SMaskInData = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Name"]; isDefined {
|
|
|
|
img.Name = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["StructParent"]; isDefined {
|
|
|
|
img.StructParent = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["ID"]; isDefined {
|
|
|
|
img.ID = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["OPI"]; isDefined {
|
|
|
|
img.OPI = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["Metadata"]; isDefined {
|
|
|
|
img.Metadata = obj
|
|
|
|
}
|
|
|
|
if obj, isDefined := dict["OC"]; isDefined {
|
|
|
|
img.OC = obj
|
|
|
|
}
|
|
|
|
|
|
|
|
img.Stream = stream.Stream
|
|
|
|
|
|
|
|
return img, nil
|
|
|
|
}
|
|
|
|
|
2017-03-14 13:04:51 +00:00
|
|
|
// Update XObject Image with new image data.
|
|
|
|
func (ximg *XObjectImage) SetImage(img *Image, cs PdfColorspace) error {
|
|
|
|
encoded, err := ximg.Filter.EncodeBytes(img.Data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
ximg.Stream = encoded
|
|
|
|
|
|
|
|
// Width, height and bits.
|
|
|
|
ximg.Width = &img.Width
|
|
|
|
ximg.Height = &img.Height
|
|
|
|
ximg.BitsPerComponent = &img.BitsPerComponent
|
|
|
|
|
|
|
|
// Guess colorspace if not explicitly set.
|
|
|
|
if cs == nil {
|
|
|
|
if img.ColorComponents == 1 {
|
|
|
|
ximg.ColorSpace = NewPdfColorspaceDeviceGray()
|
|
|
|
} else if img.ColorComponents == 3 {
|
|
|
|
ximg.ColorSpace = NewPdfColorspaceDeviceRGB()
|
|
|
|
} else if img.ColorComponents == 4 {
|
|
|
|
ximg.ColorSpace = NewPdfColorspaceDeviceCMYK()
|
|
|
|
} else {
|
|
|
|
return errors.New("Colorspace undefined")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ximg.ColorSpace = cs
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-04-19 11:46:53 +00:00
|
|
|
// Set compression filter. Decodes with current filter sets and encodes the data with the new filter.
|
|
|
|
func (ximg *XObjectImage) SetFilter(encoder StreamEncoder) error {
|
|
|
|
encoded := ximg.Stream
|
|
|
|
decoded, err := ximg.Filter.DecodeBytes(encoded)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
ximg.Filter = encoder
|
|
|
|
encoded, err = encoder.EncodeBytes(decoded)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
ximg.Stream = encoded
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-03-08 16:52:37 +00:00
|
|
|
// Compress with default settings, updating the underlying stream also.
|
|
|
|
// XXX/TODO: Add flate encoding as an option (although lossy). Need to be able
|
|
|
|
// to set default settings and override.
|
|
|
|
func (ximg *XObjectImage) Compress() error {
|
|
|
|
if ximg.Filter != nil {
|
|
|
|
common.Log.Error("XImage already compressed...")
|
|
|
|
return errors.New("Already compressed")
|
|
|
|
}
|
|
|
|
//encoder := NewFlateEncoder()
|
|
|
|
//encoder.SetPredictor(int(*ximg.Width))
|
|
|
|
encoder := NewDCTEncoder()
|
|
|
|
encoder.ColorComponents = ximg.ColorSpace.GetNumComponents()
|
|
|
|
encoder.Height = int(*ximg.Height)
|
|
|
|
encoder.Width = int(*ximg.Width)
|
|
|
|
encoder.BitsPerComponent = int(*ximg.BitsPerComponent)
|
|
|
|
ximg.Filter = encoder
|
|
|
|
|
|
|
|
encoded, err := ximg.Filter.EncodeBytes(ximg.Stream)
|
|
|
|
if err != nil {
|
|
|
|
common.Log.Debug("Error encoding: %v\n", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ximg.Stream = encoded
|
|
|
|
|
|
|
|
_ = ximg.ToPdfObject()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-22 21:10:57 +00:00
|
|
|
// This will convert to an Image which can be transformed or saved out.
|
2017-02-24 17:38:41 +00:00
|
|
|
// The image data is decoded and the Image returned.
|
2017-02-22 21:10:57 +00:00
|
|
|
func (ximg *XObjectImage) ToImage() (*Image, error) {
|
|
|
|
image := &Image{}
|
|
|
|
|
|
|
|
if ximg.Height == nil {
|
|
|
|
return nil, errors.New("Height attribute missing")
|
|
|
|
}
|
|
|
|
image.Height = *ximg.Height
|
|
|
|
|
|
|
|
if ximg.Width == nil {
|
|
|
|
return nil, errors.New("Width attribute missing")
|
|
|
|
}
|
|
|
|
image.Width = *ximg.Width
|
|
|
|
|
|
|
|
if ximg.BitsPerComponent == nil {
|
|
|
|
return nil, errors.New("Bits per component missing")
|
|
|
|
}
|
|
|
|
image.BitsPerComponent = *ximg.BitsPerComponent
|
|
|
|
|
2017-03-05 22:41:38 +00:00
|
|
|
image.ColorComponents = ximg.ColorSpace.GetNumComponents()
|
2017-03-04 17:27:23 +00:00
|
|
|
|
2017-02-22 21:10:57 +00:00
|
|
|
decoded, err := DecodeStream(ximg.primitive)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
image.Data = decoded
|
|
|
|
|
2017-03-05 22:41:38 +00:00
|
|
|
if ximg.Decode != nil {
|
|
|
|
darr, ok := ximg.Decode.(*PdfObjectArray)
|
|
|
|
if !ok {
|
|
|
|
common.Log.Debug("Invalid Decode object")
|
|
|
|
return nil, errors.New("Invalid type")
|
|
|
|
}
|
|
|
|
decode, err := darr.ToFloat64Array()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
image.decode = decode
|
|
|
|
}
|
|
|
|
|
2017-02-24 17:38:41 +00:00
|
|
|
return image, nil
|
2017-02-22 21:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ximg *XObjectImage) GetContainingPdfObject() PdfObject {
|
|
|
|
return ximg.primitive
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return a stream object.
|
|
|
|
func (ximg *XObjectImage) ToPdfObject() PdfObject {
|
|
|
|
stream := ximg.primitive
|
|
|
|
|
|
|
|
dict := stream.PdfObjectDictionary
|
2017-02-24 17:38:41 +00:00
|
|
|
if ximg.Filter != nil {
|
|
|
|
//dict.Set("Filter", ximg.Filter)
|
|
|
|
// Pre-populate the stream dictionary with the
|
|
|
|
// encoding related fields.
|
|
|
|
dict = ximg.Filter.MakeStreamDict()
|
|
|
|
stream.PdfObjectDictionary = dict
|
|
|
|
}
|
2017-02-22 21:10:57 +00:00
|
|
|
dict.Set("Type", MakeName("XObject"))
|
|
|
|
dict.Set("Subtype", MakeName("Image"))
|
|
|
|
dict.Set("Width", MakeInteger(*(ximg.Width)))
|
|
|
|
dict.Set("Height", MakeInteger(*(ximg.Height)))
|
|
|
|
|
|
|
|
if ximg.BitsPerComponent != nil {
|
|
|
|
dict.Set("BitsPerComponent", MakeInteger(*(ximg.BitsPerComponent)))
|
|
|
|
}
|
|
|
|
|
|
|
|
if ximg.ColorSpace != nil {
|
|
|
|
dict.SetIfNotNil("ColorSpace", ximg.ColorSpace.ToPdfObject())
|
|
|
|
}
|
|
|
|
dict.SetIfNotNil("Intent", ximg.Intent)
|
|
|
|
dict.SetIfNotNil("ImageMask", ximg.ImageMask)
|
|
|
|
dict.SetIfNotNil("Mask", ximg.Mask)
|
|
|
|
dict.SetIfNotNil("Decode", ximg.Decode)
|
|
|
|
dict.SetIfNotNil("Interpolate", ximg.Interpolate)
|
|
|
|
dict.SetIfNotNil("Alternatives", ximg.Alternatives)
|
|
|
|
dict.SetIfNotNil("SMask", ximg.SMask)
|
|
|
|
dict.SetIfNotNil("SMaskInData", ximg.SMaskInData)
|
|
|
|
dict.SetIfNotNil("Name", ximg.Name)
|
|
|
|
dict.SetIfNotNil("StructParent", ximg.StructParent)
|
|
|
|
dict.SetIfNotNil("ID", ximg.ID)
|
|
|
|
dict.SetIfNotNil("OPI", ximg.OPI)
|
|
|
|
dict.SetIfNotNil("Metadata", ximg.Metadata)
|
|
|
|
dict.SetIfNotNil("OC", ximg.OC)
|
|
|
|
|
|
|
|
dict.Set("Length", MakeInteger(int64(len(ximg.Stream))))
|
|
|
|
stream.Stream = ximg.Stream
|
|
|
|
|
|
|
|
return stream
|
|
|
|
}
|