I am studying currency recognition problems which is related to the Vision SDK of iOS11.
I'm having trouble handling VNHomographicImageRegistrationRequest, which determines the perspective warp matrix needed to align the content of two images. But I couldn't find how to send two images parameters into this API, can anyone help me?
Apple's Vision framework flow is always the same: Request -> Handler -> Observation
Example:
// referenceAsset & asset2 can be:
// CGImage - CIImage - URL - Data - CVPixelBuffer
// Check initializers for more info
let request = VNHomographicImageRegistrationRequest(targetedCGImage: asset2, options: [:])
let handler = VNSequenceRequestHandler()
try! handler.perform([request], on: referenceAsset)
if let results = request.results as? [VNImageHomographicAlignmentObservation] {
print("Perspective warp found: \(results.count)")
results.forEach { observation in
// A matrix with 3 rows and 3 columns.
print(observation.warpTransform)
}
}
-(matrix_float3x3)predictWithVisionFromImage:(UIImage *)imageTarget toReferenceImage:(UIImage*)imageRefer{
UIImage *scaledImageTarget = [imageTarget scaleToSize:CGSizeMake(224, 224)];
CVPixelBufferRef bufferTarget = [imageTarget pixelBufferFromCGImage:scaledImageTarget];
UIImage *scaledImageRefer = [imageRefer scaleToSize:CGSizeMake(224, 224)];
CVPixelBufferRef bufferRefer = [imageRefer pixelBufferFromCGImage:scaledImageRefer];
VNHomographicImageRegistrationRequest* request = [[VNHomographicImageRegistrationRequest alloc]initWithTargetedCVPixelBuffer:bufferTarget completionHandler:nil];
VNHomographicImageRegistrationRequest* imageRequest = (VNHomographicImageRegistrationRequest*)request;
VNImageRequestHandler* handler = [[VNImageRequestHandler alloc]initWithCVPixelBuffer:bufferRefer options:#{}];
[handler performRequests:#[imageRequest] error:nil];
NSArray* resultsArr = imageRequest.results;
VNImageHomographicAlignmentObservation* firstObservation = [resultsArr firstObject];
return firstObservation.warpTransform;
}
I have a custom UITextView and need something like this:
Google
By the way, This is my Initialize code on custom class:
void Initialize()
{
Font = UIFont.FromName("Lacuna Regular", 14f);
Editable = false;
DataDetectorTypes = UIDataDetectorType.Link;
Text = "Google";
}
but I don't know how to write the Url where I need to go (in this case, www.google.es).
Thanks in advance!
Via UIDataDetectorType.Links:
uiview.DataDetectorTypes = UIDataDetectorType.Link;
uiview.Text = #"https://www.google.es";
Via NSAttributedStringDocumentAttributes with NSAttributedString:
var urlString = #"Google";
var documentAttributes = new NSAttributedStringDocumentAttributes { DocumentType = NSDocumentType.HTML };
NSError error = null;
var attributedString = new NSAttributedString(NSData.FromString(urlString, NSStringEncoding.UTF8), documentAttributes, ref error);
// Should really check the NSError before applying
uiview.AttributedText = attributedString;
I've been searching for this problem for a few days already. Still no answer. I'm trying to send multiple images to the server, so, I need to convert the uiimage to nsdata first. But the nsdata seem to be a nil, but the 1st image always successful to be convert. Here is the code:
for image in images {
var imageTemp: NSData?
if let image_data = UIImageJPEGRepresentation(image, 1) {
imageTemp = image_data
}
if imageTemp == nil
{
print("nil")
return
}
i = i + 1;
}
I am successfully able to get HTML content and display into my UIWebView.
But want to customize the content by adding an external CSS file. I can only change the size of text and font. I tried every possible solution to make changes but it does not work - it shows no changes.
Below is my code
HTMLNode* body = [parser body];
HTMLNode* mainContentNode = [body findChildWithAttribute:#"id" matchingName:#"main_content" allowPartial:NO];
NSString *pageContent = [NSString stringWithFormat:#"%#%#", cssString, contentHtml];
[webView loadHTMLString:pageContent baseURL:[NSURL URLWithString:#"http://www.example.org"]];
-(void)webViewDidFinishLoad:(UIWebView *)webView1{
int fontSize = 50;
NSString *font = [[NSString alloc] initWithFormat:#"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", fontSize];
NSString *fontString = [[NSString alloc] initWithFormat:#"document.getElementById('body').style.fontFamily=\"helvetica\""];
[webView1 stringByEvaluatingJavaScriptFromString:fontString];
[webView1 stringByEvaluatingJavaScriptFromString:font];
}
Please help me get the css stylesheet in my view.
You can do it like this:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *cssString = #"body { font-family: Helvetica; font-size: 50px }"; // 1
NSString *javascriptString = #"var style = document.createElement('style'); style.innerHTML = '%#'; document.head.appendChild(style)"; // 2
NSString *javascriptWithCSSString = [NSString stringWithFormat:javascriptString, cssString]; // 3
[webView stringByEvaluatingJavaScriptFromString:javascriptWithCSSString]; // 4
}
What this code does:
// 1 : Define a string that contains all the CSS declarations
// 2 : Define a javascript string that creates a new <style> HTML DOM element and inserts the CSS declarations into it. Actually the inserting is done in the next step, right now there is only the %# placeholder. I did this to prevent the line from becoming too long, but step 2 and 3 could be done together.
// 3 : Combine the 2 strings
// 4 : Execute the javascript in the UIWebView
For this to work, your HTML has to have a <head></head> element.
EDIT:
You can also load the css string from a local css file (named "styles.css" in this case). Just replace step //1 with the following:
NSString *path = [[NSBundle mainBundle] pathForResource:#"styles" ofType:#"css"];
NSString *cssString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
As another option you can just inject a <link> element to the <head> that loads the CSS file:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *path = [[NSBundle mainBundle] pathForResource:#"styles" ofType:#"css"];
NSString *javascriptString = #"var link = document.createElement('link'); link.href = '%#'; link.rel = 'stylesheet'; document.head.appendChild(link)";
NSString *javascriptWithPathString = [NSString stringWithFormat:javascriptString, path];
[webView stringByEvaluatingJavaScriptFromString:javascriptWithPathString];
}
This solution works best for large CSS files. Unfortunately it does not work with remote HTML files. You can only use this when you want to insert CSS into HTML that you have downloaded to your app.
UPDATE: WKWebView / Swift 3.x
When you are working with a WKWebView injecting a <link> element does not work because of WKWebView's security settings.
You can still inject the css as a string. Either create the CSS string in your code //1 or put it in a local file //2. Just be aware that with WKWebView you have to do the injection in WKNavigationDelegate's webView(_:didFinish:) method:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
insertCSSString(into: webView) // 1
// OR
insertContentsOfCSSFile(into: webView) // 2
}
func insertCSSString(into webView: WKWebView) {
let cssString = "body { font-size: 50px; color: #f00 }"
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
func insertContentsOfCSSFile(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "styles", ofType: "css") else { return }
let cssString = try! String(contentsOfFile: path).trimmingCharacters(in: .whitespacesAndNewlines)
let jsString = "var style = document.createElement('style'); style.innerHTML = '\(cssString)'; document.head.appendChild(style);"
webView.evaluateJavaScript(jsString, completionHandler: nil)
}
Since UIWebView is deprecated in iOS 12, I'll only answer for WKWebView.
I've implemented CSS loading like it was described in the accepted answer. The problem was that sometimes the transition from HTML with no CSS applied to HTML with CSS was visible.
I think a better approach is to use the WKUserScript to inject the CSS like this:
lazy var webView: WKWebView = {
guard let path = Bundle.main.path(forResource: "style", ofType: "css") else {
return WKWebView()
}
let cssString = try! String(contentsOfFile: path).components(separatedBy: .newlines).joined()
let source = """
var style = document.createElement('style');
style.innerHTML = '\(cssString)';
document.head.appendChild(style);
"""
let userScript = WKUserScript(source: source,
injectionTime: .atDocumentEnd,
forMainFrameOnly: true)
let userContentController = WKUserContentController()
userContentController.addUserScript(userScript)
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let webView = WKWebView(frame: .zero,
configuration: configuration)
return webView
}()
You can read more about this approach in this blog post.
Instead of applying css with style tag it's better to apply it with the link tag:
func insertContentsOfCSSFile2(into webView: WKWebView) {
guard let path = Bundle.main.path(forResource: "resource", ofType: "css") else { return }
let csFile = "var head = document.getElementsByTagName('head')[0];var link = document.createElement('link'); link.rel = 'stylesheet';link.type = 'text/css';link.href = '\(path)';link.media = 'all';head.appendChild(link);"
webView.evaluateJavaScript(csFile) {(result, error) in
if let error = error {
print(error)
}
}
}
I have tested it.
it is working fine.
You need to add this header before apple style to HTML
let fontName = UIFont.systemFont(ofSize: 17.0).fontName
let htmlContent = """
<header>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no'>
</header>
<style type='text/css'>
img{max-height: 100%; min-height: 100%; height:auto; max-width: 100%; width:auto;margin-bottom:5px;}
p{text-align:left|right|center; line-height: 180%; font-family: '\(fontName)'; font-size: 17px;}
iframe{width:100%; height:250px;}
</style> \(html)
"""
webView.loadHTMLString(htmlContent, baseURL: Bundle.main.bundleURL)
I tried Amer Hukic answer. But did not work just the way it is. I added below code between my html head tags.
<link rel="stylesheet" href="style.css">
See #joern's accepted answer for more complete details. I'm adding this answer because I ran into a weird edge case. My particular use case needed to add styling to a div with a class="dialog". For some reason styling using .dialog and div weren't working though other types of styling were working. In the end I used the following to set the width of the dialog
let width = Int(webView.bounds.width)
let script = "document.getElementsByClassName(\"dialog\")[0].style.width = \"\(width)px\""
webView.evaluateJavaScript(script)
I am sending data via socket.io my app, which I want to embed the text of a parameter in a UILabel
Javascript server
socket.emit("app",{ac:"organización"})
iOS App
var ac = self.jsonOFsocket["ac"] as String
//ac === "organización"
self.label.text = ac
//self.label.text === "organizaci\U00f3n"
The socket.io the app sends unencrypted characters.
The app successfully receives all characters
The app shows different symbols
I try to do this:
func utf(txt:String) -> NSString {
var newTxt = NSString(format:txt, NSUTF8StringEncoding)
newTxt.precomposedStringWithCanonicalMapping
return newTxt
}
var ac = self.jsonOFsocket["ac"] as String
//ac === "organización"
self.label.text = uft(ac)
//self.label.text === "organizaciââ¥n"
This is important:
organizaciââ¥n
This is the Objective-C way:
NSData *data = [MyString dataUsingEncoding:NSUTF8StringEncoding];
NSString *stringWithSpecialCharacters = [[NSString alloc] initWithData:data encoding:NSNonLossyASCIIStringEncoding];
You'll have to store the proper string format on your server too and make sure it returns the right string via curl.