fix wrong git ignore
This commit is contained in:
588
internal/pdf/model/xobject.go
Normal file
588
internal/pdf/model/xobject.go
Normal file
@@ -0,0 +1,588 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
|
||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/core"
|
||||
)
|
||||
|
||||
// XObjectForm (Table 95 in 8.10.2).
|
||||
type XObjectForm struct {
|
||||
Filter core.StreamEncoder
|
||||
|
||||
FormType core.PdfObject
|
||||
BBox core.PdfObject
|
||||
Matrix core.PdfObject
|
||||
Resources *PdfPageResources
|
||||
Group core.PdfObject
|
||||
Ref core.PdfObject
|
||||
MetaData core.PdfObject
|
||||
PieceInfo core.PdfObject
|
||||
LastModified core.PdfObject
|
||||
StructParent core.PdfObject
|
||||
StructParents core.PdfObject
|
||||
OPI core.PdfObject
|
||||
OC core.PdfObject
|
||||
Name core.PdfObject
|
||||
|
||||
// Stream data.
|
||||
Stream []byte
|
||||
// Primitive
|
||||
primitive *core.PdfObjectStream
|
||||
}
|
||||
|
||||
var ErrTypeCheck = errors.New("type check error")
|
||||
|
||||
// Create a brand new XObject Form. Creates a new underlying PDF object stream primitive.
|
||||
func NewXObjectForm() *XObjectForm {
|
||||
xobj := &XObjectForm{}
|
||||
stream := &core.PdfObjectStream{}
|
||||
stream.PdfObjectDictionary = core.MakeDict()
|
||||
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 *core.PdfObjectStream) (*XObjectForm, error) {
|
||||
form := &XObjectForm{}
|
||||
form.primitive = stream
|
||||
|
||||
dict := *(stream.PdfObjectDictionary)
|
||||
|
||||
encoder, err := core.NewEncoderFromStream(stream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
form.Filter = encoder
|
||||
|
||||
if obj := dict.Get("Subtype"); obj != nil {
|
||||
name, ok := obj.(*core.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 := dict.Get("FormType"); obj != nil {
|
||||
form.FormType = obj
|
||||
}
|
||||
if obj := dict.Get("BBox"); obj != nil {
|
||||
form.BBox = obj
|
||||
}
|
||||
if obj := dict.Get("Matrix"); obj != nil {
|
||||
form.Matrix = obj
|
||||
}
|
||||
if obj := dict.Get("Resources"); obj != nil {
|
||||
obj = core.TraceToDirectObject(obj)
|
||||
d, ok := obj.(*core.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
|
||||
}
|
||||
form.Resources = res
|
||||
common.Log.Trace("Form resources: %#v", form.Resources)
|
||||
}
|
||||
|
||||
form.Group = dict.Get("Group")
|
||||
form.Ref = dict.Get("Ref")
|
||||
form.MetaData = dict.Get("MetaData")
|
||||
form.PieceInfo = dict.Get("PieceInfo")
|
||||
form.LastModified = dict.Get("LastModified")
|
||||
form.StructParent = dict.Get("StructParent")
|
||||
form.StructParents = dict.Get("StructParents")
|
||||
form.OPI = dict.Get("OPI")
|
||||
form.OC = dict.Get("OC")
|
||||
form.Name = dict.Get("Name")
|
||||
|
||||
form.Stream = stream.Stream
|
||||
|
||||
return form, nil
|
||||
}
|
||||
|
||||
func (xform *XObjectForm) GetContainingPdfObject() core.PdfObject {
|
||||
return xform.primitive
|
||||
}
|
||||
|
||||
func (xform *XObjectForm) GetContentStream() ([]byte, error) {
|
||||
decoded, err := core.DecodeStream(xform.primitive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decoded, nil
|
||||
}
|
||||
|
||||
// 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 core.StreamEncoder) error {
|
||||
encoded := content
|
||||
|
||||
if encoder == nil {
|
||||
if xform.Filter != nil {
|
||||
encoder = xform.Filter
|
||||
} else {
|
||||
encoder = core.NewRawEncoder()
|
||||
}
|
||||
}
|
||||
|
||||
enc, err := encoder.EncodeBytes(encoded)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoded = enc
|
||||
|
||||
xform.Stream = encoded
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return a stream object.
|
||||
func (xform *XObjectForm) ToPdfObject() core.PdfObject {
|
||||
stream := xform.primitive
|
||||
|
||||
dict := stream.PdfObjectDictionary
|
||||
if xform.Filter != nil {
|
||||
// Pre-populate the stream dictionary with the encoding related fields.
|
||||
dict = xform.Filter.MakeStreamDict()
|
||||
stream.PdfObjectDictionary = dict
|
||||
}
|
||||
dict.Set("Type", core.MakeName("XObject"))
|
||||
dict.Set("Subtype", core.MakeName("Form"))
|
||||
|
||||
dict.SetIfNotNil("FormType", xform.FormType)
|
||||
dict.SetIfNotNil("BBox", xform.BBox)
|
||||
dict.SetIfNotNil("Matrix", xform.Matrix)
|
||||
if xform.Resources != nil {
|
||||
dict.SetIfNotNil("Resources", xform.Resources.ToPdfObject())
|
||||
}
|
||||
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", core.MakeInteger(int64(len(xform.Stream))))
|
||||
stream.Stream = xform.Stream
|
||||
|
||||
return stream
|
||||
}
|
||||
|
||||
// XObjectImage (Table 89 in 8.9.5.1).
|
||||
// Implements PdfModel interface.
|
||||
type XObjectImage struct {
|
||||
//ColorSpace PdfObject
|
||||
Width *int64
|
||||
Height *int64
|
||||
ColorSpace PdfColorspace
|
||||
BitsPerComponent *int64
|
||||
Filter core.StreamEncoder
|
||||
|
||||
Intent core.PdfObject
|
||||
ImageMask core.PdfObject
|
||||
Mask core.PdfObject
|
||||
Matte core.PdfObject
|
||||
Decode core.PdfObject
|
||||
Interpolate core.PdfObject
|
||||
Alternatives core.PdfObject
|
||||
SMask core.PdfObject
|
||||
SMaskInData core.PdfObject
|
||||
Name core.PdfObject // Obsolete. Currently read if available and write if available. Not setting on new created files.
|
||||
StructParent core.PdfObject
|
||||
ID core.PdfObject
|
||||
OPI core.PdfObject
|
||||
Metadata core.PdfObject
|
||||
OC core.PdfObject
|
||||
Stream []byte
|
||||
// Primitive
|
||||
primitive *core.PdfObjectStream
|
||||
}
|
||||
|
||||
func NewXObjectImage() *XObjectImage {
|
||||
xobj := &XObjectImage{}
|
||||
stream := &core.PdfObjectStream{}
|
||||
stream.PdfObjectDictionary = core.MakeDict()
|
||||
xobj.primitive = stream
|
||||
return xobj
|
||||
}
|
||||
|
||||
// Creates a new XObject Image from an image object with default options.
|
||||
// If encoder is nil, uses raw encoding (none).
|
||||
func NewXObjectImageFromImage(img *Image, cs PdfColorspace, encoder core.StreamEncoder) (*XObjectImage, error) {
|
||||
xobj := NewXObjectImage()
|
||||
return UpdateXObjectImageFromImage(xobj, img, cs, encoder)
|
||||
}
|
||||
|
||||
// UpdateXObjectImageFromImage creates a new XObject Image from an Image object `img` and default
|
||||
//
|
||||
// masks from xobjIn.
|
||||
//
|
||||
// The default masks are overriden if img.hasAlpha
|
||||
// If `encoder` is nil, uses raw encoding (none).
|
||||
func UpdateXObjectImageFromImage(xobjIn *XObjectImage, img *Image, cs PdfColorspace,
|
||||
encoder core.StreamEncoder) (*XObjectImage, error) {
|
||||
xobj := NewXObjectImage()
|
||||
|
||||
if encoder == nil {
|
||||
encoder = core.NewRawEncoder()
|
||||
}
|
||||
|
||||
encoded, err := encoder.EncodeBytes(img.Data)
|
||||
if err != nil {
|
||||
common.Log.Debug("error with encoding: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xobj.Filter = encoder
|
||||
xobj.Stream = encoded
|
||||
|
||||
// Width and height.
|
||||
imWidth := img.Width
|
||||
imHeight := img.Height
|
||||
xobj.Width = &imWidth
|
||||
xobj.Height = &imHeight
|
||||
|
||||
// Bits.
|
||||
xobj.BitsPerComponent = &img.BitsPerComponent
|
||||
|
||||
// Guess colorspace if not explicitly set.
|
||||
if cs == nil {
|
||||
switch img.ColorComponents {
|
||||
case 1:
|
||||
xobj.ColorSpace = NewPdfColorspaceDeviceGray()
|
||||
case 3:
|
||||
xobj.ColorSpace = NewPdfColorspaceDeviceRGB()
|
||||
case 4:
|
||||
xobj.ColorSpace = NewPdfColorspaceDeviceCMYK()
|
||||
default:
|
||||
return nil, errors.New("colorspace undefined")
|
||||
}
|
||||
} else {
|
||||
xobj.ColorSpace = cs
|
||||
}
|
||||
|
||||
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()
|
||||
} else {
|
||||
xobj.SMask = xobjIn.SMask
|
||||
xobj.ImageMask = xobjIn.ImageMask
|
||||
if xobj.ColorSpace.GetNumComponents() == 1 {
|
||||
smaskMatteToGray(xobj)
|
||||
}
|
||||
}
|
||||
|
||||
return xobj, nil
|
||||
}
|
||||
|
||||
// smaskMatteToGray converts to gray the Matte value in the SMask image referenced by `xobj` (if
|
||||
// there is one)
|
||||
func smaskMatteToGray(xobj *XObjectImage) error {
|
||||
if xobj.SMask == nil {
|
||||
return nil
|
||||
}
|
||||
stream, ok := xobj.SMask.(*core.PdfObjectStream)
|
||||
if !ok {
|
||||
common.Log.Debug("SMask is not *PdfObjectStream")
|
||||
return ErrTypeCheck
|
||||
}
|
||||
dict := stream.PdfObjectDictionary
|
||||
matte := dict.Get("Matte")
|
||||
if matte == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
gray, err := toGray(matte.(*core.PdfObjectArray))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
grayMatte := core.MakeArrayFromFloats([]float64{gray})
|
||||
dict.SetIfNotNil("Matte", grayMatte)
|
||||
return nil
|
||||
}
|
||||
|
||||
// toGray converts a 1, 3 or 4 dimensional color `matte` to gray
|
||||
// If `matte` is not a 1, 3 or 4 dimensional color then an error is returned
|
||||
func toGray(matte *core.PdfObjectArray) (float64, error) {
|
||||
colors, err := matte.ToFloat64Array()
|
||||
if err != nil {
|
||||
common.Log.Debug("Bad Matte array: matte=%s err=%v", matte, err)
|
||||
}
|
||||
switch len(colors) {
|
||||
case 1:
|
||||
return colors[0], nil
|
||||
case 3:
|
||||
cs := PdfColorspaceDeviceRGB{}
|
||||
rgbColor, err := cs.ColorFromFloats(colors)
|
||||
if err != nil {
|
||||
return 0.0, err
|
||||
}
|
||||
return rgbColor.(*PdfColorDeviceRGB).ToGray().Val(), nil
|
||||
|
||||
case 4:
|
||||
cs := PdfColorspaceDeviceCMYK{}
|
||||
cmykColor, err := cs.ColorFromFloats(colors)
|
||||
if err != nil {
|
||||
return 0.0, err
|
||||
}
|
||||
rgbColor, err := cs.ColorToRGB(cmykColor.(*PdfColorDeviceCMYK))
|
||||
if err != nil {
|
||||
return 0.0, err
|
||||
}
|
||||
return rgbColor.(*PdfColorDeviceRGB).ToGray().Val(), nil
|
||||
}
|
||||
err = errors.New("bad Matte color")
|
||||
common.Log.Error("toGray: matte=%s err=%v", matte, err)
|
||||
return 0.0, err
|
||||
}
|
||||
|
||||
// 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 *core.PdfObjectStream) (*XObjectImage, error) {
|
||||
img := &XObjectImage{}
|
||||
img.primitive = stream
|
||||
|
||||
dict := *(stream.PdfObjectDictionary)
|
||||
|
||||
encoder, err := core.NewEncoderFromStream(stream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.Filter = encoder
|
||||
|
||||
if obj := core.TraceToDirectObject(dict.Get("Width")); obj != nil {
|
||||
iObj, ok := obj.(*core.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 := core.TraceToDirectObject(dict.Get("Height")); obj != nil {
|
||||
iObj, ok := obj.(*core.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 := core.TraceToDirectObject(dict.Get("ColorSpace")); obj != nil {
|
||||
cs, err := NewPdfColorspaceFromPdfObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img.ColorSpace = cs
|
||||
} else {
|
||||
// If not specified, assume gray..
|
||||
common.Log.Debug("XObject Image colorspace not specified - assuming 1 color component")
|
||||
img.ColorSpace = NewPdfColorspaceDeviceGray()
|
||||
}
|
||||
|
||||
if obj := core.TraceToDirectObject(dict.Get("BitsPerComponent")); obj != nil {
|
||||
iObj, ok := obj.(*core.PdfObjectInteger)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid image height object")
|
||||
}
|
||||
iVal := int64(*iObj)
|
||||
img.BitsPerComponent = &iVal
|
||||
}
|
||||
|
||||
img.Intent = dict.Get("Intent")
|
||||
img.ImageMask = dict.Get("ImageMask")
|
||||
img.Mask = dict.Get("Mask")
|
||||
img.Decode = dict.Get("Decode")
|
||||
img.Interpolate = dict.Get("Interpolate")
|
||||
img.Alternatives = dict.Get("Alternatives")
|
||||
img.SMask = dict.Get("SMask")
|
||||
img.SMaskInData = dict.Get("SMaskInData")
|
||||
img.Matte = dict.Get("Matte")
|
||||
img.Name = dict.Get("Name")
|
||||
img.StructParent = dict.Get("StructParent")
|
||||
img.ID = dict.Get("ID")
|
||||
img.OPI = dict.Get("OPI")
|
||||
img.Metadata = dict.Get("Metadata")
|
||||
img.OC = dict.Get("OC")
|
||||
|
||||
img.Stream = stream.Stream
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
switch img.ColorComponents {
|
||||
case 1:
|
||||
ximg.ColorSpace = NewPdfColorspaceDeviceGray()
|
||||
case 3:
|
||||
ximg.ColorSpace = NewPdfColorspaceDeviceRGB()
|
||||
case 4:
|
||||
ximg.ColorSpace = NewPdfColorspaceDeviceCMYK()
|
||||
default:
|
||||
return errors.New("colorspace undefined")
|
||||
}
|
||||
} else {
|
||||
ximg.ColorSpace = cs
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set compression filter. Decodes with current filter sets and encodes the data with the new filter.
|
||||
func (ximg *XObjectImage) SetFilter(encoder core.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
|
||||
}
|
||||
|
||||
// This will convert to an Image which can be transformed or saved out.
|
||||
// The image data is decoded and the Image returned.
|
||||
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
|
||||
|
||||
image.ColorComponents = ximg.ColorSpace.GetNumComponents()
|
||||
|
||||
decoded, err := core.DecodeStream(ximg.primitive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
image.Data = decoded
|
||||
|
||||
if ximg.Decode != nil {
|
||||
darr, ok := ximg.Decode.(*core.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
|
||||
}
|
||||
|
||||
return image, nil
|
||||
}
|
||||
|
||||
func (ximg *XObjectImage) GetContainingPdfObject() core.PdfObject {
|
||||
return ximg.primitive
|
||||
}
|
||||
|
||||
// Return a stream object.
|
||||
func (ximg *XObjectImage) ToPdfObject() core.PdfObject {
|
||||
stream := ximg.primitive
|
||||
|
||||
dict := stream.PdfObjectDictionary
|
||||
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
|
||||
}
|
||||
dict.Set("Type", core.MakeName("XObject"))
|
||||
dict.Set("Subtype", core.MakeName("Image"))
|
||||
dict.Set("Width", core.MakeInteger(*(ximg.Width)))
|
||||
dict.Set("Height", core.MakeInteger(*(ximg.Height)))
|
||||
|
||||
if ximg.BitsPerComponent != nil {
|
||||
dict.Set("BitsPerComponent", core.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("Matte", ximg.Matte)
|
||||
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", core.MakeInteger(int64(len(ximg.Stream))))
|
||||
stream.Stream = ximg.Stream
|
||||
|
||||
return stream
|
||||
}
|
||||
Reference in New Issue
Block a user