mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-11-28 17:47:12 +08:00
AddPage fixes for streams incorrectly being copied to page dict, add inheritance for media/crop box and rotation
This commit is contained in:
@@ -0,0 +1,61 @@
|
|||||||
|
%PDF-1.1
|
||||||
|
1 0 obj
|
||||||
|
<</Type/Catalog/Pages 2 0 R>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<</Type/Pages/Count 1/Kids[3 0 R]/MediaBox [0 0 200 100]>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/Type/Page
|
||||||
|
/Parent 2 0 R
|
||||||
|
/Resources <<
|
||||||
|
/XObject << /SomeImage 4 0 R >>
|
||||||
|
>>
|
||||||
|
/Contents 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Type/XObject
|
||||||
|
/Subtype/Image
|
||||||
|
/Width 200 % The width or height directly affects the image's file size.
|
||||||
|
/Height 100
|
||||||
|
/ColorSpace/DeviceRGB
|
||||||
|
/DecodeParms [] % Forces NativeImageDecoder.isSupported to return false.
|
||||||
|
/BitsPerComponent 8
|
||||||
|
/Length 580
|
||||||
|
/Filter [ /ASCIIHexDecode /DCTDecode ]
|
||||||
|
>>
|
||||||
|
% convert -size 1x1 xc:red jpeg:- | xxd -p -c40
|
||||||
|
stream
|
||||||
|
ffd8ffe000104a46494600010100000100010000ffdb004300030202020202030202020303030304
|
||||||
|
060404040404080606050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c
|
||||||
|
12131210130f101010ffdb00430103030304030408040408100b090b101010101010101010101010
|
||||||
|
1010101010101010101010101010101010101010101010101010101010101010101010101010ffc0
|
||||||
|
0011080001000103011100021101031101ffc40014000100000000000000000000000000000008ff
|
||||||
|
c40014100100000000000000000000000000000000ffc40015010101000000000000000000000000
|
||||||
|
00000709ffc40014110100000000000000000000000000000000ffda000c03010002110311003f00
|
||||||
|
3a03154dffd9
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<</Length 14>>
|
||||||
|
stream
|
||||||
|
500 0 0 400 0 0 cm
|
||||||
|
/SomeImage Do
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 6
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000008 00000 n
|
||||||
|
0000000054 00000 n
|
||||||
|
0000000128 00000 n
|
||||||
|
0000000246 00000 n
|
||||||
|
0000001201 00000 n
|
||||||
|
trailer
|
||||||
|
<</Root 1 0 R/Size 6>>
|
||||||
|
startxref
|
||||||
|
1281
|
||||||
|
%%EOF
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -165,9 +165,8 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CanMergeMultipleWithSelection()
|
public void CanMergeMultipleWithSelection()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
/// <param name="disposeStream">If stream should be disposed when builder is.</param>
|
/// <param name="disposeStream">If stream should be disposed when builder is.</param>
|
||||||
/// <param name="type">Type of pdf stream writer to use</param>
|
/// <param name="type">Type of pdf stream writer to use</param>
|
||||||
/// <param name="version">Pdf version to use in header.</param>
|
/// <param name="version">Pdf version to use in header.</param>
|
||||||
public PdfDocumentBuilder(Stream stream, bool disposeStream=false, PdfWriterType type=PdfWriterType.Default, decimal version=1.7m)
|
public PdfDocumentBuilder(Stream stream, bool disposeStream = false, PdfWriterType type = PdfWriterType.Default, decimal version = 1.7m)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@@ -286,10 +286,10 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
public DictionaryToken Page { get; set; }
|
public DictionaryToken Page { get; set; }
|
||||||
public IReadOnlyList<DictionaryToken> Parents { get; set; }
|
public IReadOnlyList<DictionaryToken> Parents { get; set; }
|
||||||
}
|
}
|
||||||
private readonly ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>> existingCopies =
|
private readonly ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>> existingCopies =
|
||||||
new ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>>();
|
new ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>>();
|
||||||
private readonly ConditionalWeakTable<PdfDocument, Dictionary<int, PageInfo>> existingTrees =
|
private readonly ConditionalWeakTable<PdfDocument, Dictionary<int, PageInfo>> existingTrees =
|
||||||
new ConditionalWeakTable<PdfDocument, Dictionary<int, PageInfo>>();
|
new ConditionalWeakTable<PdfDocument, Dictionary<int, PageInfo>>();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a new page with the specified size, this page will be included in the output when <see cref="Build"/> is called.
|
/// Add a new page with the specified size, this page will be included in the output when <see cref="Build"/> is called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -312,7 +312,8 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
{
|
{
|
||||||
pagesInfos[i] = new PageInfo
|
pagesInfos[i] = new PageInfo
|
||||||
{
|
{
|
||||||
Page = pageDict, Parents = parents
|
Page = pageDict,
|
||||||
|
Parents = parents
|
||||||
};
|
};
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -350,7 +351,7 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
|
|
||||||
// manually copy page dict / resources as we need to modify some
|
// manually copy page dict / resources as we need to modify some
|
||||||
var copiedPageDict = new Dictionary<NameToken, IToken>();
|
var copiedPageDict = new Dictionary<NameToken, IToken>();
|
||||||
Dictionary<NameToken, IToken> resources = new Dictionary<NameToken, IToken>();
|
Dictionary<NameToken, IToken> resources = new Dictionary<NameToken, IToken>();
|
||||||
|
|
||||||
// just put all parent resources into new page
|
// just put all parent resources into new page
|
||||||
foreach (var dict in pageInfo.Parents)
|
foreach (var dict in pageInfo.Parents)
|
||||||
@@ -358,6 +359,18 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
if (dict.TryGet(NameToken.Resources, out var resourceToken))
|
if (dict.TryGet(NameToken.Resources, out var resourceToken))
|
||||||
{
|
{
|
||||||
CopyResourceDict(resourceToken, resources);
|
CopyResourceDict(resourceToken, resources);
|
||||||
|
}
|
||||||
|
if (dict.TryGet(NameToken.MediaBox, out var mb))
|
||||||
|
{
|
||||||
|
copiedPageDict[NameToken.MediaBox] = WriterUtil.CopyToken(context, mb, document.Structure.TokenScanner, refs);
|
||||||
|
}
|
||||||
|
if (dict.TryGet(NameToken.CropBox, out var cb))
|
||||||
|
{
|
||||||
|
copiedPageDict[NameToken.CropBox] = WriterUtil.CopyToken(context, cb, document.Structure.TokenScanner, refs);
|
||||||
|
}
|
||||||
|
if (dict.TryGet(NameToken.Rotate, out var rt))
|
||||||
|
{
|
||||||
|
copiedPageDict[NameToken.Rotate] = WriterUtil.CopyToken(context, rt, document.Structure.TokenScanner, refs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,10 +409,19 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
{
|
{
|
||||||
if (!destinationDict.ContainsKey(NameToken.Create(item.Key)))
|
if (!destinationDict.ContainsKey(NameToken.Create(item.Key)))
|
||||||
{
|
{
|
||||||
if (item.Value is IndirectReferenceToken ir)
|
if (item.Value is IndirectReferenceToken ir)
|
||||||
{
|
{
|
||||||
// convert indirect to direct as PdfPageBuilder needs to modify resource entries
|
// convert indirect to direct as PdfPageBuilder needs to modify resource entries
|
||||||
destinationDict[NameToken.Create(item.Key)] = WriterUtil.CopyToken(context, document.Structure.TokenScanner.Get(ir.Data).Data, document.Structure.TokenScanner, refs);
|
var obj = document.Structure.TokenScanner.Get(ir.Data);
|
||||||
|
if (obj.Data is StreamToken)
|
||||||
|
{
|
||||||
|
// rare case, have seen /SubType as stream token, can't make direct
|
||||||
|
destinationDict[NameToken.Create(item.Key)] = WriterUtil.CopyToken(context, item.Value, document.Structure.TokenScanner, refs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
destinationDict[NameToken.Create(item.Key)] = WriterUtil.CopyToken(context, obj.Data, document.Structure.TokenScanner, refs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -458,7 +480,7 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int desiredLeafSize = 25; // allow customization at some point?
|
const int desiredLeafSize = 25; // allow customization at some point?
|
||||||
var numLeafs = (int) Math.Ceiling(Decimal.Divide(Pages.Count, desiredLeafSize));
|
var numLeafs = (int)Math.Ceiling(Decimal.Divide(Pages.Count, desiredLeafSize));
|
||||||
|
|
||||||
var leafRefs = new List<IndirectReferenceToken>();
|
var leafRefs = new List<IndirectReferenceToken>();
|
||||||
var leafChildren = new List<List<IndirectReferenceToken>>();
|
var leafChildren = new List<List<IndirectReferenceToken>>();
|
||||||
@@ -584,17 +606,17 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
{
|
{
|
||||||
// TODO shorten page tree when there is a single or small number of pages left in a branch
|
// TODO shorten page tree when there is a single or small number of pages left in a branch
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var thisObj = context.ReserveObjectNumber();
|
var thisObj = context.ReserveObjectNumber();
|
||||||
|
|
||||||
var children = new List<IndirectReferenceToken>();
|
var children = new List<IndirectReferenceToken>();
|
||||||
if (pagesNodes.Count > desiredLeafSize)
|
if (pagesNodes.Count > desiredLeafSize)
|
||||||
{
|
{
|
||||||
var currentTreeDepth = (int) Math.Ceiling(Math.Log(pagesNodes.Count, desiredLeafSize));
|
var currentTreeDepth = (int)Math.Ceiling(Math.Log(pagesNodes.Count, desiredLeafSize));
|
||||||
var perBranch = (int) Math.Ceiling(Math.Pow(desiredLeafSize, currentTreeDepth - 1));
|
var perBranch = (int)Math.Ceiling(Math.Pow(desiredLeafSize, currentTreeDepth - 1));
|
||||||
var branches = (int)Math.Ceiling(decimal.Divide(pagesNodes.Count, (decimal)perBranch));
|
var branches = (int)Math.Ceiling(decimal.Divide(pagesNodes.Count, (decimal)perBranch));
|
||||||
for (var i = 0; i < branches; i++)
|
for (var i = 0; i < branches; i++)
|
||||||
{
|
{
|
||||||
var part = pagesNodes.Skip(i*perBranch).Take(perBranch).ToList();
|
var part = pagesNodes.Skip(i * perBranch).Take(perBranch).ToList();
|
||||||
var result = CreatePageTree(part, thisObj);
|
var result = CreatePageTree(part, thisObj);
|
||||||
count += result.Count;
|
count += result.Count;
|
||||||
children.Add(result.Ref);
|
children.Add(result.Ref);
|
||||||
@@ -787,8 +809,8 @@ namespace UglyToad.PdfPig.Writer
|
|||||||
if (!completed)
|
if (!completed)
|
||||||
{
|
{
|
||||||
CompleteDocument();
|
CompleteDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Dispose();
|
context.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user