Skip to content

Commit

Permalink
Merge pull request #10 from aMytho/tag-inspector
Browse files Browse the repository at this point in the history
Add Tag inspector
  • Loading branch information
aMytho authored Feb 10, 2024
2 parents 88715d4 + c4410f0 commit bc2634c
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 117 deletions.
137 changes: 137 additions & 0 deletions Pages/Inspector/Nodes/TagNode.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
@* Copyright (C) Jonathan Shull - See license file at github.com/amytho/pdf-acc-toolset *@

@using iText.Kernel.Pdf.Tagutils;
@using Pdf_Acc_Toolset.Services.Util;
@using iText.Kernel.Pdf.Tagging;
@using iText.Kernel.Pdf;
@using iText.Layout;
@using Pdf_Acc_Toolset.Services.UI;

<div class="p-2 border border-l-2 border-y-0 border-r-0 border-solid border-gray-500"
@oncontextmenu:stopPropagation="true" @oncontextmenu:preventDefault="true" @oncontextmenu="ShowTagInfo">
<div class="flex flex-row p-1">
<div>
<button @onclick:stopPropagation="true" @onclick:preventDefault="true" @onclick="toggleKids"
class="cursor-pointer border border-solid border-gray-900 p-1 text-lg font-semibold" title="Toggle Children">@ShowHideBtn()</button>
</div>
<p class="ml-2"> @GetTagType() @GetTitle()</p>
</div>

<div class="ml-1 @ShowChildrenClass()">
@foreach (TagTreePointer tag in GetChildren())
{
<div class="m-2">
<TagNode node="tag" />
</div>
}
</div>
</div>


@code {
[Parameter]
public TagTreePointer node { get; set; }

private bool showKids = true;

private string GetTagType()
{
// Returns the tag name in the role mapped form
return TagUtil.ConvertRole(new PdfName(node.GetRole()));
}

private bool HasChildTag()
{
return node.GetKidsRoles().Count != 0;
}

private IList<TagTreePointer> GetChildren()
{
// List which will be returned with the tags
List<TagTreePointer> matchingTags = new();

// Start looking
CheckChildElement(node);

// Recursive function to check all tags in the tag tree
void CheckChildElement(TagTreePointer children)
{
// Create a copy of the current tag
PdfStructElem currentTag = children.GetContext().GetPointerStructElem(children);

// Get each child
IList<IStructureNode> kids = currentTag.GetKids();

// Check each child
if (kids != null && kids.Count > 0)
{
for (int i = 0; i < kids.Count; i++)
{
// If the kid is null or content, skip it
if (kids[i] == null || kids[i].GetType() != typeof(PdfStructElem))
{
continue;
}

// Store a copy to check children
PdfStructElem elem = children.GetContext().GetPointerStructElem(children);
TagTreePointer childPointer = children.GetContext().CreatePointerForStructElem(elem);
matchingTags.Add(childPointer.MoveToKid(i));
}
}
}

// Return result
return matchingTags;
}

private void toggleKids()
{
this.showKids = !this.showKids;
}

private string GetTitle()
{
AccessibilityProperties properties = node.GetProperties();
PdfObject titleObject = node.GetContext().GetPointerStructElem(node).GetPdfObject().Get(PdfName.T);
if (titleObject is not null) {
return titleObject.ToString();
}
return "";
}

private void ShowTagInfo()
{
AccessibilityProperties properties = node.GetProperties();
string actualText = properties.GetActualText();
string altText = properties.GetAlternateDescription();
string title = GetTitle();
byte[] idArray = properties.GetStructureElementId();

if (idArray is null || idArray.Length == 0) {
TagInspectorService.NotifyTagSelection(null, altText, actualText, null, title);
} else {
TagInspectorService.NotifyTagSelection(null, altText, actualText, idArray.ToString(), title);
}
}

private string ShowHideBtn()
{
if (showKids) {
return "v";
} else {
return "...";
}
}

private string ShowChildrenClass() {
// Return a hidden css class if kids are supposed to be hidden
// TO-DO: This seems to run for every child when a parent changes visibility.
// This is very bad for performance.
if (showKids) {
return "";
} else {
return "hidden";
}
}
}
16 changes: 16 additions & 0 deletions Pages/Inspector/TagInspector.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@* Copyright (C) Jonathan Shull - See license file at github.com/amytho/pdf-acc-toolset *@
<div class="top relative flex bg-slate-700 rounded-b-md p-2">
<button class="ml-auto" @onclick="CloseInspector">Close</button>
</div>

@if (!pdfVisible) {
<p class="ml-2 mt-2 text-lg text-red-500">
You must upload a PDF before you can view the current tag tree.
</p>
}

@if (pdfVisible) {
<div class="p-4">
<Pdf_Acc_Toolset.Pages.Inspector.Nodes.TagNode node="GetTagTree()" />
</div>
}
47 changes: 47 additions & 0 deletions Pages/Inspector/TagInspector.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (C) Jonathan Shull - See license file at github.com/amytho/pdf-acc-toolset
using Microsoft.AspNetCore.Components;
using Pdf_Acc_Toolset.Services;
using Pdf_Acc_Toolset.Services.UI;


namespace Pdf_Acc_Toolset.Pages.Inspector;

