Skip to content

Commit

Permalink
#710 set colorspace based on jpeg info
Browse files Browse the repository at this point in the history
  • Loading branch information
EliotJones authored and BobLd committed Jan 13, 2024
1 parent 83519b2 commit 90f7e4b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/UglyToad.PdfPig/Images/JpegHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public static JpegInformation GetInformation(Stream stream)
switch (marker)
{
case JpegMarker.StartOfImage:
case JpegMarker.EndOfImage:
case JpegMarker.Restart0:
case JpegMarker.Restart1:
case JpegMarker.Restart2:
Expand All @@ -49,8 +48,9 @@ public static JpegInformation GetInformation(Stream stream)
var bpp = stream.ReadByte();
var height = ReadShort(stream, shortBuffer);
var width = ReadShort(stream, shortBuffer);
var numberOfComponents = stream.ReadByte();

return new JpegInformation(width, height, bpp);
return new JpegInformation(width, height, bpp, numberOfComponents);
}
case JpegMarker.ApplicationSpecific0:
case JpegMarker.ApplicationSpecific1:
Expand Down
8 changes: 7 additions & 1 deletion src/UglyToad.PdfPig/Images/JpegInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ internal class JpegInformation
/// </summary>
public int BitsPerComponent { get; }

/// <summary>
/// 1 grayscale, 3 RGB, 4 CMYK.
/// </summary>
public int NumberOfComponents { get; }

/// <summary>
/// Create a new <see cref="JpegInformation"/>.
/// </summary>
public JpegInformation(int width, int height, int bitsPerComponent)
public JpegInformation(int width, int height, int bitsPerComponent, int numberOfComponents)
{
Width = width;
Height = height;
BitsPerComponent = bitsPerComponent;
NumberOfComponents = numberOfComponents;
}
}
}
83 changes: 52 additions & 31 deletions src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
using Tokens;
using Graphics.Operations.PathPainting;
using Images.Png;
using UglyToad.PdfPig.Actions;
using Actions;

internal class NameConflictSolver
{
private string prefix;
private readonly string prefix;
private int key = 0;
private HashSet<string> xobjectNamesUsed = new HashSet<string>();
private readonly HashSet<string> xobjectNamesUsed = new HashSet<string>();

public NameConflictSolver(string prefix)
{
Expand All @@ -44,20 +44,23 @@ private string ExtractPrefix(string name)
i++;
}

return i != 0 ? name.Substring(0,i) : prefix;

return i != 0 ? name.Substring(0, i) : prefix;
}

public string NewName(string orginalName = null)
{
var newPrefix = ExtractPrefix(orginalName);

var name = $"{newPrefix}{key}";

while (xobjectNamesUsed.Contains(name))
{
name = $"{newPrefix}{++key}";
}

xobjectNamesUsed.Add(name);

return name;
}

Expand All @@ -67,11 +70,9 @@ public string FixName(string name)
{
return NewName(name);
}
else
{
xobjectNamesUsed.Add(name);
return name;
}

xobjectNamesUsed.Add(name);
return name;
}

}
Expand All @@ -86,14 +87,14 @@ public class PdfPageBuilder

// all page data other than content streams
internal readonly Dictionary<NameToken, IToken> pageDictionary = new Dictionary<NameToken, IToken>();

// streams
internal readonly List<IPageContentStream> contentStreams;
private IPageContentStream currentStream;

// links to be resolved when all page references are available
internal readonly List<(DictionaryToken token, PdfAction action)> links;

// maps fonts added using PdfDocumentBuilder to page font names
private readonly Dictionary<Guid, NameToken> documentFonts = new Dictionary<Guid, NameToken>();
internal int nextFontId = 1;
Expand Down Expand Up @@ -135,7 +136,7 @@ internal PdfPageBuilder(int number, PdfDocumentBuilder documentBuilder)
PageNumber = number;

currentStream = new DefaultContentStream();
contentStreams = new List<IPageContentStream>() {currentStream};
contentStreams = new List<IPageContentStream>() { currentStream };
}

