mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-30 13:48:51 +08:00
Merge branch 'v3' into v3-integration-testing
This commit is contained in:
commit
24dbf33807
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user