github.com/andybalholm/giopdf@v0.0.0-20220317170119-aad9a095ad48/image.go (about)

     1  package giopdf
     2  
     3  import (
     4  	"fmt"
     5  	"image"
     6  	"image/color"
     7  	"image/jpeg"
     8  	"io"
     9  
    10  	"github.com/andybalholm/giopdf/pdf"
    11  )
    12  
    13  func decodeImage(img pdf.Value) (image.Image, error) {
    14  	if img.HasFilter("DCTDecode") {
    15  		// It's a JPEG image.
    16  		return jpeg.Decode(img.EncodedReader("DCTDecode"))
    17  	}
    18  
    19  	data, err := io.ReadAll(img.Reader())
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  	cs := img.Key("ColorSpace").Name()
    24  	bits := img.Key("BitsPerComponent").Int()
    25  	switch {
    26  	case cs == "DeviceGray" && bits == 1:
    27  		result := &bitmapImage{
    28  			Width:      img.Key("Width").Int(),
    29  			Height:     img.Key("Height").Int(),
    30  			Data:       data,
    31  			Foreground: color.White,
    32  			Background: color.Black,
    33  		}
    34  		switch img.Key("Decode").String() {
    35  		case "[0, 1]", "<nil>":
    36  			// Default; leave values unchanged.
    37  		case "[1, 0]":
    38  			result.Background = color.White
    39  			result.Foreground = color.Black
    40  		default:
    41  			return nil, fmt.Errorf("unsupported Decode array: %v", img.Key("Decode"))
    42  		}
    43  		return result, nil
    44  	}
    45  
    46  	return nil, fmt.Errorf("unsupported image (ColorSpace: %v, BitsPerComponent: %d)", img.Key("ColorSpace"), bits)
    47  }
    48  
    49  type bitmapImage struct {
    50  	Width      int
    51  	Height     int
    52  	Data       []byte
    53  	Foreground color.Color
    54  	Background color.Color
    55  }
    56  
    57  func (bi *bitmapImage) ColorModel() color.Model {
    58  	return color.GrayModel
    59  }
    60  
    61  func (bi *bitmapImage) Bounds() image.Rectangle {
    62  	return image.Rect(0, 0, bi.Width, bi.Height)
    63  }
    64  
    65  func (bi *bitmapImage) At(x, y int) color.Color {
    66  	stride := bi.Width / 8
    67  	if bi.Width%8 != 0 {
    68  		stride += 1
    69  	}
    70  	b := bi.Data[stride*y+x/8]
    71  	b &= 1 << (7 - x%8)
    72  
    73  	if b == 0 {
    74  		return bi.Background
    75  	}
    76  	return bi.Foreground
    77  }