public InlineImage CreateInlineImage(TransformationMatrix transformationMatrix, ILookupFilterProvider filterProvider, IPdfTokenScanner tokenScanner, RenderingIntent defaultRenderingIntent, IResourceStore resourceStore) { if (Properties == null || Bytes == null) { throw new InvalidOperationException($"Inline image builder not completely defined before calling {nameof(CreateInlineImage)}."); } var bounds = transformationMatrix.Transform(new PdfRectangle(new PdfPoint(1, 1), new PdfPoint(0, 0))); var width = GetByKeys <NumericToken>(NameToken.Width, NameToken.W, true).Int; var height = GetByKeys <NumericToken>(NameToken.Height, NameToken.H, true).Int; var maskToken = GetByKeys <BooleanToken>(NameToken.ImageMask, NameToken.Im, false); var isMask = maskToken?.Data == true; var bitsPerComponent = GetByKeys <NumericToken>(NameToken.BitsPerComponent, NameToken.Bpc, !isMask)?.Int ?? 1; var colorSpace = default(ColorSpace?); if (!isMask) { var colorSpaceName = GetByKeys <NameToken>(NameToken.ColorSpace, NameToken.Cs, false); if (colorSpaceName == null) { var colorSpaceArray = GetByKeys <ArrayToken>(NameToken.ColorSpace, NameToken.Cs, true); if (colorSpaceArray.Length == 0) { throw new PdfDocumentFormatException("Empty ColorSpace array defined for inline image."); } if (!(colorSpaceArray.Data[0] is NameToken firstColorSpaceName)) { throw new PdfDocumentFormatException($"Invalid ColorSpace array defined for inline image: {colorSpaceArray}."); } if (!ColorSpaceMapper.TryMap(firstColorSpaceName, resourceStore, out var colorSpaceMapped)) { throw new PdfDocumentFormatException($"Invalid ColorSpace defined for inline image: {firstColorSpaceName}."); } colorSpace = colorSpaceMapped; } else { if (!ColorSpaceMapper.TryMap(colorSpaceName, resourceStore, out var colorSpaceMapped)) { throw new PdfDocumentFormatException($"Invalid ColorSpace defined for inline image: {colorSpaceName}."); } colorSpace = colorSpaceMapped; } } var imgDic = new DictionaryToken(Properties ?? new Dictionary <NameToken, IToken>()); var details = ColorSpaceDetailsParser.GetColorSpaceDetails( colorSpace, imgDic, tokenScanner, resourceStore, filterProvider); var renderingIntent = GetByKeys <NameToken>(NameToken.Intent, null, false)?.Data?.ToRenderingIntent() ?? defaultRenderingIntent; var filterNames = new List <NameToken>(); var filterName = GetByKeys <NameToken>(NameToken.Filter, NameToken.F, false); if (filterName == null) { var filterArray = GetByKeys <ArrayToken>(NameToken.Filter, NameToken.F, false); if (filterArray != null) { filterNames.AddRange(filterArray.Data.OfType <NameToken>()); } } else { filterNames.Add(filterName); } var filters = filterProvider.GetNamedFilters(filterNames); var decodeRaw = GetByKeys <ArrayToken>(NameToken.Decode, NameToken.D, false) ?? new ArrayToken(EmptyArray <IToken> .Instance); var decode = decodeRaw.Data.OfType <NumericToken>().Select(x => x.Data).ToArray(); var filterDictionaryEntries = new Dictionary <NameToken, IToken>(); var decodeParamsDict = GetByKeys <DictionaryToken>(NameToken.DecodeParms, NameToken.Dp, false); if (decodeParamsDict == null) { var decodeParamsArray = GetByKeys <ArrayToken>(NameToken.DecodeParms, NameToken.Dp, false); if (decodeParamsArray != null) { filterDictionaryEntries[NameToken.DecodeParms] = decodeParamsArray; } } else { filterDictionaryEntries[NameToken.DecodeParms] = decodeParamsDict; } var streamDictionary = new DictionaryToken(filterDictionaryEntries); var interpolate = GetByKeys <BooleanToken>(NameToken.Interpolate, NameToken.I, false)?.Data ?? false; return(new InlineImage(bounds, width, height, bitsPerComponent, isMask, renderingIntent, interpolate, colorSpace, decode, Bytes, filters, streamDictionary, details)); }
public static XObjectImage ReadImage(XObjectContentRecord xObject, IPdfTokenScanner pdfScanner, ILookupFilterProvider filterProvider, IResourceStore resourceStore) { if (xObject == null) { throw new ArgumentNullException(nameof(xObject)); } if (xObject.Type != XObjectType.Image) { throw new InvalidOperationException($"Cannot create an image from an XObject with type: {xObject.Type}."); } var dictionary = xObject.Stream.StreamDictionary; var bounds = xObject.AppliedTransformation.Transform(new PdfRectangle(new PdfPoint(0, 0), new PdfPoint(1, 1))); var width = dictionary.Get <NumericToken>(NameToken.Width, pdfScanner).Int; var height = dictionary.Get <NumericToken>(NameToken.Height, pdfScanner).Int; var isImageMask = dictionary.TryGet(NameToken.ImageMask, pdfScanner, out BooleanToken isMaskToken) && isMaskToken.Data; var isJpxDecode = dictionary.TryGet(NameToken.Filter, out var token) && token is NameToken filterName && filterName.Equals(NameToken.JpxDecode); int bitsPerComponent = 0; if (!isImageMask && !isJpxDecode) { if (!dictionary.TryGet(NameToken.BitsPerComponent, pdfScanner, out NumericToken bitsPerComponentToken)) { throw new PdfDocumentFormatException($"No bits per component defined for image: {dictionary}."); } bitsPerComponent = bitsPerComponentToken.Int; } else if (isImageMask) { bitsPerComponent = 1; } var intent = xObject.DefaultRenderingIntent; if (dictionary.TryGet(NameToken.Intent, out NameToken renderingIntentToken)) { intent = renderingIntentToken.Data.ToRenderingIntent(); } var interpolate = dictionary.TryGet(NameToken.Interpolate, pdfScanner, out BooleanToken interpolateToken) && interpolateToken.Data; DictionaryToken filterDictionary = xObject.Stream.StreamDictionary; if (xObject.Stream.StreamDictionary.TryGet(NameToken.Filter, out var filterToken) && filterToken is IndirectReferenceToken) { if (filterDictionary.TryGet(NameToken.Filter, pdfScanner, out ArrayToken filterArray)) { filterDictionary = filterDictionary.With(NameToken.Filter, filterArray); } else if (filterDictionary.TryGet(NameToken.Filter, pdfScanner, out NameToken filterNameToken)) { filterDictionary = filterDictionary.With(NameToken.Filter, filterNameToken); } else { filterDictionary = null; } } var supportsFilters = filterDictionary != null; if (filterDictionary != null) { var filters = filterProvider.GetFilters(filterDictionary, pdfScanner); foreach (var filter in filters) { if (!filter.IsSupported) { supportsFilters = false; break; } } } var decodeParams = dictionary.GetObjectOrDefault(NameToken.DecodeParms, NameToken.Dp); if (decodeParams is IndirectReferenceToken refToken) { dictionary = dictionary.With(NameToken.DecodeParms, pdfScanner.Get(refToken.Data).Data); } var streamToken = new StreamToken(dictionary, xObject.Stream.Data); var decodedBytes = supportsFilters ? new Lazy <IReadOnlyList <byte> >(() => streamToken.Decode(filterProvider, pdfScanner)) : null; var decode = EmptyArray <decimal> .Instance; if (dictionary.TryGet(NameToken.Decode, pdfScanner, out ArrayToken decodeArrayToken)) { decode = decodeArrayToken.Data.OfType <NumericToken>() .Select(x => x.Data) .ToArray(); } var colorSpace = default(ColorSpace?); if (!isImageMask) { if (dictionary.TryGet(NameToken.ColorSpace, pdfScanner, out NameToken colorSpaceNameToken) && TryMapColorSpace(colorSpaceNameToken, resourceStore, out var colorSpaceResult)) { colorSpace = colorSpaceResult; } else if (dictionary.TryGet(NameToken.ColorSpace, pdfScanner, out ArrayToken colorSpaceArrayToken) && colorSpaceArrayToken.Length > 0) { var first = colorSpaceArrayToken.Data[0]; if ((first is NameToken firstColorSpaceName) && TryMapColorSpace(firstColorSpaceName, resourceStore, out colorSpaceResult)) { colorSpace = colorSpaceResult; } } else if (!isJpxDecode) { colorSpace = xObject.DefaultColorSpace; } } var details = ColorSpaceDetailsParser.GetColorSpaceDetails(colorSpace, dictionary, pdfScanner, resourceStore, filterProvider); return(new XObjectImage( bounds, width, height, bitsPerComponent, colorSpace, isJpxDecode, isImageMask, intent, interpolate, decode, dictionary, xObject.Stream.Data, decodedBytes, details)); }