Merge branch 'v3' into v3-integration-testing

This commit is contained in:
Gunnsteinn Hall 2019-01-25 16:47:12 +00:00 committed by GitHub
commit 24dbf33807
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 179 additions and 12 deletions

View File

@ -57,6 +57,7 @@ type StreamEncoder interface {
GetFilterName() string
MakeDecodeParams() PdfObject
MakeStreamDict() *PdfObjectDictionary
UpdateParams(params *PdfObjectDictionary)
EncodeBytes(data []byte) ([]byte, error)
DecodeBytes(encoded []byte) ([]byte, error)
@ -136,6 +137,29 @@ func (enc *FlateEncoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *FlateEncoder) UpdateParams(params *PdfObjectDictionary) {
predictor, err := GetNumberAsInt64(params.Get("Predictor"))
if err == nil {
enc.Predictor = int(predictor)
}
bpc, err := GetNumberAsInt64(params.Get("BitsPerComponent"))
if err == nil {
enc.BitsPerComponent = int(bpc)
}
columns, err := GetNumberAsInt64(params.Get("Width"))
if err == nil {
enc.Columns = int(columns)
}
colorComponents, err := GetNumberAsInt64(params.Get("ColorComponents"))
if err == nil {
enc.Colors = int(colorComponents)
}
}
// Create a new flate decoder from a stream object, getting all the encoding parameters
// from the DecodeParms stream object dictionary entry.
func newFlateEncoderFromStream(streamObj *PdfObjectStream, decodeParams *PdfObjectDictionary) (*FlateEncoder, error) {
@ -507,6 +531,34 @@ func (enc *LZWEncoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *LZWEncoder) UpdateParams(params *PdfObjectDictionary) {
predictor, err := GetNumberAsInt64(params.Get("Predictor"))
if err == nil {
enc.Predictor = int(predictor)
}
bpc, err := GetNumberAsInt64(params.Get("BitsPerComponent"))
if err == nil {
enc.BitsPerComponent = int(bpc)
}
columns, err := GetNumberAsInt64(params.Get("Width"))
if err == nil {
enc.Columns = int(columns)
}
colorComponents, err := GetNumberAsInt64(params.Get("ColorComponents"))
if err == nil {
enc.Colors = int(colorComponents)
}
earlyChange, err := GetNumberAsInt64(params.Get("EarlyChange"))
if err == nil {
enc.EarlyChange = int(earlyChange)
}
}
// Create a new LZW encoder/decoder from a stream object, getting all the encoding parameters
// from the DecodeParms stream object dictionary entry.
func newLZWEncoderFromStream(streamObj *PdfObjectStream, decodeParams *PdfObjectDictionary) (*LZWEncoder, error) {
@ -824,6 +876,34 @@ func (enc *DCTEncoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *DCTEncoder) UpdateParams(params *PdfObjectDictionary) {
colorComponents, err := GetNumberAsInt64(params.Get("ColorComponents"))
if err == nil {
enc.ColorComponents = int(colorComponents)
}
bpc, err := GetNumberAsInt64(params.Get("BitsPerComponent"))
if err == nil {
enc.BitsPerComponent = int(bpc)
}
width, err := GetNumberAsInt64(params.Get("Width"))
if err == nil {
enc.Width = int(width)
}
height, err := GetNumberAsInt64(params.Get("Height"))
if err == nil {
enc.Height = int(height)
}
quality, err := GetNumberAsInt64(params.Get("Quality"))
if err == nil {
enc.Quality = int(quality)
}
}
// Create a new DCT encoder/decoder from a stream object, getting all the encoding parameters
// from the stream object dictionary entry and the image data itself.
// TODO: Support if used with other filters [ASCII85Decode FlateDecode DCTDecode]...
@ -1037,9 +1117,17 @@ func (enc *DCTEncoder) EncodeBytes(data []byte) ([]byte, error) {
}
// Draw the data on the image..
if enc.BitsPerComponent < 8 {
enc.BitsPerComponent = 8
}
bytesPerColor := enc.ColorComponents * enc.BitsPerComponent / 8
if bytesPerColor < 1 {
bytesPerColor = 1
}
x := 0
y := 0
bytesPerColor := enc.ColorComponents * enc.BitsPerComponent / 8
for i := 0; i+bytesPerColor-1 < len(data); i += bytesPerColor {
var c gocolor.Color
if enc.ColorComponents == 1 {
@ -1238,6 +1326,10 @@ func (enc *RunLengthEncoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *RunLengthEncoder) UpdateParams(params *PdfObjectDictionary) {
}
// ASCIIHexEncoder implements ASCII hex encoder/decoder.
type ASCIIHexEncoder struct {
}
@ -1263,6 +1355,10 @@ func (enc *ASCIIHexEncoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *ASCIIHexEncoder) UpdateParams(params *PdfObjectDictionary) {
}
func (enc *ASCIIHexEncoder) DecodeBytes(encoded []byte) ([]byte, error) {
bufReader := bytes.NewReader(encoded)
var inb []byte
@ -1337,6 +1433,10 @@ func (enc *ASCII85Encoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *ASCII85Encoder) UpdateParams(params *PdfObjectDictionary) {
}
// DecodeBytes decodes byte array with ASCII85. 5 ASCII characters -> 4 raw binary bytes
func (enc *ASCII85Encoder) DecodeBytes(encoded []byte) ([]byte, error) {
var decoded []byte
@ -1502,6 +1602,10 @@ func (enc *RawEncoder) MakeStreamDict() *PdfObjectDictionary {
return MakeDict()
}
// UpdateParams updates the parameter values of the encoder.
func (enc *RawEncoder) UpdateParams(params *PdfObjectDictionary) {
}
func (enc *RawEncoder) DecodeBytes(encoded []byte) ([]byte, error) {
return encoded, nil
}
@ -1535,6 +1639,10 @@ func (enc *CCITTFaxEncoder) MakeStreamDict() *PdfObjectDictionary {
return MakeDict()
}
// UpdateParams updates the parameter values of the encoder.
func (enc *CCITTFaxEncoder) UpdateParams(params *PdfObjectDictionary) {
}
func (enc *CCITTFaxEncoder) DecodeBytes(encoded []byte) ([]byte, error) {
common.Log.Debug("Error: Attempting to use unsupported encoding %s", enc.GetFilterName())
return encoded, ErrNoCCITTFaxDecode
@ -1571,6 +1679,10 @@ func (enc *JBIG2Encoder) MakeStreamDict() *PdfObjectDictionary {
return MakeDict()
}
// UpdateParams updates the parameter values of the encoder.
func (enc *JBIG2Encoder) UpdateParams(params *PdfObjectDictionary) {
}
func (enc *JBIG2Encoder) DecodeBytes(encoded []byte) ([]byte, error) {
common.Log.Debug("Error: Attempting to use unsupported encoding %s", enc.GetFilterName())
return encoded, ErrNoJBIG2Decode
@ -1607,6 +1719,10 @@ func (enc *JPXEncoder) MakeStreamDict() *PdfObjectDictionary {
return MakeDict()
}
// UpdateParams updates the parameter values of the encoder.
func (enc *JPXEncoder) UpdateParams(params *PdfObjectDictionary) {
}
func (enc *JPXEncoder) DecodeBytes(encoded []byte) ([]byte, error) {
common.Log.Debug("Error: Attempting to use unsupported encoding %s", enc.GetFilterName())
return encoded, ErrNoJPXDecode
@ -1805,6 +1921,13 @@ func (enc *MultiEncoder) MakeStreamDict() *PdfObjectDictionary {
return dict
}
// UpdateParams updates the parameter values of the encoder.
func (enc *MultiEncoder) UpdateParams(params *PdfObjectDictionary) {
for _, encoder := range enc.encoders {
encoder.UpdateParams(params)
}
}
func (enc *MultiEncoder) DecodeBytes(encoded []byte) ([]byte, error) {
decoded := encoded
var err error

View File

@ -300,7 +300,7 @@ func (cs *PdfColorspaceDeviceGray) ImageToRGB(img Image) (Image, error) {
var rgbSamples []uint32
for i := 0; i < len(samples); i++ {
grayVal := samples[i]
grayVal := samples[i] * 255 / uint32(math.Pow(2, float64(img.BitsPerComponent))-1)
rgbSamples = append(rgbSamples, grayVal, grayVal, grayVal)
}
rgbImage.BitsPerComponent = 8

View File

@ -13,6 +13,7 @@ import (
_ "image/gif"
_ "image/png"
"io"
"math"
"github.com/unidoc/unidoc/common"
. "github.com/unidoc/unidoc/pdf/core"
@ -170,8 +171,8 @@ func (img *Image) ToGoImage() (goimage.Image, error) {
val := uint16(samples[i])<<8 | uint16(samples[i+1])
c = gocolor.Gray16{val}
} else {
val := uint8(samples[i] & 0xff)
c = gocolor.Gray{val}
val := samples[i] * 255 / uint32(math.Pow(2, float64(img.BitsPerComponent))-1)
c = gocolor.Gray{uint8(val & 0xff)}
}
} else if img.ColorComponents == 3 {
if img.BitsPerComponent == 16 {
@ -221,9 +222,12 @@ type ImageHandler interface {
// Read any image type and load into a new Image object.
Read(r io.Reader) (*Image, error)
// NewImageFromGoImage load a unidoc Image from a standard Go image structure.
// NewImageFromGoImage loads a RGBA unidoc Image from a standard Go image structure.
NewImageFromGoImage(goimg goimage.Image) (*Image, error)
// NewGrayImageFromGoImage loads a grayscale unidoc Image from a standard Go image structure.
NewGrayImageFromGoImage(goimg goimage.Image) (*Image, error)
// Compress an image.
Compress(input *Image, quality int64) (*Image, error)
}
@ -231,7 +235,7 @@ type ImageHandler interface {
// DefaultImageHandler is the default implementation of the ImageHandler using the standard go library.
type DefaultImageHandler struct{}
// NewImageFromGoImage creates a unidoc Image from a golang Image.
// NewImageFromGoImage creates a new RGBA unidoc Image from a golang Image.
func (ih DefaultImageHandler) NewImageFromGoImage(goimg goimage.Image) (*Image, error) {
// Speed up jpeg encoding by converting to RGBA first.
// Will not be required once the golang image/jpeg package is optimized.
@ -269,6 +273,21 @@ func (ih DefaultImageHandler) NewImageFromGoImage(goimg goimage.Image) (*Image,
return &imag, nil
}
// NewGrayImageFromGoImage creates a new grayscale unidoc Image from a golang Image.
func (ih DefaultImageHandler) NewGrayImageFromGoImage(goimg goimage.Image) (*Image, error) {
b := goimg.Bounds()
m := goimage.NewGray(b)
draw.Draw(m, b, goimg, b.Min, draw.Src)
return &Image{
Width: int64(b.Dx()),
Height: int64(b.Dy()),
BitsPerComponent: 8,
ColorComponents: 1,
Data: m.Pix,
}, nil
}
// Read reads an image and loads into a new Image object with an RGB
// colormap and 8 bits per component.
func (ih DefaultImageHandler) Read(reader io.Reader) (*Image, error) {

View File

@ -41,21 +41,41 @@ func scaleImage(stream *core.PdfObjectStream, scale float64) error {
newW := int(math.RoundToEven(float64(i.Width) * scale))
newH := int(math.RoundToEven(float64(i.Height) * scale))
rect := image.Rect(0, 0, newW, newH)
var newImage draw.Image
var imageHandler func(image.Image) (*model.Image, error)
switch xImg.ColorSpace.String() {
case "DeviceRGB":
newImage = image.NewRGBA(rect)
imageHandler = model.ImageHandling.NewImageFromGoImage
case "DeviceGray":
newImage = image.NewGray(rect)
imageHandler = model.ImageHandling.NewGrayImageFromGoImage
default:
return fmt.Errorf("optimization is not supported for color space %s", xImg.ColorSpace.String())
}
draw.CatmullRom.Scale(newImage, newImage.Bounds(), goimg, goimg.Bounds(), draw.Over, &draw.Options{})
i, err = model.ImageHandling.NewImageFromGoImage(newImage)
if err != nil {
if i, err = imageHandler(newImage); err != nil {
return err
}
// Update image encoder
encoderParams := core.MakeDict()
encoderParams.Set("ColorComponents", core.MakeInteger(int64(i.ColorComponents)))
encoderParams.Set("BitsPerComponent", core.MakeInteger(i.BitsPerComponent))
encoderParams.Set("Width", core.MakeInteger(i.Width))
encoderParams.Set("Height", core.MakeInteger(i.Height))
encoderParams.Set("Quality", core.MakeInteger(100))
encoderParams.Set("Predictor", core.MakeInteger(1))
xImg.Filter.UpdateParams(encoderParams)
// Update image
if err := xImg.SetImage(i, nil); err != nil {
return err
}
xImg.SetImage(i, xImg.ColorSpace)
xImg.ToPdfObject()
return nil
}

View File

@ -455,9 +455,14 @@ func (ximg *XObjectImage) SetImage(img *Image, cs PdfColorspace) error {
ximg.Stream = encoded
// Width, height and bits.
ximg.Width = &img.Width
ximg.Height = &img.Height
ximg.BitsPerComponent = &img.BitsPerComponent
w := img.Width
ximg.Width = &w
h := img.Height
ximg.Height = &h
bpc := img.BitsPerComponent
ximg.BitsPerComponent = &bpc
// Guess colorspace if not explicitly set.
if cs == nil {