how to get html string from NSAttributedString in iOS - html

I am using UITextview in my app. And I have set allowsEditingTextAttributes property to YES in order to show images and formatted text if user copy pasted from browser into textView and working fine.
I want to retrieve the content back as html from UITextView, is there any way to get it? (I can achieve it using UIWebView but I need to use UITextView only)
Thanks

As far as I know, there is no API provided by Apple to do what you want. You need to get the attributed text as an NSAttributedString from the UITextView and convert it to HTML. There are open-source projects for this however, for example DTCoreText. If you're not looking for very advanced features, you might also be able to build this yourself, just by looping through the string's characters and analyzing the style attributes.
EDIT: Actually, there is an API to do this now! You can use NSAttributedString's dataFromRange:documentAttributes:error:, passing NSHTMLTextDocumentType as the requested document type.
Cheers!
Example (in Swift, can be done similarly in Objective-C):
//Grab the attributed string, convert it to HTML data
let data = try self.textView.attributedText.dataFromRange(
NSMakeRange(0, self.textView.attributedText.length),
documentAttributes: [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType]
)
//Convert the UTF-8 data to a string, display it in the text view
self.textView.attributedText = NSAttributedString(
string: NSString(data: data, encoding: NSUTF8StringEncoding)! as String
)

You could take a look at this repository: https://github.com/IdeasOnCanvas/Ashton
To read:
AshtonHTMLReader.h
- (NSAttributedString *)attributedStringFromHTMLString:(NSString *)htmlString;
And to writer:
AshtonHTMLWriter.h
- (NSString *)HTMLStringFromAttributedString:(NSAttributedString *)input;
See if it can help you.

Related

Swift 4: help decoding a JSON that contains an encoded image using base64

