mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-03-10 00:23:29 +08:00
write version from builder in xmp metadata #633
This commit is contained in:
@@ -8,12 +8,15 @@ namespace UglyToad.PdfPig.Writer
|
||||
{
|
||||
internal static class PdfABaselineRuleBuilder
|
||||
{
|
||||
public static void Obey(Dictionary<NameToken, IToken> catalog, Func<IToken, IndirectReferenceToken> writerFunc,
|
||||
public static void Obey(
|
||||
Dictionary<NameToken, IToken> catalog,
|
||||
Func<IToken, IndirectReferenceToken> writerFunc,
|
||||
PdfDocumentBuilder.DocumentInformationBuilder documentInformationBuilder,
|
||||
PdfAStandard archiveStandard)
|
||||
PdfAStandard archiveStandard,
|
||||
decimal version)
|
||||
{
|
||||
catalog[NameToken.OutputIntents] = OutputIntentsFactory.GetOutputIntentsArray(writerFunc);
|
||||
var xmpStream = XmpWriter.GenerateXmpStream(documentInformationBuilder, 1.7m, archiveStandard);
|
||||
var xmpStream = XmpWriter.GenerateXmpStream(documentInformationBuilder, version, archiveStandard);
|
||||
var xmpObj = writerFunc(xmpStream);
|
||||
catalog[NameToken.Metadata] = xmpObj;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Writer
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Tokens;
|
||||
@@ -8,7 +9,12 @@
|
||||
{
|
||||
private readonly Dictionary<byte[], IndirectReferenceToken> hashes = new Dictionary<byte[], IndirectReferenceToken>(new FNVByteComparison());
|
||||
|
||||
public PdfDedupStreamWriter(Stream stream, bool dispose, ITokenWriter tokenWriter = null) : base(stream, dispose, tokenWriter)
|
||||
public PdfDedupStreamWriter(
|
||||
Stream stream,
|
||||
bool dispose,
|
||||
ITokenWriter tokenWriter = null,
|
||||
Action<decimal> recordVersion = null
|
||||
) : base(stream, dispose, tokenWriter, recordVersion)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ namespace UglyToad.PdfPig.Writer
|
||||
using Content;
|
||||
using Core;
|
||||
using Fonts;
|
||||
using PdfPig.Actions;
|
||||
using Actions;
|
||||
using PdfPig.Fonts.TrueType;
|
||||
using PdfPig.Fonts.Standard14Fonts;
|
||||
using PdfPig.Fonts.TrueType.Parser;
|
||||
using PdfPig.Outline;
|
||||
using PdfPig.Outline.Destinations;
|
||||
using Outline;
|
||||
using Outline.Destinations;
|
||||
using Tokenization.Scanner;
|
||||
using Tokens;
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace UglyToad.PdfPig.Writer
|
||||
private readonly Dictionary<Guid, FontStored> fonts = new Dictionary<Guid, FontStored>();
|
||||
private bool completed = false;
|
||||
private int fontId = 0;
|
||||
private decimal version = 1.7m;
|
||||
|
||||
private readonly static ArrayToken DefaultProcSet = new ArrayToken(new List<NameToken>
|
||||
{
|
||||
@@ -76,7 +77,7 @@ namespace UglyToad.PdfPig.Writer
|
||||
/// </summary>
|
||||
public PdfDocumentBuilder()
|
||||
{
|
||||
context = new PdfStreamWriter(new MemoryStream(), true);
|
||||
context = new PdfStreamWriter(new MemoryStream(), true, recordVersion: x => version = x);
|
||||
context.InitializePdf(1.7m);
|
||||
}
|
||||
|
||||
@@ -86,7 +87,7 @@ namespace UglyToad.PdfPig.Writer
|
||||
/// <param name="version">Pdf version to use in header.</param>
|
||||
public PdfDocumentBuilder(decimal version)
|
||||
{
|
||||
context = new PdfStreamWriter(new MemoryStream(), true);
|
||||
context = new PdfStreamWriter(new MemoryStream(), true, recordVersion: x => version = x);
|
||||
context.InitializePdf(version);
|
||||
}
|
||||
|
||||
@@ -103,12 +104,13 @@ namespace UglyToad.PdfPig.Writer
|
||||
switch (type)
|
||||
{
|
||||
case PdfWriterType.ObjectInMemoryDedup:
|
||||
context = new PdfDedupStreamWriter(stream, disposeStream, tokenWriter);
|
||||
context = new PdfDedupStreamWriter(stream, disposeStream, tokenWriter, x => version = x);
|
||||
break;
|
||||
default:
|
||||
context = new PdfStreamWriter(stream, disposeStream, tokenWriter);
|
||||
context = new PdfStreamWriter(stream, disposeStream, tokenWriter, x => version = x);
|
||||
break;
|
||||
}
|
||||
|
||||
context.InitializePdf(version);
|
||||
}
|
||||
|
||||
@@ -712,7 +714,7 @@ namespace UglyToad.PdfPig.Writer
|
||||
{
|
||||
Func<IToken, IndirectReferenceToken> writerFunc = x => context.WriteToken(x);
|
||||
|
||||
PdfABaselineRuleBuilder.Obey(catalogDictionary, writerFunc, DocumentInformation, ArchiveStandard);
|
||||
PdfABaselineRuleBuilder.Obey(catalogDictionary, writerFunc, DocumentInformation, ArchiveStandard, version);
|
||||
|
||||
switch (ArchiveStandard)
|
||||
{
|
||||
|
||||
@@ -1,104 +1,115 @@
|
||||
namespace UglyToad.PdfPig.Writer
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Core;
|
||||
using Graphics.Operations;
|
||||
using Tokens;
|
||||
|
||||
/// <summary>
|
||||
/// This class would lazily flush all token. Allowing us to make changes to references without need to rewrite the whole stream
|
||||
/// </summary>
|
||||
internal class PdfStreamWriter : IPdfStreamWriter
|
||||
{
|
||||
protected const decimal DefaultVersion = 1.2m;
|
||||
protected Dictionary<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
|
||||
protected bool DisposeStream { get; set; }
|
||||
protected bool Initialized { get; set; }
|
||||
protected int CurrentNumber { get; set; } = 1;
|
||||
protected readonly ITokenWriter TokenWriter;
|
||||
|
||||
internal PdfStreamWriter(Stream baseStream, bool disposeStream = true, ITokenWriter tokenWriter = null)
|
||||
{
|
||||
Stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
|
||||
if (!baseStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("Output stream must be writable");
|
||||
}
|
||||
DisposeStream = disposeStream;
|
||||
TokenWriter = tokenWriter ?? new TokenWriter();
|
||||
}
|
||||
|
||||
namespace UglyToad.PdfPig.Writer
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Core;
|
||||
using Graphics.Operations;
|
||||
using Tokens;
|
||||
|
||||
/// <summary>
|
||||
/// This class would lazily flush all token. Allowing us to make changes to references without need to rewrite the whole stream
|
||||
/// </summary>
|
||||
internal class PdfStreamWriter : IPdfStreamWriter
|
||||
{
|
||||
private readonly Action<decimal> recordVersion;
|
||||
protected const decimal DefaultVersion = 1.2m;
|
||||
protected Dictionary<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
|
||||
protected bool DisposeStream { get; set; }
|
||||
protected bool Initialized { get; set; }
|
||||
protected int CurrentNumber { get; set; } = 1;
|
||||
protected readonly ITokenWriter TokenWriter;
|
||||
|
||||
public Stream Stream { get; protected set; }
|
||||
|
||||
public bool AttemptDeduplication { get; set; } = true;
|
||||
|
||||
public virtual IndirectReferenceToken WriteToken(IToken token)
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
InitializePdf(DefaultVersion);
|
||||
}
|
||||
|
||||
var ir = ReserveObjectNumber();
|
||||
offsets.Add(ir.Data, Stream.Position);
|
||||
var obj = new ObjectToken(Stream.Position, ir.Data, token);
|
||||
TokenWriter.WriteToken(obj, Stream);
|
||||
return ir;
|
||||
}
|
||||
|
||||
public virtual IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference)
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
InitializePdf(DefaultVersion);
|
||||
}
|
||||
|
||||
offsets.Add(indirectReference.Data, Stream.Position);
|
||||
var obj = new ObjectToken(Stream.Position, indirectReference.Data, token);
|
||||
TokenWriter.WriteToken(obj, Stream);
|
||||
return indirectReference;
|
||||
}
|
||||
|
||||
public IndirectReferenceToken ReserveObjectNumber()
|
||||
{
|
||||
return new IndirectReferenceToken(new IndirectReference(CurrentNumber++, 0));
|
||||
}
|
||||
|
||||
public void InitializePdf(decimal version)
|
||||
{
|
||||
WriteString($"%PDF-{version.ToString("0.0", CultureInfo.InvariantCulture)}", Stream);
|
||||
|
||||
Stream.WriteText("%");
|
||||
Stream.WriteByte(169);
|
||||
Stream.WriteByte(205);
|
||||
Stream.WriteByte(196);
|
||||
Stream.WriteByte(210);
|
||||
Stream.WriteNewLine();
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
public void CompletePdf(IndirectReferenceToken catalogReference, IndirectReferenceToken documentInformationReference = null)
|
||||
{
|
||||
TokenWriter.WriteCrossReferenceTable(offsets, catalogReference.Data, Stream, documentInformationReference?.Data);
|
||||
}
|
||||
|
||||
private static void WriteString(string text, Stream stream)
|
||||
{
|
||||
var bytes = OtherEncodings.StringAsLatin1Bytes(text);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
stream.WriteNewLine();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (DisposeStream)
|
||||
{
|
||||
Stream?.Dispose();
|
||||
}
|
||||
|
||||
Stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal PdfStreamWriter(
|
||||
Stream baseStream,
|
||||
bool disposeStream = true,
|
||||
ITokenWriter tokenWriter = null,
|
||||
Action<decimal> recordVersion = null)
|
||||
{
|
||||
Stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
|
||||
|
||||
if (!baseStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("Output stream must be writable");
|
||||
}
|
||||
|
||||
this.recordVersion = recordVersion;
|
||||
DisposeStream = disposeStream;
|
||||
TokenWriter = tokenWriter ?? new TokenWriter();
|
||||
}
|
||||
|
||||
public virtual IndirectReferenceToken WriteToken(IToken token)
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
InitializePdf(DefaultVersion);
|
||||
}
|
||||
|
||||
var ir = ReserveObjectNumber();
|
||||
offsets.Add(ir.Data, Stream.Position);
|
||||
var obj = new ObjectToken(Stream.Position, ir.Data, token);
|
||||
TokenWriter.WriteToken(obj, Stream);
|
||||
return ir;
|
||||
}
|
||||
|
||||
public virtual IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference)
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
InitializePdf(DefaultVersion);
|
||||
}
|
||||
|
||||
offsets.Add(indirectReference.Data, Stream.Position);
|
||||
var obj = new ObjectToken(Stream.Position, indirectReference.Data, token);
|
||||
TokenWriter.WriteToken(obj, Stream);
|
||||
return indirectReference;
|
||||
}
|
||||
|
||||
public IndirectReferenceToken ReserveObjectNumber()
|
||||
{
|
||||
return new IndirectReferenceToken(new IndirectReference(CurrentNumber++, 0));
|
||||
}
|
||||
|
||||
public void InitializePdf(decimal version)
|
||||
{
|
||||
recordVersion?.Invoke(version);
|
||||
|
||||
WriteString($"%PDF-{version.ToString("0.0", CultureInfo.InvariantCulture)}", Stream);
|
||||
|
||||
Stream.WriteText("%");
|
||||
Stream.WriteByte(169);
|
||||
Stream.WriteByte(205);
|
||||
Stream.WriteByte(196);
|
||||
Stream.WriteByte(210);
|
||||
Stream.WriteNewLine();
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
public void CompletePdf(IndirectReferenceToken catalogReference, IndirectReferenceToken documentInformationReference = null)
|
||||
{
|
||||
TokenWriter.WriteCrossReferenceTable(offsets, catalogReference.Data, Stream, documentInformationReference?.Data);
|
||||
}
|
||||
|
||||
private static void WriteString(string text, Stream stream)
|
||||
{
|
||||
var bytes = OtherEncodings.StringAsLatin1Bytes(text);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
stream.WriteNewLine();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (DisposeStream)
|
||||
{
|
||||
Stream?.Dispose();
|
||||
}
|
||||
|
||||
Stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ using UglyToad.PdfPig.Tokens;
|
||||
|
||||
namespace UglyToad.PdfPig.Writer.Xmp
|
||||
{
|
||||
using System.Globalization;
|
||||
|
||||
internal static class XmpWriter
|
||||
{
|
||||
private const string Xmptk = "Adobe XMP Core 5.6-c014 79.156797, 2014/08/20-09:53:02 ";
|
||||
@@ -67,7 +69,7 @@ namespace UglyToad.PdfPig.Writer.Xmp
|
||||
AddElementsForSchema(rdfDescriptionElement, AdobePdfPrefix, AdobePdfNamespace, builder,
|
||||
new List<SchemaMapper>
|
||||
{
|
||||
new SchemaMapper("PDFVersion", b => "1.7"),
|
||||
new SchemaMapper("PDFVersion", b => version.ToString("F1", CultureInfo.InvariantCulture)),
|
||||
new SchemaMapper("Producer", b => b.Producer)
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user