public void CanGeneratePngFromCcittFaxDecodedImageData()
        {
            var decodedBytes = ImageHelpers.LoadFileBytes("ccittfax-decoded.bin");
            var image        = new TestPdfImage
            {
                ColorSpaceDetails = IndexedColorSpaceDetails.Stencil(DeviceGrayColorSpaceDetails.Instance, new[] { 1m, 0 }),
                DecodedBytes      = decodedBytes,
                WidthInSamples    = 1800,
                HeightInSamples   = 3113,
                BitsPerComponent  = 1
            };

            Assert.True(PngFromPdfImageFactory.TryGenerate(image, out var bytes));
            Assert.True(ImageHelpers.ImagesAreEqual(LoadImage("ccittfax.png"), bytes));
        }
Esempio n. 2
0
        public static ColorSpaceDetails GetColorSpaceDetails(ColorSpace?colorSpace,
                                                             DictionaryToken imageDictionary,
                                                             IPdfTokenScanner scanner,
                                                             IResourceStore resourceStore,
                                                             ILookupFilterProvider filterProvider,
                                                             bool cannotRecurse = false)
        {
            if (imageDictionary.GetObjectOrDefault(NameToken.ImageMask, NameToken.Im) != null ||
                filterProvider.GetFilters(imageDictionary, scanner).OfType <CcittFaxDecodeFilter>().Any())
            {
                if (cannotRecurse)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var colorSpaceDetails = GetColorSpaceDetails(colorSpace, imageDictionary.Without(NameToken.Filter).Without(NameToken.F), scanner, resourceStore, filterProvider, true);

                var decodeRaw = imageDictionary.GetObjectOrDefault(NameToken.Decode, NameToken.D) as ArrayToken
                                ?? new ArrayToken(EmptyArray <IToken> .Instance);
                var decode = decodeRaw.Data.OfType <NumericToken>().Select(x => x.Data).ToArray();

                return(IndexedColorSpaceDetails.Stencil(colorSpaceDetails, decode));
            }

            if (!colorSpace.HasValue)
            {
                return(UnsupportedColorSpaceDetails.Instance);
            }

            switch (colorSpace.Value)
            {
            case ColorSpace.DeviceGray:
                return(DeviceGrayColorSpaceDetails.Instance);

            case ColorSpace.DeviceRGB:
                return(DeviceRgbColorSpaceDetails.Instance);

            case ColorSpace.DeviceCMYK:
                return(DeviceCmykColorSpaceDetails.Instance);

            case ColorSpace.CalGray:
            {
                if (!TryGetColorSpaceArray(imageDictionary, resourceStore, scanner, out var colorSpaceArray) ||
                    colorSpaceArray.Length != 2)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var first = colorSpaceArray[0] as NameToken;

                if (first == null || !ColorSpaceMapper.TryMap(first, resourceStore, out var innerColorSpace) ||
                    innerColorSpace != ColorSpace.CalGray)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var second = colorSpaceArray[1];

                // WhitePoint is required
                if (!DirectObjectFinder.TryGet(second, scanner, out DictionaryToken dictionaryToken) ||
                    !dictionaryToken.TryGet(NameToken.WhitePoint, scanner, out ArrayToken whitePointToken))
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var whitePoint = whitePointToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();

                // BlackPoint is optional
                IReadOnlyList <decimal> blackPoint = null;
                if (dictionaryToken.TryGet(NameToken.BlackPoint, scanner, out ArrayToken blackPointToken))
                {
                    blackPoint = blackPointToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();
                }

                // Gamma is optional
                decimal?gamma = null;
                if (dictionaryToken.TryGet(NameToken.Gamma, scanner, out NumericToken gammaToken))
                {
                    gamma = gammaToken.Data;
                }

                return(new CalGrayColorSpaceDetails(whitePoint, blackPoint, gamma));
            }

            case ColorSpace.CalRGB:
            {
                if (!TryGetColorSpaceArray(imageDictionary, resourceStore, scanner, out var colorSpaceArray) ||
                    colorSpaceArray.Length != 2)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var first = colorSpaceArray[0] as NameToken;

                if (first == null || !ColorSpaceMapper.TryMap(first, resourceStore, out var innerColorSpace) ||
                    innerColorSpace != ColorSpace.CalRGB)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var second = colorSpaceArray[1];

                // WhitePoint is required
                if (!DirectObjectFinder.TryGet(second, scanner, out DictionaryToken dictionaryToken) ||
                    !dictionaryToken.TryGet(NameToken.WhitePoint, scanner, out ArrayToken whitePointToken))
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var whitePoint = whitePointToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();

                // BlackPoint is optional
                IReadOnlyList <decimal> blackPoint = null;
                if (dictionaryToken.TryGet(NameToken.BlackPoint, scanner, out ArrayToken blackPointToken))
                {
                    blackPoint = blackPointToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();
                }

                // Gamma is optional
                IReadOnlyList <decimal> gamma = null;
                if (dictionaryToken.TryGet(NameToken.Gamma, scanner, out ArrayToken gammaToken))
                {
                    gamma = gammaToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();
                }

                // Matrix is optional
                IReadOnlyList <decimal> matrix = null;
                if (dictionaryToken.TryGet(NameToken.Matrix, scanner, out ArrayToken matrixToken))
                {
                    matrix = matrixToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();
                }

                return(new CalRGBColorSpaceDetails(whitePoint, blackPoint, gamma, matrix));
            }

            case ColorSpace.Lab:
                return(UnsupportedColorSpaceDetails.Instance);

            case ColorSpace.ICCBased:
            {
                if (!TryGetColorSpaceArray(imageDictionary, resourceStore, scanner, out var colorSpaceArray) ||
                    colorSpaceArray.Length != 2)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var first = colorSpaceArray[0] as NameToken;

                if (first == null || !ColorSpaceMapper.TryMap(first, resourceStore, out var innerColorSpace) ||
                    innerColorSpace != ColorSpace.ICCBased)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var second = colorSpaceArray[1];

                // N is required
                if (!DirectObjectFinder.TryGet(second, scanner, out StreamToken streamToken) ||
                    !streamToken.StreamDictionary.TryGet(NameToken.N, scanner, out NumericToken numeric))
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                // Alternate is optional
                ColorSpaceDetails alternateColorSpaceDetails = null;
                if (streamToken.StreamDictionary.TryGet(NameToken.Alternate, out NameToken alternateColorSpaceNameToken) &&
                    ColorSpaceMapper.TryMap(alternateColorSpaceNameToken, resourceStore, out var alternateColorSpace))
                {
                    alternateColorSpaceDetails =
                        GetColorSpaceDetails(alternateColorSpace, imageDictionary, scanner, resourceStore, filterProvider, true);
                }

                // Range is optional
                IReadOnlyList <decimal> range = null;
                if (streamToken.StreamDictionary.TryGet(NameToken.Range, scanner, out ArrayToken arrayToken))
                {
                    range = arrayToken.Data.OfType <NumericToken>().Select(x => x.Data).ToList();
                }

                // Metadata is optional
                XmpMetadata metadata = null;
                if (streamToken.StreamDictionary.TryGet(NameToken.Metadata, scanner, out StreamToken metadataStream))
                {
                    metadata = new XmpMetadata(metadataStream, filterProvider, scanner);
                }

                return(new ICCBasedColorSpaceDetails(numeric.Int, alternateColorSpaceDetails, range, metadata));
            }

            case ColorSpace.Indexed:
            {
                if (cannotRecurse)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                if (!TryGetColorSpaceArray(imageDictionary, resourceStore, scanner, out var colorSpaceArray) ||
                    colorSpaceArray.Length != 4)
                {
                    // Error instead?
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var first = colorSpaceArray[0] as NameToken;

                if (first == null || !ColorSpaceMapper.TryMap(first, resourceStore, out var innerColorSpace) ||
                    innerColorSpace != ColorSpace.Indexed)
                {
                    return(UnsupportedColorSpaceDetails.Instance);
                }

                var second = colorSpaceArray[1];

                ColorSpaceDetails baseDetails;

                if (DirectObjectFinder.TryGet(second, scanner, out NameToken baseColorSpaceNameToken) &&
                    ColorSpaceMapper.TryMap(baseColorSpaceNameToken, resourceStore, out var baseColorSpaceName))
                {
                    baseDetails = GetColorSpaceDetails(
                        baseColorSpaceName,
                        imageDictionary,
                        scanner,
                        resourceStore,
                        filterProvider,
                        true);
                }
                else if (DirectObjectFinder.TryGet(second, scanner, out ArrayToken baseColorSpaceArrayToken) &&
                         baseColorSpaceArrayToken.Length > 0 && baseColorSpaceArrayToken[0] is NameToken baseColorSpaceArrayNameToken &&
                         ColorSpaceMapper.TryMap(baseColorSpaceArrayNameToken, resourceStore, out var baseColorSpaceArrayColorSpace))
                {
                    var pseudoImageDictionary = new DictionaryToken(
                        new Dictionary <NameToken, IToken>
                        {
                            { NameToken.ColorSpace, baseColorSpaceArrayToken }
                        });

                    baseDetails = GetColorSpaceDetails(
                        baseColorSpaceArrayColorSpace,
                        pseudoImageDictionary,
                        scanner,
                        resourceStore,
                        filterProvider,
                        true);
                }