Is it possible to convert an NSattributedString with attachments (RTFD not RTF) to ASCII, edit the stream, and convert it back? So far I am able to convert an RTFD to a String stream. But turning it back into an NSData object does not work. Here's the code I'm using in a playground.
import Cocoa
func stream(attr: NSAttributedString) -> String? {
if let d = attr.rtfd(from: NSMakeRange(0, attr.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType]) {
if let str = String(data: d, encoding: .ascii) { return str }
else {
print("Unable to produce RTFD string")
return nil
}
}
print("Unable to produce RTFD data stream")
return nil
}
if let im = NSImage(named: "image.png") {
let a = NSTextAttachment()
a.image = im
let s = NSAttributedString(attachment: a)
if let str = stream(attr: s) {
print("\(str)\n") //prints a string, which contains RTF code combined with NSTextAttachment string representation
if let data = str.data(using: .ascii) { //this is where things stop working
if let newRTF = NSAttributedString(rtfd: data as Data, documentAttributes: nil) {
print(newRTF)
}
else { print("rtfd was not created") }
}
else { print("could not make data") }
}
}
What am I missing? Or is my entire concept wrong here? I am doing this to get around a limitation of the way OS X handles images attached in RTF documents.
Edit:
The limitation I am trying to address is to set the size of an image in an RTF stream. The text handling system requires that we use NSTextAttachment. Whenever an image is pasted from that, it automatically sizes the image to whatever the pixel height and width are. Unfortunately there is no way to control this property. I have tried here and also using all the techniques here.
As far as the ASCII stream, I'm not trying to edit the image attachment itself. When the stream is printed, the actual RTF code is visible and editable. This works and would be a good workaround for this limitation. All I need is to edit the RTF code and change the \width and \height properties that Apple uses.
After your edit I can see what you are trying to do, interesting idea, but it won't work - at least not easily.
Take a look at the value of d, it is not an ASCII string stored as a value of type Data (or NSData). It is a serialised representation of multiple items; the RTF stream (text), the image data (binary). If you convert this to an ASCII string and back again it is not going to work, you can't represent arbitrary binary data as ASCII unless you encode it (e.g. something like base 64 encoding).
Now you could attempt what you are trying a slightly different way, skip the conversion to ASCII and edit the Data value directly. That is certainly possible, but as you are editing a format you don't know (the serialised representation) you would have to be careful... And even if you succeed in editing the representation there is no guarantee that converting back to an NSAttributedString with an NSTextAttachment will preserve your edits.
I suggest you tackle this another way. You have an NSAttributedString and you don't like the RTF produced after you write this to a file. So edit the RTF after it is written, e.g. open up the RTFD package, open the contained RTF file (TXT.rtf), edit it, write it back.
HTH
Related
Hi I'm trying to capture a picture using kotlin and registerForActivityResult but I allways get a blur image with no quality I've read several post but I can't understand how to work with my application. I'm using a fragment to call the camera. Any suggestions? Sorry for my bad english I've spent about the full week trying it works. And nothing. Thanks in advance
private var imagenUri: Uri? =null
val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
try {
val intent = result.data
intent!!.putExtra(MediaStore.EXTRA_OUTPUT, imagenUri)
val bitMap = intent?.extras?.get("data") as Bitmap
imagenUri= getImageUriFromBitmap(requireContext(),bitMap)
binding.ivImagen.setImageURI(imagenUri)
Toast.makeText(context, "la uri es: $imagenUri", Toast.LENGTH_SHORT).show()
} catch (e: java.lang.Exception){
Toast.makeText(context, "NO SE HA PODIDO ENCONTRAR IMAGEN", Toast.LENGTH_SHORT).show()}
}
}
binding.ibTomarFoto.setOnClickListener(){
startForResult.launch(Intent(MediaStore.ACTION_IMAGE_CAPTURE))
}
From the documentation:
public static final String ACTION_IMAGE_CAPTURE
Standard Intent action that can be sent to have the camera application capture an image and return it.
The caller may pass an extra EXTRA_OUTPUT to control where this image will be written. If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap object in the extra field. This is useful for applications that only need a small image. If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri value of EXTRA_OUTPUT.
So you need to add the EXTRA_OUTPUT extra to get a full-size image stored at a URI you supply. Otherwise you get a small image as a data payload in the result Intent (those bundles can't handle large objects).
It looks like you're already trying to do that, you've just added it to the wrong place - you need to add it to the Intent you call launch with, not the result one. It's a configuration option for the task you're launching!
So this should work:
binding.ibTomarFoto.setOnClickListener(){
startForResult.launch(
Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, imagenUri)
)
}
And then remove the same putExtra line from your result-handler code (it doesn't do anything, but there's no point having it there)
I know how to use VS Extensibility to get the entire active document's text. Unfortunately, that only gets me the text and doesn't give me the formatting, and I want that too.
I can, for example, get an IWpfTextView but once I get it, I'm not sure what to do with it. Are there examples of actually getting all the formatting from it? I'm only really interested in text foreground/background color, that's it.
Note: I need the formatted text on every edit, so unfortunately doing cut-and-paste using the clipboard is not an option.
Possibly the simplest method is to select all of the text and copy it to the clipboard. VS puts the rich text into the clipboard, so when you paste, elsewhere, you'll get the colors (assuming you handle rich text in your destination).
Here's my not-the-simplest solution. TL;DR: you can jump to the code at https://github.com/jimmylewis/GetVSTextViewFormattedTextSample.
The VS editor uses "classifications" to show segments of text which have special meaning. These classifications can then be formatted differently according to the language and user settings.
There's an API for getting the classifications in a document, but it didn't work for me. Or other people, apparently. But we can still get the classifications through an ITagAggregator<IClassificationTag>, as described in the preceding link, or right here:
[Import]
IViewTagAggregatorFactoryService tagAggregatorFactory = null;
// in some method...
var classificationAggregator = tagAggregatorFactory.CreateTagAggregator<IClassificationTag>(textView);
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
var tags = classificationAggregator.GetTags(wholeBufferSpan);
Armed with these, we can rebuild the document. It's important to note that some text is not classified, so you have to piece everything together in chunks.
It's also notable that at this point, we have no idea how any of these tags are formatted - i.e. the colors used during rendering. If you want to, you can define your own mapping from IClassificationType to a color of your choice. Or, we can ask VS for what it would do using an IClassificationFormatMap. Again, remember, this is affected by user settings, Light vs. Dark theme, etc.
Either way, it could look something like this:
// Magic sauce pt1: See the example repo for an RTFStringBuilder I threw together.
RTFStringBuilder sb = new RTFStringBuilder();
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
// Magic sauce pt2: see the example repo, but it's basically just
// mapping the spans from the snippet above with the formatting settings
// from the IClassificationFormatMap.
var textSpans = GetTextSpansWithFormatting(textBuffer);
int currentPos = 0;
var formattedSpanEnumerator = textSpans.GetEnumerator();
while (currentPos < wholeBufferSpan.Length && formattedSpanEnumerator.MoveNext())
{
var spanToFormat = formattedSpanEnumerator.Current;
if (currentPos < spanToFormat.Span.Start)
{
int unformattedLength = spanToFormat.Span.Start - currentPos;
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, unformattedLength);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
System.Drawing.Color textColor = GetTextColor(spanToFormat.Formatting.ForegroundBrush);
sb.AppendText(spanToFormat.Span.GetText(), textColor);
currentPos = spanToFormat.Span.End;
}
if (currentPos < wholeBufferSpan.Length)
{
// append any remaining unformatted text
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, wholeBufferSpan.Length - currentPos);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
return sb.ToString();
Hope this helps with whatever you're doing. The example repo will ask if you you want the formatted text in the clipboard after each edit, but that was just a dirty way that I could test and see that it worked. It's annoying, but it was just a PoC.
Sorry guys I want to try this again just reword it so its understandable.
ImageFiles is an array of PFObjects, about 10 images
let randomNumber = imageFiles[Int(arc4random_uniform(UInt32(imageFiles.count)))]
println(randomNumber)
and the println gives me a random image file from the array.
How do I put that into the image view? Meaning i want a random element of the array to be viewable in the uiimage view.
let image = UIImage(data: randomNumber as AnyObject as! NSData)
closest I've got... no syntax error only runtime
Could not cast value of type 'PFObject' (0x105639070) to 'NSData' (0x106c97a48).
An actual image stored in Parse is not of the format PFObject, it is of the type PFFile. Normally a reference to a PFFile is stored within a PFObject.
I can imagine your code/pseudocode will end up looking like the following:
let myRandomImageMetaData = imageFiles[Int(arc4random_uniform(UInt32(imageFiles.count)))]
let imageFileReference: PFFile = myRandomImageMetaData["imgLink"]
The actual code will depend on your database structure which I've already asked you for here, but you never provided.
Now that you have the file reference, then you actually have to download the image data itself. You can do it like so:
imageFileReference.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
}
}
}
You can read more about storing and retrieving images stored as PFFile in Parse here:
https://parse.com/docs/ios/guide#files-images
Now, your next problem is that you have not known all of this while uploading the images in the first place. So there is a high risk that you've uploaded the images to Parse badly in the first place and that the images doesn't exist there at all.
I want to restrict character input on NSTextField, i.e. so that disallowed characters aren't even appearing. Most of what I found about this topic were solutions that only validate after text input finished or using NSFormatter which still allows the character to appear.
So far I came up with this solution, sub-classing NSTextField:
class RestrictedTextField : NSTextField
{
static let VALID_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'-.& ";
override func textDidChange(notification:NSNotification)
{
for c in stringValue
{
if (RestrictedTextField.VALID_CHARACTERS.rangeOfString("\(c)") == nil)
{
stringValue = stringValue.stringByReplacingOccurrencesOfString("\(c)", withString: "", options: .LiteralSearch, range: nil);
break;
}
}
}
}
It works but isn't really optimal because the textcursor still moves by one space if an invalid character is tried to be entered. I also think the loop shouldn't be necessary so I wonder does somebody know a more elegant solution for this?
You have complete control with a subclass of NSFormatter. I'm not sure why you think you don't.
Override isPartialStringValid(_:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:) and implement the desired logic. From the docs (with some minor edits by me):
In a subclass implementation, evaluate [the string pointed to by *partialStringPtr] according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and change the selection range.
So, if the user tries to insert disallowed characters, you can either reject their edit in its entirety or modify it to strip those disallowed characters. (Remember that user changes can include pasting, so it's not necessarily just a single typed character.) To reject the change entirely, assign origString to *partialStringPtr and origSelRange to *proposedSelRangePtr.
I'm getting a CVImageBufferRef from my AVCaptureSession, and I'd like to take that image buffer and upload it over the network. To save space and time, I would like to do this without rendering the image into a CIImage and NSBitmapImage, which is the solution I've seen everywhere (like here: How can I obtain raw data from a CVImageBuffer object).
This is because my impression is that the CVImageBuffer might be compressed, which is awesome for me, and if I render it, I have to uncompress it into a full bitmap and then upload the whole bitmap. I would like to take the compressed data (realizing that a single compressed frame might be unrenderable later by itself) just as it sits within the CVImageBuffer. I think this means I want the CVImageBuffer's base data pointer and its length, but it doesn't appear there's a way to get that within the API. Anybody have any ideas?
CVImageBuffer itself is an abstract type. Your image should be an instance of either CVPixelBuffer, CVOpenGLBuffer, or CVOpenGLTexture. The documentation for those types lists the functions you can use for accessing the data.
To tell which type you have use the GetTypeID methods:
CVImageBufferRef image = …;
CFTypeID imageType = CFGetTypeID(image);
if (imageType == CVPixelBufferGetTypeID()) {
// Pixel Data
}
else if (imageType == CVOpenGLBufferGetTypeID()) {
// OpenGL pbuffer
}
else if (imageType == CVOpenGLTextureGetTypeID()) {
// OpenGL Texture
}