How to enable annotation in PDFJS viewer - pdf.js

I am using PDFJS and the viewer. I do however have the problem that annotation are not shown correctly like the are in the pdfs demo viewer https://mozilla.github.io/pdf.js/web/viewer.html.
Annotation correctly displayed in pdfs demo viewer:
Here is now it is displayed in my app using Chrome:
Here is how it is displayed I Safari using my app:
This is now I initialise the pdfs viewer:
function initPdfjs() {
// Enable hyperlinks within PDF files.
pdfLinkService = new (pdfjsViewer as any).PDFLinkService({
eventBus,
});
// Enable find controller.
pdfFindController = new (pdfjsViewer as any).PDFFindController({
eventBus,
linkService: pdfLinkService,
});
const container = document.getElementById('viewerContainer');
if (container) {
// Initialize PDFViewer
pdfViewer = new (pdfjsViewer as any).PDFViewer({
eventBus,
container,
removePageBorders: true,
linkService: pdfLinkService,
findController: pdfFindController,
});
// pdfViewer.textLayerMode = Utils.enableTextSelection() ? TextLayerMode.ENABLE : TextLayerMode.DISABLE;
pdfViewer.textLayerMode = TextLayerMode.ENABLE_ENHANCE;
// See https://github.com/mozilla/pdf.js/issues/11245
if (Utils.isIos()) {
pdfViewer.maxCanvasPixels = 4000 * 4000;
}
pdfLinkService.setViewer(pdfViewer);
return;
} else {
console.error(`getElementById('viewerContainer') failed`);
}
}
What do I need to do in order to get the annotations to display correctly in my app?

I got it working. I don't know if it is the right way, but I post it in case somebody can use it.
First I setup webpack to copy the content from ./node_modules/pdfjs-dist/web/images to my dist folder so the images got included. That solved all the display errors except {{date}}, {{time}}.
new CopyPlugin({
patterns: [
{ from: './node_modules/pdfjs-dist/web/images', to: '' },
{ from: './l10n', to: 'l10n' },
],
}),
To solve the {{date}}, {{time}} problem I set up a localisation service. I did that by copying the file ng2-pdfjs-viewer-master/pdfjs/web/locale/en-US/viewer.properties to ./l10n/local.properties in my project. Then it is copied to the dist folder by above webpack plugin. I then setup the l10n service in my pdfjs by adding this code:
// initialize localization service, so time stamp in embedded comments are shown correctly
l10n = new (pdfjsViewer as any).GenericL10n('en-US');
const dir = await l10n.getDirection();
document.getElementsByTagName('html')[0].dir = dir;
and added l10n to PDFViewer initialisation:
// Initialize PDFViewer
pdfViewer = new (pdfjsViewer as any).PDFViewer({
eventBus,
container,
removePageBorders: true,
linkService: pdfLinkService,
findController: pdfFindController,
l10n,
});
And now annotations is shown correctly:
What I find a bit weird is the date format. I used en-US as locale, so I would expect it to be mm/dd/yyyy (American way), but it is dd/mm/yyyy (like a dane would prefer it). I have tried to fool around with the date settings on my Mac and language settings in Chrome, but it doesn't look like it has any effect, so I don't know what to do if an American customer complains.

Related

Flutter/Dart overwriting File in getApplicationDocumentsDirectory not working immediately