I'm a Swift (and programming) newb, fair warning.
I'm working on an app that is used to track scavenger hunt bonuses. I want to use a JSON file to contain all the bonus data, including a sample image. I see how to encode the image into base64 outside the program, then I can add it into my JSON as a string. Where I'm not certain is what to do with this? From searching I see you would use something like:
class func convertBase64ToImage(imageString: String) -> UIImage {
let imageData = Data(base64Encoded: imageString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
return UIImage(data: imageData)!
}
But I'm not certain if that would simply display said image, or if I need to save that and then call it somehow. The goal is to simply view the image (it is used for reference by the person taking a picture with their placard in the shot).
(I haven't implemented this in code yet, I'm still researching how to do it)
Your code works fine. You can test it out in a Playground easily enough. I used https://www.base64-image.de to Base64 encode a small PNG file and generate a string which I ran through your function. It worked fine.
To answer your direct question, UIImage is simply an image which you can display to the user as follows:
Create a view controller. Add a UIImageView to the view controller and wire up an outlet for it with a suitable name (for example, bonusImageView).
Call your function within the view controller to load the image into the image view.
bonusImageView.image = convertBase64ToImage(imageString: imageString)
Where imageString is the Base64-encoded string you obtained from your JSON.
Whether or not you choose to store the imageString first is up to you. It's not necessary to store it if all you want to do is retrieve it from a server and display it on demand.

get dynamically loaded html using alamofire + swift

I am trying to request a website's html code and use it in an app in Xcode (Swift 3.0) and the pod Alamofire. In the html code online, the data contents that I want to scrape are in a div class that returns data from an Events calendar, in the form of a javascript web plugin. Since the website is not static, when I request the html and print the resulting response as a string, the data I want is not contained in the string. A message appears that says:
<noscript>Your browser must support JavaScript to view this content.
Please enable JavaScript in your browser settings then try again.
Events calendar powered by Trumba
</noscript>
My code using Alamofire looks like:
func downloadCalendar(){
Alamofire.request(urlString).responseString { (AlamofireResponse) in
print(AlamofireResponse.result.value!)
}
}
The urlString is a variable for the actual webpage's url.
Is there a way to get all of the html that appears in the html online into Xcode using Alamofire? If it's not possible with Alamofire is there another way to do this using Swift?
I've tried to accomplish a similar thing, unfortunately to no avail...
It seams AlamoFire grabs the first response it gets....
There is a workaround - use UIWebView:
static let webView = UIWebView()
self.webView.loadRequest(URLRequest.init(url: URL.init(string:"http://example.com")!)
DispatchQueue.main.asyncAfter(deadline: .now()+10.0) {[unowned self] in
if let html = self.webView.stringByEvaluatingJavaScript(from: "document.documentElement.outerHTML")
{print(html)}
}
Where 10.0 is the approx number of seconds required for javascript to finish loading the webpage data.
However since: it's not thread safe, you must use a singleton webView,
import UIKit and can't do it in the background - it's far from the perfect solution...
It might be easier to setup a proxy webserver in between to do the parsing for you.
Cheers!

Is it possible to make "HTML to speech" same like "Text to speech"?

I have one weird requirement that in my existing app I have Text2Speech and for that, I have used AVSpeechSynthesizer to speech text, but now the requirement changed and now I need to convert HTML files data to text something like HTML2Speech.
One Solution we can think:
use HTML parsing and get all text from HTML and use same framework
for Text2Speech.
But the client doesn't want that type of parsing and he wants any API or framework which is providing directly HTML2Speech feature.
Any suggestion or help will be highly appreciated.
As I have worked with HTML parsing and text2speech here you can go with 2 steps
1.get Attribute string from HTML file with below code works in iOS7+
As per your client perspective : if there is any API in market for HTML2Speech may be its Paid or
you are depended on that API if you use any. While Native framework
will help same what you/client wants.
Step 1:
[[NSAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)}
documentAttributes:nil error:nil];
Then you can pass this Attributed String in AVSpeechUtterance
Step 2:
use below method to get HTML2String:
/**
* "ConvertHTMLtoStrAndPlay" : This method will convert the HTML to String
synthesizer.
*
* #param aURLHtmlFilePath : "object of html file path"
*/
-(void)ConvertHTMLtoStrAndPlay:(UIButton*)aBtnPlayPause
isSpeechPaused:(BOOL)speechPaused
stringWithHTMLAttributes:(NSAttributedString*)aStrWithHTMLAttributes
{
if (synthesizer.speaking == NO && speechPaused == NO) {
AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:aStrWithHTMLAttributes.string];
//utterance.rate = AVSpeechUtteranceMinimumSpeechRate;
if (IS_ARABIC) {
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:#"ar-au"];
}else{
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:#"en-au"];
}
[synthesizer speakUtterance:utterance];
}
else{
[synthesizer pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate];
}
if (speechPaused == NO) {
[synthesizer continueSpeaking];
} else {
[synthesizer pauseSpeakingAtBoundary:AVSpeechBoundaryImmediate];
}
}
and as usual while you need to stop use below code to stop Speech.
/**
* "StopPlayWithAVSpeechSynthesizer" : this method will stop the playing of audio on the application.
*/
-(void)StopPlayWithAVSpeechSynthesizer{
// Do any additional setup after loading the view, typically from a nib.
[synthesizer stopSpeakingAtBoundary:AVSpeechBoundaryImmediate];
}
Hope This will help you to get HTML2Speech feature.
There's two parts to a solution here...
Presumably you don't care about the formatting in the HTML--after all, by the time it gets to the speech synthesizer, this text is to be spoken, not viewed. AVSpeechSynthesizer takes plain text, so you just need to get rid of the HTML markup. One easy way to do that is to create an NSAttributedString from the HTML, then ask that attributed string for its underlying plain-text string to pass text to the synthesizer.
In iOS 10 you don't even have to extract the string from an attributed string — you can pass an attributed string directly to AVSpeechUtterance.
One way or another it will always be parsing HTML to something else if you don't want to read files. If the client want direct HTML2Speech solution you can provide a method that takes html file as an argument and read it. What's happening with this file under the hood should not bother client that much as long as it's clean and not causing problems.
What happen when client will ask for Markdown2Speech or XML2Speech. For what i see in your desciption is better to have it for now in one framework with two public methods Text2Speech and HTML2Speech that will take as argument link to file or NSString.
So as #rickster suggest it can be NSAttributedString or NSString. There is a lot of parsers out there, Or if you want own solution you can remove everything what's inside < and > and change encoding.
The safest method will be to extract the text and use existing text2speech API.
Though if you are sure that the browser will be chrome then Speech Synthesis API maybe helpful. But this API still not fully adopted by all browsers; it will be a risky solution.
You can find necessary info regarding this API at
https://developers.google.com/web/updates/2014/01/Web-apps-that-talk-Introduction-to-the-Speech-Synthesis-API?hl=en
https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html#examples-synthesis
https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API
There is no direct API for HTML to Speech except Speech Synthesis API mentioned above. Though you can try http://responsivevoice.org/. But I think this one is also based on browser's Speech Synthesis or Speech generation at server. So to use this one, you would have to extract text and pass the text to API to get the speech

How do you display image from "image_url" in Yelp API?

I now understand how to parse and display JSON data, but one thing eludes me: when I call "image_url" and receive the actual URL, how can I instead display the image that it refers to? ...and yes, I am a novice :)
Thanks!
You can do that like this:
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:theUrl]]];
where theUrl is the url in string format. Then simply assign the image to your image view: imageView.image = image - presuming you have set up a UIImageView either in your code, as an IBOutlet or as a tagged object in a view.
NOTE: You may want to have a look at Lazy Table Images to load the image asynchronously.

Opening HTML source code in Cocoa

I'm trying to display HTML source code in my NSDocument based application. However, it renders the page as Safari would show it.
Here's the code that I use to open HTML:
NSData*data;
NSMutableDictionary *dict = [NSDictionary dictionaryWithObject:NSHTMLTextDocumentType
forKey:NSDocumentTypeDocumentOption];
data = [NSData dataWithContentsOfFile:[self fileName]];
mString = [[NSAttributedString alloc]
initWithData:data options:dict documentAttributes:NULL
error:outError];
What am I doing wrong?
The correct solution is a mix of your original code and the bogus solution I gave you in my previous answer (which I've deleted). Use NSPlainTextDocumentType as the type, as you were doing originally, but use initWithData:options:documentAttributes:error:, not initWithHTML:options:documentAttributes:.
Alternatively, create a plain NSString holding the source code, and then create an attributed string with that plain string plus whatever attributes you want to apply to the whole document (e.g., fixed-pitch font).