mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-27 13:48:51 +08:00
Improving godoc and fixing style image.go
This commit is contained in:
parent
d8ce72df07
commit
a66ad79023
@ -19,7 +19,7 @@ import (
|
||||
"github.com/unidoc/unidoc/pdf/internal/sampling"
|
||||
)
|
||||
|
||||
// Basic representation of an image.
|
||||
// Image interface is a basic representation of an image used in PDF.
|
||||
// The colorspace is not specified, but must be known when handling the image.
|
||||
type Image struct {
|
||||
Width int64 // The width of the image in samples
|
||||
@ -36,22 +36,23 @@ type Image struct {
|
||||
decode []float64 // [Dmin Dmax ... values for each color component]
|
||||
}
|
||||
|
||||
// Threshold alpha channel. Set all alpha values below threshold to transparent.
|
||||
// AlphaMapFunc represents a alpha mapping function: byte -> byte. Can be used for
|
||||
// thresholding the alpha channel, i.e. setting all alpha values below threshold to transparent.
|
||||
type AlphaMapFunc func(alpha byte) byte
|
||||
|
||||
// Allow mapping of alpha data for transformations. Can allow custom filtering of alpha data etc.
|
||||
func (this Image) AlphaMap(mapFunc AlphaMapFunc) {
|
||||
for idx, alpha := range this.alphaData {
|
||||
this.alphaData[idx] = mapFunc(alpha)
|
||||
// AlphaMap performs mapping of alpha data for transformations. Allows custom filtering of alpha data etc.
|
||||
func (img *Image) AlphaMap(mapFunc AlphaMapFunc) {
|
||||
for idx, alpha := range img.alphaData {
|
||||
img.alphaData[idx] = mapFunc(alpha)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the raw byte slice into samples which are stored in a uint32 bit array.
|
||||
// GetSamples converts the raw byte slice into samples which are stored in a uint32 bit array.
|
||||
// Each sample is represented by BitsPerComponent consecutive bits in the raw data.
|
||||
func (this *Image) GetSamples() []uint32 {
|
||||
samples := sampling.ResampleBytes(this.Data, int(this.BitsPerComponent))
|
||||
func (img *Image) GetSamples() []uint32 {
|
||||
samples := sampling.ResampleBytes(img.Data, int(img.BitsPerComponent))
|
||||
|
||||
expectedLen := int(this.Width) * int(this.Height) * this.ColorComponents
|
||||
expectedLen := int(img.Width) * int(img.Height) * img.ColorComponents
|
||||
if len(samples) < expectedLen {
|
||||
// Return error, or fill with 0s?
|
||||
common.Log.Debug("Error: Too few samples (got %d, expecting %d)", len(samples), expectedLen)
|
||||
@ -62,15 +63,15 @@ func (this *Image) GetSamples() []uint32 {
|
||||
return samples
|
||||
}
|
||||
|
||||
// Convert samples to byte-data.
|
||||
func (this *Image) SetSamples(samples []uint32) {
|
||||
resampled := sampling.ResampleUint32(samples, int(this.BitsPerComponent), 8)
|
||||
// SetSamples convert samples to byte-data and sets for the image.
|
||||
func (img *Image) SetSamples(samples []uint32) {
|
||||
resampled := sampling.ResampleUint32(samples, int(img.BitsPerComponent), 8)
|
||||
data := []byte{}
|
||||
for _, val := range resampled {
|
||||
data = append(data, byte(val))
|
||||
}
|
||||
|
||||
this.Data = data
|
||||
img.Data = data
|
||||
}
|
||||
|
||||
// Resample resamples the image data converting from current BitsPerComponent to a target BitsPerComponent
|
||||
@ -85,8 +86,8 @@ func (this *Image) SetSamples(samples []uint32) {
|
||||
// }
|
||||
// // Resample as 1 bit.
|
||||
// grayImage.Resample(1)
|
||||
func (this *Image) Resample(targetBitsPerComponent int64) {
|
||||
samples := this.GetSamples()
|
||||
func (img *Image) Resample(targetBitsPerComponent int64) {
|
||||
samples := img.GetSamples()
|
||||
|
||||
// Image data are stored row by row. If the number of bits per row is not a multiple of 8, the end of the
|
||||
// row needs to be padded with extra bits to fill out the last byte.
|
||||
@ -98,13 +99,13 @@ func (this *Image) Resample(targetBitsPerComponent int64) {
|
||||
// i.e. 10011010 >> targetBitsPerComponent
|
||||
// Current bits: 8, target bits: 1... need to downsample by 8-1 = 7
|
||||
|
||||
if targetBitsPerComponent < this.BitsPerComponent {
|
||||
downsampling := this.BitsPerComponent - targetBitsPerComponent
|
||||
if targetBitsPerComponent < img.BitsPerComponent {
|
||||
downsampling := img.BitsPerComponent - targetBitsPerComponent
|
||||
for i := range samples {
|
||||
samples[i] >>= uint(downsampling)
|
||||
}
|
||||
} else if targetBitsPerComponent > this.BitsPerComponent {
|
||||
upsampling := targetBitsPerComponent - this.BitsPerComponent
|
||||
} else if targetBitsPerComponent > img.BitsPerComponent {
|
||||
upsampling := targetBitsPerComponent - img.BitsPerComponent
|
||||
for i := range samples {
|
||||
samples[i] <<= uint(upsampling)
|
||||
}
|
||||
@ -114,9 +115,9 @@ func (this *Image) Resample(targetBitsPerComponent int64) {
|
||||
|
||||
// Write out row by row...
|
||||
data := []byte{}
|
||||
for i := int64(0); i < this.Height; i++ {
|
||||
ind1 := i * this.Width * int64(this.ColorComponents)
|
||||
ind2 := (i+1)*this.Width*int64(this.ColorComponents) - 1
|
||||
for i := int64(0); i < img.Height; i++ {
|
||||
ind1 := i * img.Width * int64(img.ColorComponents)
|
||||
ind2 := (i+1)*img.Width*int64(img.ColorComponents) - 1
|
||||
|
||||
resampled := sampling.ResampleUint32(samples[ind1:ind2], int(targetBitsPerComponent), 8)
|
||||
for _, val := range resampled {
|
||||
@ -124,33 +125,33 @@ func (this *Image) Resample(targetBitsPerComponent int64) {
|
||||
}
|
||||
}
|
||||
|
||||
this.Data = data
|
||||
this.BitsPerComponent = int64(targetBitsPerComponent)
|
||||
img.Data = data
|
||||
img.BitsPerComponent = int64(targetBitsPerComponent)
|
||||
}
|
||||
|
||||
// Converts the unidoc Image to a golang Image structure.
|
||||
func (this *Image) ToGoImage() (goimage.Image, error) {
|
||||
// ToGoImage converts the unidoc Image to a golang Image structure.
|
||||
func (img *Image) ToGoImage() (goimage.Image, error) {
|
||||
common.Log.Trace("Converting to go image")
|
||||
bounds := goimage.Rect(0, 0, int(this.Width), int(this.Height))
|
||||
var img DrawableImage
|
||||
bounds := goimage.Rect(0, 0, int(img.Width), int(img.Height))
|
||||
var imgout DrawableImage
|
||||
|
||||
if this.ColorComponents == 1 {
|
||||
if this.BitsPerComponent == 16 {
|
||||
img = goimage.NewGray16(bounds)
|
||||
if img.ColorComponents == 1 {
|
||||
if img.BitsPerComponent == 16 {
|
||||
imgout = goimage.NewGray16(bounds)
|
||||
} else {
|
||||
img = goimage.NewGray(bounds)
|
||||
imgout = goimage.NewGray(bounds)
|
||||
}
|
||||
} else if this.ColorComponents == 3 {
|
||||
if this.BitsPerComponent == 16 {
|
||||
img = goimage.NewRGBA64(bounds)
|
||||
} else if img.ColorComponents == 3 {
|
||||
if img.BitsPerComponent == 16 {
|
||||
imgout = goimage.NewRGBA64(bounds)
|
||||
} else {
|
||||
img = goimage.NewRGBA(bounds)
|
||||
imgout = goimage.NewRGBA(bounds)
|
||||
}
|
||||
} else if this.ColorComponents == 4 {
|
||||
img = goimage.NewCMYK(bounds)
|
||||
} else if img.ColorComponents == 4 {
|
||||
imgout = goimage.NewCMYK(bounds)
|
||||
} else {
|
||||
// XXX? Force RGB convert?
|
||||
common.Log.Debug("Unsupported number of colors components per sample: %d", this.ColorComponents)
|
||||
common.Log.Debug("Unsupported number of colors components per sample: %d", img.ColorComponents)
|
||||
return nil, errors.New("Unsupported colors")
|
||||
}
|
||||
|
||||
@ -159,27 +160,27 @@ func (this *Image) ToGoImage() (goimage.Image, error) {
|
||||
y := 0
|
||||
aidx := 0
|
||||
|
||||
samples := this.GetSamples()
|
||||
//bytesPerColor := colorComponents * int(this.BitsPerComponent) / 8
|
||||
bytesPerColor := this.ColorComponents
|
||||
samples := img.GetSamples()
|
||||
//bytesPerColor := colorComponents * int(img.BitsPerComponent) / 8
|
||||
bytesPerColor := img.ColorComponents
|
||||
for i := 0; i+bytesPerColor-1 < len(samples); i += bytesPerColor {
|
||||
var c gocolor.Color
|
||||
if this.ColorComponents == 1 {
|
||||
if this.BitsPerComponent == 16 {
|
||||
if img.ColorComponents == 1 {
|
||||
if img.BitsPerComponent == 16 {
|
||||
val := uint16(samples[i])<<8 | uint16(samples[i+1])
|
||||
c = gocolor.Gray16{val}
|
||||
} else {
|
||||
val := uint8(samples[i] & 0xff)
|
||||
c = gocolor.Gray{val}
|
||||
}
|
||||
} else if this.ColorComponents == 3 {
|
||||
if this.BitsPerComponent == 16 {
|
||||
} else if img.ColorComponents == 3 {
|
||||
if img.BitsPerComponent == 16 {
|
||||
r := uint16(samples[i])<<8 | uint16(samples[i+1])
|
||||
g := uint16(samples[i+2])<<8 | uint16(samples[i+3])
|
||||
b := uint16(samples[i+4])<<8 | uint16(samples[i+5])
|
||||
a := uint16(0xffff) // Default: solid (0xffff) whereas transparent=0.
|
||||
if this.alphaData != nil && len(this.alphaData) > aidx+1 {
|
||||
a = (uint16(this.alphaData[aidx]) << 8) | uint16(this.alphaData[aidx+1])
|
||||
if img.alphaData != nil && len(img.alphaData) > aidx+1 {
|
||||
a = (uint16(img.alphaData[aidx]) << 8) | uint16(img.alphaData[aidx+1])
|
||||
aidx += 2
|
||||
}
|
||||
c = gocolor.RGBA64{R: r, G: g, B: b, A: a}
|
||||
@ -188,13 +189,13 @@ func (this *Image) ToGoImage() (goimage.Image, error) {
|
||||
g := uint8(samples[i+1] & 0xff)
|
||||
b := uint8(samples[i+2] & 0xff)
|
||||
a := uint8(0xff) // Default: solid (0xff) whereas transparent=0.
|
||||
if this.alphaData != nil && len(this.alphaData) > aidx {
|
||||
a = uint8(this.alphaData[aidx])
|
||||
if img.alphaData != nil && len(img.alphaData) > aidx {
|
||||
a = uint8(img.alphaData[aidx])
|
||||
aidx++
|
||||
}
|
||||
c = gocolor.RGBA{R: r, G: g, B: b, A: a}
|
||||
}
|
||||
} else if this.ColorComponents == 4 {
|
||||
} else if img.ColorComponents == 4 {
|
||||
c1 := uint8(samples[i] & 0xff)
|
||||
m1 := uint8(samples[i+1] & 0xff)
|
||||
y1 := uint8(samples[i+2] & 0xff)
|
||||
@ -202,18 +203,18 @@ func (this *Image) ToGoImage() (goimage.Image, error) {
|
||||
c = gocolor.CMYK{C: c1, M: m1, Y: y1, K: k1}
|
||||
}
|
||||
|
||||
img.Set(x, y, c)
|
||||
imgout.Set(x, y, c)
|
||||
x++
|
||||
if x == int(this.Width) {
|
||||
if x == int(img.Width) {
|
||||
x = 0
|
||||
y++
|
||||
}
|
||||
}
|
||||
|
||||
return img, nil
|
||||
return imgout, nil
|
||||
}
|
||||
|
||||
// The ImageHandler interface implements common image loading and processing tasks.
|
||||
// ImageHandler interface implements common image loading and processing tasks.
|
||||
// Implementing as an interface allows for the possibility to use non-standard libraries for faster
|
||||
// loading and processing of images.
|
||||
type ImageHandler interface {
|
||||
@ -227,12 +228,11 @@ type ImageHandler interface {
|
||||
Compress(input *Image, quality int64) (*Image, error)
|
||||
}
|
||||
|
||||
// Default implementation.
|
||||
|
||||
// DefaultImageHandler is the default implementation of the ImageHandler using the standard go library.
|
||||
type DefaultImageHandler struct{}
|
||||
|
||||
// Create a unidoc Image from a golang Image.
|
||||
func (this DefaultImageHandler) NewImageFromGoImage(goimg goimage.Image) (*Image, error) {
|
||||
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.
|
||||
b := goimg.Bounds()
|
||||
@ -269,9 +269,9 @@ func (this DefaultImageHandler) NewImageFromGoImage(goimg goimage.Image) (*Image
|
||||
return &imag, nil
|
||||
}
|
||||
|
||||
// Reads an image and loads into a new Image object with an RGB
|
||||
// Read reads an image and loads into a new Image object with an RGB
|
||||
// colormap and 8 bits per component.
|
||||
func (this DefaultImageHandler) Read(reader io.Reader) (*Image, error) {
|
||||
func (ih DefaultImageHandler) Read(reader io.Reader) (*Image, error) {
|
||||
// Load the image with the native implementation.
|
||||
goimg, _, err := goimage.Decode(reader)
|
||||
if err != nil {
|
||||
@ -279,18 +279,20 @@ func (this DefaultImageHandler) Read(reader io.Reader) (*Image, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.NewImageFromGoImage(goimg)
|
||||
return ih.NewImageFromGoImage(goimg)
|
||||
}
|
||||
|
||||
// To be implemented.
|
||||
// Compress is yet to be implemented.
|
||||
// Should be able to compress in terms of JPEG quality parameter,
|
||||
// and DPI threshold (need to know bounding area dimensions).
|
||||
func (this DefaultImageHandler) Compress(input *Image, quality int64) (*Image, error) {
|
||||
func (ih DefaultImageHandler) Compress(input *Image, quality int64) (*Image, error) {
|
||||
return input, nil
|
||||
}
|
||||
|
||||
// ImageHandler is used for handling images.
|
||||
var ImageHandling ImageHandler = DefaultImageHandler{}
|
||||
|
||||
// SetImageHandler sets the image handler used by the package.
|
||||
func SetImageHandler(imgHandling ImageHandler) {
|
||||
ImageHandling = imgHandling
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user