Hyperlinks are lost when using PDFsharp to concatenate multiple PDFs - pdfsharp

When using PDFsharp (v1.5x) to concatenate multiple PDF files, hyperlinks that exist in the source files are lost.

The links need to be manually recreated in the composite file. Run this method each time you add a new PdfPage object to the target document.
private void FixWebLinkAnnotations(PdfPage page, PdfDocument doc, int docPage)
{
for (var i = 0; i < page.Annotations.Count; i++)
{
var annot = page.Annotations[i];
var subType = annot.Elements.GetString(PdfAnnotation.Keys.Subtype);
if (subType == "/Link")
{
var dest = annot.Elements.GetDictionary(PdfAnnotation.Keys.A);
var rect = annot.Elements.GetRectangle(PdfAnnotation.Keys.Rect);
if (dest != null && rect != null && dest.Elements.Count > 0)
{
var uri = dest.Elements.GetString("/URI");
for (var p = 0; p < doc.PageCount; p++)
{
if (p == docPage && uri != null)
{
doc.Pages[docPage].Annotations.Add(PdfLinkAnnotation.CreateWebLink(rect, uri));
}
}
}
}
}
}
This code was adapted from https://forum.pdfsharp.net/viewtopic.php?f=3&t=3382 to work with hyperlinks rather than document references.

Related

using futures with flutter maps

I have this code which is supposed to loop through images to upload them to firebase, then take their links and put it inside the Product class so the product can have its images link. Then, upload the product too.
The problem is it doesn't wait for the upload to happen to insert its links to the product.
Code
List<String> imgUrls = [];
Future<void> loopThroughMap()async{
_map.forEach((storedImage, inGallery) async {
if (!inGallery && storedImage != null && storedImage.path != null) {
await GallerySaver.saveImage(storedImage.path);
}
String urlString = await FirestoreHelper.uploadImage(storedImage);
imgUrls.add(urlString);
});
}
This function is called in here
`
await loopThroughMap();
print('FINISHED THIS ONE, imgs Urls length ${imgUrls.length}');
for (int i = 0; i < imgUrls.length; i++) {
if (i == 0)
_editedProduct.imageUrl = imgUrls[i];
else if (i == 1)
_editedProduct.imageUrl2 = imgUrls[i];
else if (i == 2)
_editedProduct.imageUrl3 = imgUrls[i];
else if (i == 3) _editedProduct.imageUrl4 = imgUrls[i];
}`
The imgUrls list length is ALWAYS zero.
Could it be a problem with the map.foreach?
Ok, I changed the uploading from the ForEach loop to a for loop, and it works fine!
List<File> _listedImages = [];
Future<void> loopThroughMap(){
_map.forEach((storedImage, inGallery) async {
if (!inGallery && storedImage != null && storedImage.path != null) {
GallerySaver.saveImage(storedImage.path);
}
_listedImages.add(storedImage);
});
}
/////
for(var img in _listedImages){
String url = await FirestoreHelper.uploadImage(img);
imgUrls.add(url);
}
After a lot of iterations, the only variable that was causing the error was the ForEach loop.

DotNetZip - [wildcard.png]

Can you extract on a wildcard?
I can see that you can when zipping up files? I will not know the name of the files within the zipped folder, however the type will always be .png and there will only ever be one png file.
i.e.
using (var ms = new MemoryStream())
{
var entry = zipout["*.png"];
if (entry != null)
{
entry.Extract(ms);
}
else
{
return;
}
}
using (var zipout = ZipFile.Read(stream))
{
using (var ms = new MemoryStream())
{
foreach (var e in zipout.Where(e => e.FileName.Contains(".png")))
{
e.Extract(ms);
}
}
}

set control ID using string.concat

i've some code in c#, in which there are many lines of code where the ID of a control is set by string.concat. For ex:
private genericControl ctrlGrid;
genericControl = Page.LoadControl(obj);
genericControl.ID = string.concat("gridControl");
Can there be any specific reasons for setting the ID using string.concat?
Can there be any performance hit associated with this?
I think you should use just:
genericControl.ID = "gridControl";
EDIT:
Take a look at string.Concat() method that will be used when you are passing one parameter:
public static string Concat(params string[] values)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
int totalLength = 0;
string[] strArray = new string[values.Length];
for (int i = 0; i < values.Length; i++)
{
string str = values[i];
strArray[i] = (str == null) ? Empty : str;
totalLength += strArray[i].Length;
if (totalLength < 0)
{
throw new OutOfMemoryException();
}
}
return ConcatArray(strArray, totalLength);
}
So yes, it has performance overhead and better to use just string.

How to get a substring from a string variable which is having HTML tags

