Files
PdfPig/src/UglyToad.PdfPig/XObjects/XObjectFactory.cs
Eliot Jones 74774995d6 complete move of truetype, afm and standard14 fonts
the 3 font types mentioned are moved to the new fonts project, any referenced types are moved to the core project. most truetype classes are made public #8.
2020-01-04 22:39:13 +00:00

132 lines
5.1 KiB
C#

namespace UglyToad.PdfPig.XObjects
{
using System;
using System.Collections.Generic;
using System.Linq;
using Content;
using Core;
using Filters;
using Graphics;
using Graphics.Colors;
using Graphics.Core;
using Tokenization.Scanner;
using Tokens;
internal static class XObjectFactory
{
public static XObjectImage ReadImage(XObjectContentRecord xObject, IPdfTokenScanner pdfScanner,
IFilterProvider filterProvider,
IResourceStore resourceStore,
bool isLenientParsing)
{
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;
var decodedBytes = new Lazy<IReadOnlyList<byte>>(() => xObject.Stream.Decode(filterProvider));
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))
{
if (colorSpaceArrayToken.Length == 0)
{
throw new PdfDocumentFormatException($"Empty ColorSpace array defined for image XObject: {dictionary}.");
}
var first = colorSpaceArrayToken.Data[0];
if (!(first is NameToken firstColorSpaceName) || !TryMapColorSpace(firstColorSpaceName, resourceStore, out colorSpaceResult))
{
throw new PdfDocumentFormatException($"Invalid ColorSpace array defined for image XObject: {colorSpaceArrayToken}.");
}
colorSpace = colorSpaceResult;
}
else if (!isJpxDecode)
{
throw new PdfDocumentFormatException($"No ColorSpace defined for image XObject: {dictionary}.");
}
}
return new XObjectImage(bounds, width, height, bitsPerComponent, colorSpace, isJpxDecode, isImageMask, intent, interpolate, decode,
dictionary, xObject.Stream.Data, decodedBytes);
}
private static bool TryMapColorSpace(NameToken name, IResourceStore resourceStore, out ColorSpace colorSpaceResult)
{
if (name.TryMapToColorSpace(out colorSpaceResult))
{
return true;
}
if (!resourceStore.TryGetNamedColorSpace(name, out var colorSpaceNamedToken))
{
return false;
}
return colorSpaceNamedToken.Name.TryMapToColorSpace(out colorSpaceResult);
}
}
}