public partial class TagInspector
{
[Parameter]
public EventCallback<int> OnCloseInspector { get; set; }

private bool pdfVisible = false;

protected override void OnInitialized()
{
TagInspectorService.PdfReady += OnPdfReady;
TagInspectorService.PdfClosed += OnPdfClosed;

if (PdfManager.outFile != null) {
pdfVisible = true;
}
base.OnInitialized();
}

private void OnPdfReady()
{
Console.WriteLine("Tag View Created");
this.pdfVisible = true;
}

private void OnPdfClosed(object sender, EventArgs e)
{
this.pdfVisible = false;
}

private void CloseInspector()
{
this.OnCloseInspector.InvokeAsync();
}

private iText.Kernel.Pdf.Tagutils.TagTreePointer GetTagTree()
{
return PdfManager.GetTagRoot();
}
}
44 changes: 44 additions & 0 deletions Pages/Inspector/TagViewer.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@* Copyright (C) Jonathan Shull - See license file at github.com/amytho/pdf-acc-toolset *@

@using Pdf_Acc_Toolset.Services.UI;

@if (@Tag is not null)
{
<p class="text-lg font-semibold">
Tag info
</p>
@if (Tag.Title.Length != 0) {
<p class="mt-2">Title: @Tag.Title</p>
} else {
<p class="mt-2">Title: None</p>
}
<p>Alt Text: @Tag.AltText</p>
<p>Actual Text: @Tag.ActualText</p>
<p>ID: @Tag.ID</p>
}
else
{
<p class="text-lg font-semibold text-red-500">
No Tag Selected
</p>
<p class="font-semibold">Right-click a tag to view its properties.</p>
}


@code {

private UserTagSelection Tag { get; set; }

protected override void OnInitialized()
{
TagInspectorService.TagSelected += OnTagUpdated;
base.OnInitialized();
}

private void OnTagUpdated(object sender, UserTagSelection tag)
{
this.Tag = tag;
StateHasChanged();
}
}

4 changes: 4 additions & 0 deletions Pages/Save.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.JSInterop;
using Pdf_Acc_Toolset.Services;
using Pdf_Acc_Toolset.Services.Pdf;
using Pdf_Acc_Toolset.Services.UI;
using Pdf_Acc_Toolset.Services.Util;

namespace Pdf_Acc_Toolset.Pages;
Expand Down Expand Up @@ -69,6 +70,9 @@ private async void SavePdf()
return;
}

// Close Tag Inspector
TagInspectorService.NotifyPdfClose();

// Save the PDF
PdfManager.Save();
Console.WriteLine("Saving the PDF");
Expand Down
5 changes: 1 addition & 4 deletions Pages/Tools/helpers/PdfColor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@foreach (Color color in Colors)
{
<button class="w-10 h-8 rounded-sm" style="background-color: rgb(@GetDisplayableColor(color));"
@onclick="() => EmitColor(color)">
@onclick="() => EmitColor(color)" type="button">
</button>
}
</div>
Expand All @@ -25,9 +25,6 @@
{
// Convert to RGB from any color space
float[] rgb = ColorUtil.ConvertColorToRgb(color);
Console.WriteLine(rgb[0]);
Console.WriteLine(rgb[1]);
Console.WriteLine(rgb[2]);
// Return the RGB value of each. We multiple by 255 because the current val is a decimal < 1
// CSS expects an int from 0-255
return $"{rgb[0] * 255},{rgb[1] * 255},{rgb[2] * 255}";
Expand Down
2 changes: 2 additions & 0 deletions Services/PdfManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using iText.Kernel.Pdf.Tagutils;
using iText.Layout;
using Pdf_Acc_Toolset.Services.Pdf;
using Pdf_Acc_Toolset.Services.UI;
using Pdf_Acc_Toolset.Services.Util;

namespace Pdf_Acc_Toolset.Services;
Expand Down Expand Up @@ -134,6 +135,7 @@ public static void SetOutputFile(Stream input, PdfImportConfig conf)
// Allow it to be downloaded
pdfDownloadable = true;
hasDownloaded = false;
TagInspectorService.NotifyPdfReady();
}

/// <summary>
Expand Down
33 changes: 33 additions & 0 deletions Services/UI/TagInspectorService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (C) Jonathan Shull - See license file at github.com/amytho/pdf-acc-toolset
namespace Pdf_Acc_Toolset.Services.UI;

public class TagInspectorService
{
public static event Action PdfReady;
public static EventHandler PdfClosed; // This must be an event handler since it is synchronous
public static EventHandler<UserTagSelection> TagSelected { get; set; }

public static void NotifyPdfReady()
{
PdfReady?.Invoke();
}

public static void NotifyPdfClose()
{
PdfClosed?.Invoke(null, null);
}

public static void NotifyTagSelection(string tagType, string altText, string actualText, string id, string title)
{
TagSelected.Invoke(null, new UserTagSelection(tagType, altText, actualText, id, title));
}
}

public class UserTagSelection(string tagType, string altText, string actualText, string id, string title)
{
public string TagType = tagType ?? "None";
public string AltText = altText ?? "None";
public string ActualText = actualText ?? "None";
public string ID = id ?? "None";
public string Title = title ?? "None";
}
33 changes: 0 additions & 33 deletions Services/UI/TocService.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Shared/Badge.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@* Copyright (C) Jonathan Shull - See license file at github.com/amytho/pdf-acc-toolset *@
<div class="rounded-full font-semibold py-1 px-2 leading-normal bg-blue-600 hover:bg-blue-500 m-1">
<div class="rounded-full font-semibold py-1 px-2 leading-normal bg-blue-600 hover:bg-blue-500 m-1 w-min">
<p>@content</p>
</div>

Expand Down
Loading

0 comments on commit bc2634c

Please sign in to comment.