I have a string variable assigned with some Content in HTML format.
Some thing like this var strLabel:String = "This is <b>Test</b>;
But in run time i have get the first 10 characters of the string and display it in another control.
For this, what did was
txtLabelName.Text = String(strLabel).substr(0,10) + ' ...';
But in the output i am getting as This is <b. Basically it considering HTML related tags also as text. But my code has to omit the HTML tags while calculating sub string.
Please anybody help me to do this?
Use this regexp to strip html tags (more or less):
txtLabelName.text = strLabel.replace(/\<.+?\>/g, '').substr(0, 10) + ' ...';
It's a very simple regexp to strip all tags so it won't work on more complex tags (probably).
I got this code from some blog. This is working Perfectly
public static function stripHtmlTags(html:String, tags:String = ""):String
{
var tagsToBeKept:Array = new Array();
if (tags.length > 0)
tagsToBeKept = tags.split(new RegExp("\\s*,\\s*"));
var tagsToKeep:Array = new Array();
for (var i:int = 0; i < tagsToBeKept.length; i++)
{
if (tagsToBeKept[i] != null && tagsToBeKept[i] != "")
tagsToKeep.push(tagsToBeKept[i]);
}
var toBeRemoved:Array = new Array();
var tagRegExp:RegExp = new RegExp("<([^>\\s]+)(\\s[^>]+)*>", "g");
var foundedStrings:Array = html.match(tagRegExp);
for (i = 0; i < foundedStrings.length; i++)
{
var tagFlag:Boolean = false;
if (tagsToKeep != null)
{
for (var j:int = 0; j < tagsToKeep.length; j++)
{
var tmpRegExp:RegExp = new RegExp("<\/?" + tagsToKeep[j] + "( [^<>]*)*>", "i");
var tmpStr:String = foundedStrings[i] as String;
if (tmpStr.search(tmpRegExp) != -1)
tagFlag = true;
}
}
if (!tagFlag)
toBeRemoved.push(foundedStrings[i]);
}
for (i = 0; i < toBeRemoved.length; i++)
{
var tmpRE:RegExp = new RegExp("([\+\*\$\/])","g");
var tmpRemRE:RegExp = new RegExp((toBeRemoved[i] as String).replace(tmpRE, "\\$1"),"g");
html = html.replace(tmpRemRE, "");
}
return html;
}

In AS3/Flex, how can I get from flat data to hierarchical data?

I have some data that gets pulled out of a database and mapped to an arraycollection. This data has a field called parentid, and I would like to map the data into a new arraycollection with hierarchical information to then feed to an advanced data grid.
I think I'm basically trying to take the parent object, add a new property/field/variable of type ArrayCollection called children and then remove the child object from the original list and clone it into the children array? Any help would be greatly appreciated, and I apologize ahead of time for this code:
private function PutChildrenWithParents(accountData : ArrayCollection) : ArrayCollection{
var pos_inner:int = 0;
var pos_outer:int = 0;
while(pos_outer < accountData.length){
if (accountData[pos_outer].ParentId != null){
pos_inner = 0;
while(pos_inner < accountData.length){
if (accountData[pos_inner].Id == accountData[pos_outer].ParentId){
accountData.addItemAt(
accountData[pos_inner] + {children:new ArrayCollection(accountData[pos_outer])},
pos_inner
);
accountData.removeItemAt(pos_outer);
accountData.removeItemAt(pos_inner+1);
}
pos_inner++;
}
}
pos_outer++;
}
return accountData;
}
I had a similar problem with a hierarchical task set which was slightly different as it has many root elements, this is what i did, seems good to me:
public static function convertFlatTasks(tasks:Array):Array
{
var rootItems:Array = [];
var task:TaskData;
// hashify tasks on id and clear all pre existing children
var taskIdHash:Array = [];
for each (task in tasks){
taskIdHash[task.id] = task;
task.children = [];
task.originalChildren = [];
}
// loop through all tasks and push items into their parent
for each (task in tasks){
var parent:TaskData = taskIdHash[task.parentId];
// if no parent then root element, i.e push into the return Array
if (parent == null){
rootItems.push(task);
}
// if has parent push into children and originalChildren
else {
parent.children.push(task);
parent.originalChildren.push(task);
}
}
return rootItems;
}
Try this:
AccountData:
public class AccountData
{
public var Id:int;
public var ParentId:int;
public var children:/*AccountData*/Array;
public function AccountData(id:int, parentId:int)
{
children = [];
this.Id = id;
this.ParentId = parentId;
}
}
Code:
private function PutChildrenWithParents(accountData:ArrayCollection):AccountData
{
// dummy data for testing
//var arr:/*AccountData*/Array = [new AccountData(2, 1),
// new AccountData(1, 0), // root
// new AccountData(4, 2),
// new AccountData(3, 1)
// ];
var arr:/*AccountData*/Array = accountData.source;
var dict:Object = { };
var i:int;
// generate a lookup dictionary
for (i = 0; i < arr.length; i++)
{
dict[arr[i].Id] = arr[i];
}
// root element
dict[0] = new AccountData(0, 0);
// generate the tree
for (i = 0; i < arr.length; i++)
{
dict[arr[i].ParentId].children.push(arr[i]);
}
return dict[0];
}
dict[0] holds now your root element.
Maybe it's doesn't have the best possible performance but it does what you want.
PS: This code supposes that there are no invalid ParentId's.
Here's what I ended up doing, apparently you can dynamically add new properties to an object with
object['new_prop'] = whatever
From there, I used a recursive function to iterate through any children so you could have n levels of the hierarchy and if it found anything it would pass up through the chain by reference until the original function found it and acted on it.
private function PutChildrenWithParents(accountData : ArrayCollection) : ArrayCollection{
var pos_inner:int = 0;
var pos_outer:int = 0;
var result:Object = new Object();
while(pos_outer < accountData.length){
if (accountData[pos_outer].ParentId != null){
pos_inner = 0;
while(pos_inner < accountData.length){
result = CheckForParent(accountData[pos_inner],
accountData[pos_outer].ParentId);
if ( result != null ){
if(result.hasOwnProperty('children') == false){
result['children'] = new ArrayCollection();
}
result.children.addItem(accountData[pos_outer]);
accountData.removeItemAt(pos_outer);
pos_inner--;
}
pos_inner++;
}
}
pos_outer++;
}
return accountData;
}
private function CheckForParent(suspectedParent:Object, parentId:String) : Object{
var parentObj:Object;
var counter:int = 0;
if ( suspectedParent.hasOwnProperty('children') == true ){
while (counter < suspectedParent.children.length){
parentObj = CheckForParent(suspectedParent.children[counter], parentId);
if (parentObj != null){
return parentObj;
}
counter++;
}
}
if ( suspectedParent.Id == parentId ){
return suspectedParent;
}
return null;
}

Resources