[pdfmod] Show custom page labels (eg ii or A-10) if set
- From: Gabriel Burt <gburt src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [pdfmod] Show custom page labels (eg ii or A-10) if set
- Date: Fri, 7 Aug 2009 18:07:16 +0000 (UTC)
commit b97700ff60aa5930877d53fa83cc29f24e9cd69e
Author: Michael McKinley <m mckinley gmail com>
Date: Fri Aug 7 11:03:57 2009 -0700
Show custom page labels (eg ii or A-10) if set
Signed-off-by: Gabriel Burt <gabriel burt gmail com>
src/PdfMod/Makefile.am | 1 +
src/PdfMod/PdfMod.mdp | 1 +
src/PdfMod/PdfMod/Document.cs | 3 +
src/PdfMod/PdfMod/PageLabels.cs | 274 +++++++++++++++++++++++++++++++++++++
src/PdfMod/PdfMod/PdfListStore.cs | 17 ++-
5 files changed, 289 insertions(+), 7 deletions(-)
---
diff --git a/src/PdfMod/Makefile.am b/src/PdfMod/Makefile.am
index be15cb2..0544d26 100644
--- a/src/PdfMod/Makefile.am
+++ b/src/PdfMod/Makefile.am
@@ -90,6 +90,7 @@ FILES = \
PdfMod/GlobalActions.cs \
PdfMod/MetadataEditorBox.cs \
PdfMod/Page.cs \
+ PdfMod/PageLabels.cs \
PdfMod/PageThumbnail.cs \
PdfMod/PdfIconView.cs \
PdfMod/PdfListStore.cs \
diff --git a/src/PdfMod/PdfMod.mdp b/src/PdfMod/PdfMod.mdp
index b13736d..e020204 100644
--- a/src/PdfMod/PdfMod.mdp
+++ b/src/PdfMod/PdfMod.mdp
@@ -37,6 +37,7 @@
<File name="PdfMod.Actions/MoveAction.cs" subtype="Code" buildaction="Compile" />
<File name="PdfMod/MetadataEditorBox.cs" subtype="Code" buildaction="Compile" />
<File name="PdfMod/PageThumbnail.cs" subtype="Code" buildaction="Compile" />
+ <File name="PdfMod/PageLabels.cs" subtype="Code" buildaction="Compile" />
</Contents>
<References>
<ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
diff --git a/src/PdfMod/PdfMod/Document.cs b/src/PdfMod/PdfMod/Document.cs
index 26343de..0d46740 100644
--- a/src/PdfMod/PdfMod/Document.cs
+++ b/src/PdfMod/PdfMod/Document.cs
@@ -16,8 +16,10 @@ namespace PdfMod
private List<Page> pages = new List<Page> ();
private string tmp_path;
private string tmp_uri;
+ private PageLabels page_labels;
internal string CurrentStateUri { get { return tmp_uri ?? Uri; } }
+ public PageLabels Labels { get { return page_labels; } }
public string SuggestedSavePath { get; set; }
public string Uri { get; private set; }
public string Path { get; private set; }
@@ -130,6 +132,7 @@ namespace PdfMod
pages.Add (page);
}
+ page_labels = new PageLabels (pdf_document);
ExpireThumbnails (pages);
OnChanged ();
}
diff --git a/src/PdfMod/PdfMod/PageLabels.cs b/src/PdfMod/PdfMod/PageLabels.cs
new file mode 100644
index 0000000..8a3f492
--- /dev/null
+++ b/src/PdfMod/PdfMod/PageLabels.cs
@@ -0,0 +1,274 @@
+//Author: Michael McKinley (m mckinley gmail com)
+
+using System;
+using System.Linq;
+using System.Text;
+using System.Collections.Generic;
+
+using PdfSharp;
+using PdfSharp.Pdf;
+using PdfSharp.Pdf.Advanced;
+using System;
+
+namespace PdfMod
+{
+ struct PageLabelFormat
+ {
+ public string number_style;
+ public string prefix;
+ public int first_number;
+ }
+
+ public class PageLabels
+ {
+ private const string name_labels = "/PageLabels";
+ private const string name_numtree = "/Nums";
+
+ //Keys (PdfNames) for formatting attributes
+ private const string name_fmt = "/S";
+ private const string name_start_at = "/St";
+ private const string name_prefix = "/P";
+
+ //Possible values for the numbering style
+ private const string alpha_upper = "/A";
+ private const string alpha_lower = "/a";
+ private const string roman_upper = "/R";
+ private const string roman_lower = "/r";
+ private const string arabic = "/D";
+
+ private SortedDictionary<int, PageLabelFormat> page_labels;
+ private PdfDictionary.DictionaryElements pdf_elements;
+ private PdfDocument pdf_document;
+ private bool edited;
+
+ public string this[Page page] { get { return this[page.Index]; } }
+
+ public string this[int index]
+ {
+ get
+ {
+ if (index < 0 || index > pdf_document.PageCount) {
+ throw new IndexOutOfRangeException();
+ }
+
+ if (page_labels.Count == 0) {
+ return null;
+ }
+
+ int range_base = GetFormat (index);
+ try {
+ PageLabelFormat cur_format = page_labels[range_base];
+ string label = cur_format.prefix;
+
+ //Restart numbering for each range of pages
+ int vindex = index + cur_format.first_number - range_base;
+
+ if (cur_format.number_style == roman_upper || cur_format.number_style == alpha_upper) {
+ label += RenderVal (vindex, cur_format.number_style).ToUpper ();
+ } else {
+ label += RenderVal (vindex, cur_format.number_style).ToLower ();
+ }
+ return label;
+ } catch (KeyNotFoundException e) {
+ return (1 + index).ToString ();
+ }
+ return (1 + index).ToString ();
+ }
+ }
+
+ internal PageLabels (PdfDocument document)
+ {
+ page_labels = new SortedDictionary<int, PageLabelFormat>();
+ pdf_elements = document.Internals.Catalog.Elements;
+ pdf_document = document;
+ edited = false;
+
+ //Ignore documents that don't have labelling stuff defined
+ if (!pdf_elements.Contains (name_labels)) {
+ return;
+ }
+
+ //Ignore documents that don't have a properly-defined PageLabelFmt section
+ PdfDictionary my_labels = pdf_elements.GetDictionary (name_labels);
+ if (!my_labels.Elements.Contains (name_numtree)) {
+ return;
+ }
+
+ /* The number tree (not my term) is a PdfArray arranged as follows: [##, dict, ##, dict, ##, dict ...]
+ * ## represents the starting index of the page (0-based) and the following dict is a PdfDictionary
+ * containing formatting information regarding the range
+ */
+
+ PdfArray number_tree = my_labels.Elements.GetArray (name_numtree);
+
+ for (int i = 0; i < number_tree.Elements.Count / 2; ++i) {
+ Console.WriteLine ("Range # {0}", i);
+ PageLabelFormat temp_label = new PageLabelFormat ();
+
+ int range_start = number_tree.Elements.GetInteger (i * 2);
+ PdfDictionary label_data = number_tree.Elements.GetDictionary (i * 2 + 1);
+
+ //Set the prefix, default to ""
+ if (label_data.Elements.Contains (name_prefix)) {
+ temp_label.prefix = label_data.Elements.GetString (name_prefix);
+ } else {
+ temp_label.prefix = "";
+ }
+
+ //Set the start number, default to 1
+ if (label_data.Elements.Contains (name_start_at)) {
+ temp_label.first_number = label_data.Elements.GetInteger (name_start_at);
+ } else {
+ temp_label.first_number = 1;
+ }
+
+ //Set the format type, default to no numbering (only show the prefix)
+ if (label_data.Elements.Contains (name_fmt)) {
+ temp_label.number_style = label_data.Elements.GetString (name_fmt);
+ } else {
+ temp_label.number_style = "";
+ }
+
+ page_labels.Add (range_start, temp_label);
+ }
+ }
+
+ //Determine which formatting rules apply to page index. Returns the start of the formatting range
+ private int GetFormat (int index)
+ {
+ //Todo: find the correct range using a binary search
+ SortedDictionary<int, PageLabelFormat>.KeyCollection ranges = page_labels.Keys;
+
+ int last = -1;
+ foreach (int range_start in ranges) {
+ if (range_start > index) break;
+ last = range_start;
+ }
+ return last;
+ }
+
+ //Render the value index in the proper format (case-agnostic)
+ private string RenderVal (int index, string fmt)
+ {
+ if (arabic == fmt) {
+ return index.ToString ();
+ } else if (roman_upper == fmt || roman_lower == fmt) {
+ return ToRoman (index);
+ } else if (alpha_lower == fmt || alpha_upper == fmt) {
+ return ToAlpha (index);
+ } else {
+ return "";
+ }
+ }
+
+ //Convert val into Roman numerals
+ private string ToRoman (int val)
+ {
+ StringBuilder roman_val = new StringBuilder ();
+ //TODO: see if there's a more elegant conversion
+
+ if (val >= 1000) {
+ roman_val.Append ('M', val / 1000);
+ val -= (1000 * (val / 1000));
+ }
+ if (val >= 900) {
+ roman_val.Append ("CM");
+ val -= 900;
+ }
+ if (val >= 500) {
+ roman_val.Append ('D', val / 500);
+ val -= (500 * (val / 500));
+ }
+ if (val >= 400) {
+ roman_val.Append ("CD");
+ val -= 400;
+ }
+ if (val >= 100) {
+ roman_val.Append ('C', val / 100);
+ val -= (100 * (val / 100));
+ }
+ if (val >= 90) {
+ roman_val.Append ("XC");
+ val -= 90;
+ }
+ if (val >= 50) {
+ roman_val.Append ('L', val / 50);
+ val -= (50 * (val / 50));
+ }
+ if (val >= 40) {
+ roman_val.Append ("XL");
+ val -= 40;
+ }
+ if (val >= 10) {
+ roman_val.Append ('X', val / 10);
+ val -= (10 * (val / 10));
+ }
+ if (val >= 9) {
+ roman_val.Append ("IX");
+ val -= 9;
+ }
+ if (val >= 5) {
+ roman_val.Append ('V', val / 5);
+ val -= (5 * (val / 5));
+ }
+ if (val >= 4) {
+ roman_val.Append ("IV");
+ val -= 4;
+ }
+ roman_val.Append ('I', val);
+ return roman_val.ToString ();
+ }
+
+ //Convert val into the alpha representation. 1 -> a, 2 -> b, ... 26 -> z, 27 -> aa, 28 -> bb, etc.
+ private string ToAlpha (int val)
+ {
+ char letter = (char)((val - 1) % 26 + 'a');
+ int rep_count = (val - 1)/26 + 1;
+ StringBuilder s = new StringBuilder (rep_count);
+ s.Append (letter, rep_count);
+ return s.ToString ();
+ }
+
+ //Write labels to the PDF
+ internal void WriteLabels ()
+ {
+ if (!edited) {
+ return;
+ }
+
+ //Grab the labels element, creating it if necessary
+ PdfDictionary labels_dict;
+ if (!pdf_elements.Contains (name_labels)) {
+ labels_dict = new PdfDictionary (pdf_document);
+ pdf_elements.Add (new PdfName (name_labels), labels_dict);
+ } else {
+ labels_dict = pdf_elements.GetDictionary (name_labels);
+ }
+ labels_dict.Elements.Clear ();
+
+ //Create the number tree
+ PdfArray number_tree = new PdfArray (pdf_document);
+
+ //Add the range-start, attrib-dict pairs
+ foreach (int range_start in page_labels.Keys)
+ {
+ number_tree.Elements.Add (new PdfInteger (range_start));
+ PageLabelFormat label_format = page_labels[range_start];
+ PdfDictionary r_attribs = new PdfDictionary (pdf_document);
+
+ if (label_format.number_style.Length > 0) {
+ r_attribs.Elements.Add (new PdfName (name_fmt), new PdfName (label_format.number_style));
+ }
+ if (label_format.first_number > 1) {
+ r_attribs.Elements.Add (new PdfName (name_start_at), new PdfInteger (label_format.first_number));
+ }
+ if (label_format.prefix.Length > 0) {
+ r_attribs.Elements.Add (new PdfName (name_prefix), new PdfString (label_format.prefix));
+
+ }
+ number_tree.Elements.Add (r_attribs);
+ }
+ labels_dict.Elements.Add (new PdfName (name_numtree), number_tree);
+ }
+ }
+}
diff --git a/src/PdfMod/PdfMod/PdfListStore.cs b/src/PdfMod/PdfMod/PdfListStore.cs
index 145e7aa..8800211 100644
--- a/src/PdfMod/PdfMod/PdfListStore.cs
+++ b/src/PdfMod/PdfMod/PdfListStore.cs
@@ -48,21 +48,24 @@ namespace PdfMod
}
}
}
-
+
+ private string GetPageTooltip (Page page)
+ {
+ var label = page.Document.Labels[page];
+ string page_no = Catalog.GetString (String.Format ("Page {0}", page.Index + 1));
+ return ((null == label) ? page_no : String.Format ("{0} ({1})", label, page_no));
+ }
+
public void UpdateForPage (TreeIter iter, Page page)
{
SetValue (iter, SortColumn, page.Index);
- SetValue (iter, TooltipColumn, String.Format (Catalog.GetString ("Page {0}"), page.Index + 1));
+ SetValue (iter, TooltipColumn, GetPageTooltip(page));
SetValue (iter, PageColumn, page);
}
internal object [] GetValuesForPage (Page page)
{
- return new object[] {
- page.Index,
- String.Format (Catalog.GetString ("Page {0}"), page.Index + 1),
- page
- };
+ return new object[] { page.Index, GetPageTooltip(page), page };
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]