I'm trying to overwrite a file in my apps temporary directory but for some reason the overwrite is not taking effect until I fully hot restart my app.
I'm trying to set my _pickedImage variable to the new changedImage once it has been copied to the directory, however when using setState it is always keeping the first image that was placed into the directory and not overwriting it each time. So when I display the _pickedImage it will always show the first initial image until i fully restart, once i fully restart the app the change is taking place. The reason for wanting to do this is so that users can effectively change the image if they wish. Hope this makes sense any help would be massively appreciated
var image = await ImagePicker.pickImage(source: source, maxWidth: 800.0);
if (image != null) {
final Directory extDir = await getApplicationDocumentsDirectory();
final String dirPath = '${extDir.path}/image';
if (Directory(dirPath).existsSync()) {
print('it exists');
var dir = new Directory(dirPath);
dir.deleteSync(recursive: true);
if (Directory(dirPath).existsSync()) {
print('still exists');
} else {
//It is getting in here so seemingly its deleting the orignal directory
print('does not exist');
}
}
new Directory(dirPath).createSync(recursive: true);
String path =
'$dirPath/temporaryImage.jpg';
File changedImage = image.copySync(path);`
setState(() {
//this is where the problem lies
_pickedImage = changedImage;
});
Cache is the problem. See issue https://github.com/flutter/flutter/issues/24858
From documentation https://api.flutter.dev/flutter/painting/ImageProvider-class.html
ImageProvider uses the global imageCache to cache images.
You can use
import 'package:flutter/painting.dart'
// to clear specific cache
imageCache.evict(FileImage(processedImage));
// to clear all cache
imageCache.clear();
It did not directly solve issue I had, however, it was the key.

Replace UIWebView's (loaded through a web service) <img> tag source with a local (cached) source

I am working on an app (swift) where i need to load a web page inside UIWebView. Inside that UIWebView there's an <img src="http://www.example.com/uploads/43454.jpg" /> element.
All works fine in this scenario, but the problem is that my 43454.jpg image can be of 5-10 megabytes everytime. So when the UIWebView loads it keeps on loading image for about 2 minutes. Plus this <img> tag can have random sources i.e. 22234.jpg, 98734.jpg, 33123.jpg, and so on.
So to tackle this situation I am trying to use following approach:
List all possible images that we need to show in UIWebView, download and cache them (used Kingfisher library for this purpose) at aplication's startup.
When my UIWebView loads my URL initially, it has nothing in it's <img> elements src attribute, but have a data-image-name="22234.jpg" attribute-value pair.
Now when UIWebView finishes loading its contents, get the image name value from data-image-name attribute.
Check for that image in cache, and update the <img> element's src attribute with that image from cache.
This way UIWebView won't be downloading the image over and over again.
Note: Assuming that UIWebView automatically manages resource cache. All other file types *.js, *.css are being properly cached and not being loaded over and over again. The same doesn't go for images, don't know why.
If this approach seems okay, then how should I accomplish it (Swift 2.2)?
Any quick help will be much appreciated. Thanks
This seems to be the same situation in one of my projects. I had exactly this same scenario. I am going to paste my code here, may be it helps you figure out your solution.
As soon as my app loads I create an array of image URLs and pass it to Kingfisher library to download and cache all images (to disk).
for url in response {
let URL = NSURL(string: url as! String)!
self.PlanImagesArray.append(URL)
}
let prefetcher = ImagePrefetcher(
urls: self.PlanImagesArray,
optionsInfo: nil,
progressBlock: {
(skippedResources, failedResources, completedResources) -> () in
print("progress resources are prefetched: \(completedResources)")
print("progress resources are failedResources: \(failedResources)")
print("progress resources are skippedResources: \(skippedResources)")
},
completionHandler: {
(skippedResources, failedResources, completedResources) -> () in
print("These resources are prefetched: \(completedResources)")
print("These resources are failedResources: \(failedResources)")
print("These resources are skippedResources: \(skippedResources)")
self.activityLoadingIndicator.stopAnimating()
})
prefetcher.start()
At my web view screen I initially loaded my web view and after that used following code to check for particular image in cache and if found converted it into a base64 string and put it back in src attribute of the element.
func webViewDidFinishLoad(webView : UIWebView) {
//UIApplication.sharedApplication().networkActivityIndicatorVisible = false
print("webViewDidFinishLoad")
let xlinkHref = webView.stringByEvaluatingJavaScriptFromString("document.getElementById('background_image').getAttribute('xlink:href')")
//print("xlink:href before = \(webView.stringByEvaluatingJavaScriptFromString("document.getElementById('background_image').getAttribute('xlink:href')"))")
if xlinkHref == "" {
let imageCacheKey = webView.stringByEvaluatingJavaScriptFromString("document.getElementById('background_image').getAttribute('data-cache-key')")
let imageCachePath = ImageCache.defaultCache.cachePathForKey(imageCacheKey! as String)
var strBase64:String = ""
webView.stringByEvaluatingJavaScriptFromString(
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
"script.text = \"function setAttributeOnFly(elemName, attName, attValue) { " +
"document.getElementById(elemName).setAttribute(attName, attValue);" +
"}\";" +
"document.getElementsByTagName('head')[0].appendChild(script);"
)!
if(imageCachePath != "") {
ImageCache.defaultCache.retrieveImageForKey(imageCacheKey! as String, options: nil) { (imageCacheObject, imageCacheType) -> () in
let imageData:NSData = UIImageJPEGRepresentation(imageCacheObject!, 100)!
strBase64 = "data:image/jpg;base64," + imageData.base64EncodedStringWithOptions(.EncodingEndLineWithCarriageReturn)
webView.stringByEvaluatingJavaScriptFromString("setAttributeOnFly('background_image', 'xlink:href', '\(strBase64)');")!
}
} else {
webView.stringByEvaluatingJavaScriptFromString("setAttributeOnFly('background_image', 'xlink:href', '\(imageCacheKey)');")!
}
}
Hope it helps.
It sounds like you're basically saying "I know what the images are ahead of time, so I don't want to wait for the UIWebView to load them from the server every time. I want the html to use my local copies instead."
While it's a hack, my first thought was:
Have 2 UIWebViews: one is visible to the user and the other is hidden.
"Trigger" the real page in the hidden UIWebView. When the HTML reaches you...
Create a new string, that is a copy of that HTML, but with the image tags that say <img src="http://... replaced with <img src=\"file://... and pointing to the correct image(s) on disk.
Now tell the visible UIWebView to load that HTML string you built in step 3.

Redirect URL from local filesystem to internet with FireFox extension

I have several PDF files on my computer that contain links to other pages. Those links, however, direct you to the local filesystem instead of the internet. I.e. clicking the link opens the browser and takes you to file:///page instead of http://domain/page.
Getting these files modified to include the full URL is not an option.
I tried using available Firefox extensions to redirect the URL, but none worked, so I tried creating my own extension to do the same. What I've found so far is that the URL isn't accessible until the tab's "ready" event fires, but a page referring to a local file without the full path is always "uninitialized."
Here's my extension script, almost straight from https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/tabs:
var tabs = require("sdk/tabs");
tabs.on('open', function(tab){
tab.on('ready', function(tab){
if (tab.url.indexOf("file:///page") != -1) {
tab.url = tab.url.replace("file://", "https://domain");
}
});
});
Any ideas how to go about redirecting a page from a local file to another location?
The following snippet works fine with me.
In main.js:
var tabs = require("sdk/tabs");
tabs.on('ready', function(tab){
var new_url = tab.url;
if (tab.url.indexOf("file:///") != -1) {
new_url = new_url.replace("file:///", "https://domain/");
tab.url = new_url;
}
});
Although, my Firefox didn't fire the ready event on my tab when the url is something like what you want. For example, when the url is file:///page/lala.pdf, firefox ignores the url and does not try to reach it.
I believe Firefox wants a "real" path to load the page such as file:///C:page/lala.pdf.
I hope this will help you.
The easiest way I've found to do this is actually from another StackOverflow answer... Get Content of Location Bar. Use the function in that answer to retrieve the URL and then redirect based on that. So I end up with the following:
var tabs = require("sdk/tabs");
tabs.on('open', function(tab){
tab.on('activate', function(tab){
var { getMostRecentWindow } = require("sdk/window/utils");
var urlBar = getMostRecentWindow().document.getElementById('urlbar');
if (urlBar.value.indexOf("file:///page/") != -1) {
tab.url = urlBar.value.replace("file://", "https://domain");
}
});
});

WkWebview Cannot load Blob data in <a href

I have a web application that uses the WkWebview and has offline data stored in an IndexedDB. I am trying to load an offline PDF file from within the WkWebview using the following javascript.
var blob = b64toBlob(UserResource_data[i].PDF,'text/html'); //Stored as base 64 in indexeddb
file = new Blob([blob], {type: 'application/pdf'});
fileURL = webkitURL.createObjectURL(file);
ResourceLink = 'View PDF';
However nothing loads in the webview I just get a white screen and nothing crashes.
Swift Code:
self.webView!.loadRequest(navigationAction.request)
I have implemented a method to handle links with _blank for the target and it works fine for loading external pdf files.
Is this supported by WkWebView? or does anyone have any better ideas.
Embedding these files within the project is not an option as they must be externally update-able
EDIT - Found Workaround
Instead of using "createObjectURL()" I created a data URL
function LoadOfflinePDF(id){
var blob = b64toBlob(UserResource_data[id].PDF,'text/html');
var reader = new FileReader();
var out = new Blob([blob], {type: 'application/pdf'});
reader.onload = function(e){
//window.open(reader.result,'_blank');
console.log("LoadedpdfURL: "+id);
UserResource_data[id].PDF = reader.result;
}
reader.readAsDataURL(out);
}
Then created a popup with the dataURL
function openPDFReader(){
var id = this.id;
id = id.split("_");
id = id[1];
console.log("Opening: "+id);
window.open(UserResource_data[id].PDF);
}
So now I can properly display my offline PDF files stored in IndexedDB using the WKWebView

flash.display.Loader class on iOS

Intro - I am working on a iOS game using Flash CS5.5. In my game i am loading a image via the camera roll, and gonna use the image in the gameplay. I want the image to load back in when the user restarts the game.
Question - Is there a way to access such image again without having to open up the camera roll interface.
Can i use the flash.display.Loader class? Is there any special things i need to do or set? Or is there another way?
I've tried just saving the file, given from the MediaEvent dispatched when you select an image.
But i have no luck using the URL given in the loader object. I am using the example from this page as my base: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/media/CameraRoll.html.
Yes this is possible. You need to save the image into the apps documents directory using the File class with something like this: (this uses the Adobe JPGEncoder class)
f = File.documentsDirectory.resolvePath("logo.jpg");
stream = new FileStream();
stream.open(f, FileMode.WRITE);
j = new JPGEncoder(80);
var bytes:ByteArray = j.encode(visualLogo.bitmapData);
stream.writeBytes(bytes, 0, bytes.length);
stream.writeBytes(bytes, 0, bytes.bytesAvailable);
stream.close();
//I read the file back in to test that it has been successfully written
stream.openAsync(f, FileMode.READ);
stream.addEventListener(Event.COMPLETE, bringBoardOn, false, 0, true);
Then load it back in using something like this:
f = File.documentsDirectory.resolvePath ("logo.jpg");
if (f.exists == true) {
var _urlRequest:URLRequest = new URLRequest(f.url);
loader=new Loader;
loader.load(_urlRequest);
loader.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void{ trace(e) });
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, ImageLoaded, false, 0, true);
_urlRequest = null;
}

Resources