internal PdfPageBuilder(int number, PdfDocumentBuilder documentBuilder, IEnumerable<CopiedContentStream> copied,
Expand Down Expand Up @@ -553,7 +554,7 @@ private NameToken GetAddedFont(PdfDocumentBuilder.AddedFont font)
{
value = NameToken.Create($"F{nextFontId++}");
var resources = pageDictionary.GetOrCreateDict(NameToken.Resources);
var fonts = resources.GetOrCreateDict(NameToken.Font);
var fonts = resources.GetOrCreateDict(NameToken.Font);
while (fonts.ContainsKey(value))
{
value = NameToken.Create($"F{nextFontId++}");
Expand All @@ -576,7 +577,7 @@ public AddedImage AddJpeg(byte[] fileBytes, PdfRectangle placementRectangle)
return AddJpeg(stream, placementRectangle);
}
}


/// <summary>
/// Adds the JPEG image represented by the input stream at the specified location.
Expand All @@ -587,7 +588,13 @@ public AddedImage AddJpeg(Stream fileStream, PdfRectangle placementRectangle = d
var info = JpegHandler.GetInformation(fileStream);

if (placementRectangle.Equals(default(PdfRectangle)))
placementRectangle = new PdfRectangle(0, 0, info.Width, info.Height);
{
placementRectangle = new PdfRectangle(
0,
0,
info.Width,
info.Height);
}

byte[] data;
using (var memory = new MemoryStream())
Expand All @@ -597,14 +604,28 @@ public AddedImage AddJpeg(Stream fileStream, PdfRectangle placementRectangle = d
data = memory.ToArray();
}

NameToken colorSpace;
if (info.NumberOfComponents == 1)
{
colorSpace = NameToken.Devicegray;
}
else if (info.NumberOfComponents == 4)
{
colorSpace = NameToken.Devicecmyk;
}
else
{
colorSpace = NameToken.Devicergb;
}

var imgDictionary = new Dictionary<NameToken, IToken>
{
{NameToken.Type, NameToken.Xobject },
{NameToken.Subtype, NameToken.Image },
{NameToken.Width, new NumericToken(info.Width) },
{NameToken.Height, new NumericToken(info.Height) },
{NameToken.BitsPerComponent, new NumericToken(info.BitsPerComponent)},
{NameToken.ColorSpace, NameToken.Devicergb},
{NameToken.ColorSpace, colorSpace},
{NameToken.Filter, NameToken.DctDecode},
{NameToken.Length, new NumericToken(data.Length)}
};
Expand All @@ -613,12 +634,12 @@ public AddedImage AddJpeg(Stream fileStream, PdfRectangle placementRectangle = d
var resources = pageDictionary.GetOrCreateDict(NameToken.Resources);
var xObjects = resources.GetOrCreateDict(NameToken.Xobject);

var key = NameToken.Create( xobjectsNames.NewName());
var key = NameToken.Create(xobjectsNames.NewName());
xObjects[key] = reference;

currentStream.Add(Push.Value);
// This needs to be the placement rectangle.
currentStream.Add(new ModifyCurrentTransformationMatrix(new []
currentStream.Add(new ModifyCurrentTransformationMatrix(new[]
{
(decimal)placementRectangle.Width, 0,
0, (decimal)placementRectangle.Height,
Expand Down Expand Up @@ -760,7 +781,7 @@ public AddedImage AddPng(Stream pngStream, PdfRectangle placementRectangle = def
{
imgDictionary.Add(NameToken.Smask, smaskReference);
}

var reference = documentBuilder.AddImage(new DictionaryToken(imgDictionary), compressed);

var resources = pageDictionary.GetOrCreateDict(NameToken.Resources);
Expand Down Expand Up @@ -839,7 +860,7 @@ public PdfPageBuilder CopyFrom(Page srcPage)

// Special cases
// Since we don't directly add font's to the pages resources, we have to go look at the document's font
if(srcResourceDictionary.TryGet(NameToken.Font, srcPage.pdfScanner, out DictionaryToken fontsDictionary))
if (srcResourceDictionary.TryGet(NameToken.Font, srcPage.pdfScanner, out DictionaryToken fontsDictionary))
{
var pageFontsDictionary = resources.GetOrCreateDict(NameToken.Font);

Expand Down Expand Up @@ -1006,12 +1027,12 @@ private List<Letter> DrawLetters(NameToken name, string text, IWritingFont font,
var documentSpace = textMatrix.Transform(renderingMatrix.Transform(fontMatrix.Transform(rect)));

var letter = new Letter(
c.ToString(),
documentSpace,
advanceRect.BottomLeft,
advanceRect.BottomRight,
width,
(double)fontSize,
c.ToString(),
documentSpace,
advanceRect.BottomLeft,
advanceRect.BottomRight,
width,
(double)fontSize,
FontDetails.GetDefault(name),
TextRenderingMode.Fill,
GrayColor.Black,
Expand Down Expand Up @@ -1083,7 +1104,7 @@ internal class DefaultContentStream : IPageContentStream

public DefaultContentStream() : this(new List<IGraphicsStateOperation>())
{

}
public DefaultContentStream(List<IGraphicsStateOperation> operations)
{
Expand Down Expand Up @@ -1124,7 +1145,7 @@ internal class CopiedContentStream : IPageContentStream
private readonly IndirectReferenceToken token;
public bool ReadOnly => true;
public bool HasContent => true;

public CopiedContentStream(IndirectReferenceToken indirectReferenceToken)
{
token = indirectReferenceToken;
Expand All @@ -1140,7 +1161,7 @@ public void Add(IGraphicsStateOperation operation)
throw new NotSupportedException("Writing to a copied content stream is not supported.");
}

public List<IGraphicsStateOperation> Operations =>
public List<IGraphicsStateOperation> Operations =>
throw new NotSupportedException("Reading raw operations is not supported from a copied content stream.");
}

Expand Down Expand Up @@ -1183,6 +1204,6 @@ internal AddedImage(IndirectReference reference, int width, int height)
}
}


}
}

0 comments on commit 90f7e4b

Please sign in to comment.