From e056c0e4d46ff62ad64cc496a5cb5b5e03f20bad Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Thu, 27 Feb 2020 00:26:20 +1100 Subject: [PATCH] Fixed PdfColorspaceSpecialIndexed.ImageToRGB() (#259) * Fixed PdfColorspaceSpecialIndexed.ImageToRGB() Fixes https://github.com/unidoc/unipdf/issues/258 * Fixed indexed colorspace bounds checking. * Being super cautious to prevent a divide by zero error. I don't think the base cs can have <1 cpts. * Updated image hash in extract_images_test.go to match new indexed colorspace code. * add testfile from unipdf#258 --- internal/e2etest/extract_images_test.go | 9 ++++++--- model/colorspace.go | 27 +++++++++++++++---------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/internal/e2etest/extract_images_test.go b/internal/e2etest/extract_images_test.go index f66310170..6d2cc4703 100644 --- a/internal/e2etest/extract_images_test.go +++ b/internal/e2etest/extract_images_test.go @@ -16,6 +16,8 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" + "github.com/unidoc/unipdf/v3/common" "github.com/unidoc/unipdf/v3/extractor" "github.com/unidoc/unipdf/v3/model" @@ -38,7 +40,7 @@ var knownExtrImgsHashes = map[string]string{ "7eee345c983461d44ae939b3f800a97642817c8d.pdf": "5a4cd00537f8a1f39fff2d4c6dd5cc53", "52ab322c1697aca9bad37288f7c502e37fa657af.pdf": "2bddee02dff89a38c08322c9d2c779a6", "0edf09fd438db2f18c1bb08fccc1f81a7b280bf2.pdf": "583f755b3fb1bd5697036616442687ab", - "cafe55316a45435c3817f4c1b6a19c9cd52db825.pdf": "b199badff0abb0311a2cbe35c7fce580", + "cafe55316a45435c3817f4c1b6a19c9cd52db825.pdf": "8b8c2eaa9b3a64eb5941348280c9c2a0", "6773e6aa5d8a2d26362cf3fca2874b3a81025bae.pdf": "f052e3e333839508a8bdd8d1a3ba1973", "d11a3ca55664828b69d7c39d83d5c0a63fcea89d.pdf": "29287cd44f009dce5aa9c2a0dc9a3c83", "483933bf73cc4fcc264eb69214ff763ccf299e49.pdf": "627dcf88805786d03b2e76d367b42642", @@ -46,12 +48,13 @@ var knownExtrImgsHashes = map[string]string{ "f856baf7ffcd96003b6bda800171cb0e5680f78e.pdf": "a9505d8c22f1fd063fbe0b05aa33a5fc", "201c20676fe8da14a8130852c91ed58b48cba8fb.pdf": "ffcb78d126c04be9ca2497bb43b6e964", "f0152456494aa09e5cf82c4afe9ecd2fdc2e8d72.pdf": "d0e68157aaa7f9f4406807512db3e676", - "d95643acea1ec3f6215bda35e4cd89dbd8898c44.pdf": "1739aed3e1cbfa5e98f8d7fef17a614b", + "d95643acea1ec3f6215bda35e4cd89dbd8898c44.pdf": "b4c7c2ae9671af69f71e9965e9cf67e8", "110d793aeaa7accbe40b5ab9db249d5a103d3b50.pdf": "a57e347edddfd3f6032b85553b3537cd", "d15a0aa289524619a971188372dd05fb712f1b2c.pdf": "380907273bb8ea64943d986491d827ec", "932e0dfa52c20ffe83b8178fb98296a0dab177d1.pdf": "b44d8b073f99ac3db28d7951e3c7d970", "60a8c28da5c23081834adac4170755904d8c4166.pdf": "9167f381d5eed7a2e5fd10eca567c519", "e51296be2615b9389482c9c16505286619b6cf36.pdf": "ec6e1f6297dd1cbda6ccba39e0c7d3d2", + "d3dd65300785dcf2114663397e475376bac88e75.pdf": "ea848ed888176368e697f577934f0452", // From unipdf#258. } func TestExtractImages(t *testing.T) { @@ -93,7 +96,7 @@ func TestExtractImages(t *testing.T) { knownHash, has := knownExtrImgsHashes[file.Name()] if has { - require.Equal(t, knownHash, hash) + assert.Equal(t, knownHash, hash) matchcount++ } else { t.Logf("%s - hash: %s not in the list of known hashes", file.Name(), hash) diff --git a/model/colorspace.go b/model/colorspace.go index 6b974ec4a..797ee28be 100644 --- a/model/colorspace.go +++ b/model/colorspace.go @@ -2217,8 +2217,9 @@ func (cs *PdfColorspaceSpecialPattern) ImageToRGB(img Image) (Image, error) { return img, errors.New("invalid colorspace for image (pattern)") } -// PdfColorspaceSpecialIndexed is an indexed color space is a lookup table, where the input element is an index to the -// lookup table and the output is a color defined in the lookup table in the Base colorspace. +// PdfColorspaceSpecialIndexed is an indexed color space is a lookup table, where the input element +// is an index to the lookup table and the output is a color defined in the lookup table in the Base +// colorspace. // [/Indexed base hival lookup] type PdfColorspaceSpecialIndexed struct { Base PdfColorspace @@ -2232,9 +2233,7 @@ type PdfColorspaceSpecialIndexed struct { // NewPdfColorspaceSpecialIndexed returns a new Indexed color. func NewPdfColorspaceSpecialIndexed() *PdfColorspaceSpecialIndexed { - cs := &PdfColorspaceSpecialIndexed{} - cs.HiVal = 255 - return cs + return &PdfColorspaceSpecialIndexed{HiVal: 255} } func (cs *PdfColorspaceSpecialIndexed) String() string { @@ -2401,24 +2400,30 @@ func (cs *PdfColorspaceSpecialIndexed) ImageToRGB(img Image) (Image, error) { baseImage.Height = img.Height baseImage.Width = img.Width baseImage.alphaData = img.alphaData - baseImage.BitsPerComponent = img.BitsPerComponent + // TODO(peterwilliams97): Add support for other BitsPerComponent values. + // See https://github.com/unidoc/unipdf/issues/260 + baseImage.BitsPerComponent = 8 baseImage.hasAlpha = img.hasAlpha - baseImage.ColorComponents = img.ColorComponents + baseImage.ColorComponents = cs.Base.GetNumComponents() samples := img.GetSamples() N := cs.Base.GetNumComponents() + if N < 1 { + return Image{}, fmt.Errorf("bad base colorspace NumComponents=%d", N) + } + var baseSamples []uint32 // Convert the indexed data to base color map data. for i := 0; i < len(samples); i++ { // Each data point represents an index location. // For each entry there are N values. - index := int(samples[i]) * N + index := int(samples[i]) common.Log.Trace("Indexed: index=%d N=%d lut=%d", index, N, len(cs.colorLookup)) // Ensure does not go out of bounds. - if index+N-1 >= len(cs.colorLookup) { + if (index+1)*N > len(cs.colorLookup) { // Clip to the end value. - index = len(cs.colorLookup) - N - 1 + index = len(cs.colorLookup)/N - 1 common.Log.Trace("Clipping to index: %d", index) if index < 0 { common.Log.Debug("ERROR: Can't clip index. Is PDF file damaged?") @@ -2426,7 +2431,7 @@ func (cs *PdfColorspaceSpecialIndexed) ImageToRGB(img Image) (Image, error) { } } - cvals := cs.colorLookup[index : index+N] + cvals := cs.colorLookup[index*N : (index+1)*N] common.Log.Trace("C Vals: % d", cvals) for _, val := range cvals { baseSamples = append(baseSamples, uint32(val))