attributes not saving with file - objective-c

This is probably easy, but I can not seam to figure it out - maybe it's late. I have a simple program that takes the text from an NSTextView and saves it as rtf. Saving the text itself works great, I just can not figure out how to get the attributes to tag along.
Code:
NSAttributedString *saveString = [[NSAttributedString alloc]
initWithString:[textView string]];
NSData *writeResults = [saveString
RTFFromRange:NSMakeRange:(0, [saveString length])
doumentAttributes:?? ];
[writeResults writeToURL:[panel URL] atomically: YES];
I know I need an NSDictionary for the documentAttributes, so how do I get that from the view?
What am I missing?

It seems that you are asking the textView for its string property. You need to ask it for its attributedString property:
NSAttributedString *saveString = textView.attributedString;
You can get the attributes from an attributed string like this:
NSMutableDictionary *allAttributes = [[NSMutableDictionary alloc] init];
[saveString enumerateAttribuesInRange:NSMakeRange(0,saveString.length) options:NSAttributedStringEnumerationReverse usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
[allAttrubutes addEntriesFromDictionary:attrs];
}];
NSData *writeResults = [saveString.string RTFFromRange:NSMakeRange(0,saveString.length) documentAttributes:allAttributes];
I have used this method to get attributes many times however I have never saved to RTF so I don't know exactly how this will turn out. All the attributes will be in the dictionary however.

Related

Objective c - How to programmatically set UIImage DPI of JPEG file while saving it

I have read that you can change the meta data of an image to set the dpi to another value other than the default 72. I tried the solution in this question but had the same problem as the author of that question. The image metadata properties in the original image seems to take precedence over modifications.
I am using the ALAssetsLibrary to write an image to the photo library on my iPhone. I need to dpi to be 500 instead of the standard 72dpi. I know it is possible to change the properties by manipulating the bits directly (as shown here), but am hoping that iOS gives a better solution.
Thank you in advance for your help.
This piece of code for manipulating image metadata -if exists- and you can use this to change any values in image meta data. Please be aware changing DPI value in metadata does not actually process image and change DPI.
#import <ImageIO/ImageIO.h>
-(NSData *)changeMetaDataInImage
{
NSData *sourceImageData = [[NSData alloc] initWithContentsOfFile:#"~/Desktop/1.jpg"];
if (sourceImageData != nil)
{
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)sourceImageData, NULL);
NSDictionary *metadata = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, 0, NULL);
NSMutableDictionary *tempMetadata = [metadata mutableCopy];
[tempMetadata setObject:[NSNumber numberWithInt:300] forKey:#"DPIHeight"];
[tempMetadata setObject:[NSNumber numberWithInt:300] forKey:#"DPIWidth"];
NSMutableDictionary *EXIFDictionary = [[tempMetadata objectForKey:(NSString *)kCGImagePropertyTIFFDictionary] mutableCopy];
[EXIFDictionary setObject:[NSNumber numberWithInt:300] forKey:(NSString *)kCGImagePropertyTIFFXResolution];
[EXIFDictionary setObject:[NSNumber numberWithInt:300] forKey:(NSString *)kCGImagePropertyTIFFYResolution];
NSMutableDictionary *JFIFDictionary = [[NSMutableDictionary alloc] init];
[JFIFDictionary setObject:[NSNumber numberWithInt:300] forKey:(NSString *)kCGImagePropertyJFIFXDensity];
[JFIFDictionary setObject:[NSNumber numberWithInt:300] forKey:(NSString *)kCGImagePropertyJFIFYDensity];
[JFIFDictionary setObject:#"1" forKey:(NSString *)kCGImagePropertyJFIFVersion];
[tempMetadata setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyTIFFDictionary];
[tempMetadata setObject:JFIFDictionary forKey:(NSString *)kCGImagePropertyJFIFDictionary];
NSMutableData *destinationImageData = [NSMutableData data];
CFStringRef UTI = CGImageSourceGetType(source);
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)destinationImageData, UTI, 1, NULL);
CGImageDestinationAddImageFromSource(destination, source,0, (__bridge CFDictionaryRef) tempMetadata);
CGImageDestinationFinalize(destination);
return destinationImageData;
}
}
While trying to employ this solution for exporting JPEGs, I found that Photoshop wouldn't honour the DPI as exported. It turns out that Photoshop actively ignores the JFIF header information (and, in fact, doesn't even export it itself when it writes out JPEGs).
I ditched the JFIF section entirely. Most modern image libraries look at the TIFF/EXIF data first, so including that (and only that) seems to work well. Your mileage may vary, so be sure to test as many export destinations as you can!
However, the TIFF data is missing the ResolutionUnit tag, without which Photoshop will ignore XResolution and YResolution. It can have three values:
1 = No absolute unit of measurement. Used for images that may have a non-square aspect ratio, but no meaningful absolute dimensions.
2 = Inch.
3 = Centimeter.
Setting ResolutionUnit to 2 is required for DPI (dots per inch), for example:
[EXIFDictionary setObject:#(2) forKey:(NSString *)kCGImagePropertyTIFFResolutionUnit];

plist wont pull into my NSMutableArray. am i missing something?

So here's my code. I'm trying to display content from a plist into a table and i keep running into errors. ive been at it all day so i'm probably missing something fairly easy. hope you guys can figure out why when i build, the table is empty.
here is my plist (without headers):
<array>
<dict>
<key>word</key>
<string>AWord1</string>
<key>definition</key>
<string>here is a definition</string>
<key>partOfSpeech</key>
<string>here is a part of speech</string>
</dict>
<dict>
<key>word</key>
<string>Bword1</string>
<key>definition</key>
<string>here is a definition</string>
<key>partOfSpeech</key>
<string>here is a part of speech</string>
</dict>
</array>
</plist>
edit: closing tags were missing due to misformatting - fixed
ok. here is my new code. i NSLog'd and decided to back up to before i went to plist. so, if you could help. how would you suggest i pull this data from plist instead (assuming the data is in the plist)
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
NSArray *countriesToLiveInArray = [NSArray arrayWithObjects:#"Iceland", #"Greenland", #"Switzerland", #"Norway", #"New Zealand", #"Greece", #"Italy", #"Ireland", nil];
NSDictionary *countriesToLiveInDict = [NSDictionary dictionaryWithObject:countriesToLiveInArray forKey:#"Countries"];
NSArray *countriesLivedInArray = [NSArray arrayWithObjects:#"India", #"U.S.A", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", #"Test", nil];
NSDictionary *countriesLivedInDict = [NSDictionary dictionaryWithObject:countriesLivedInArray forKey:#"Countries"];
[listOfItems addObject:countriesToLiveInDict];
[listOfItems addObject:countriesLivedInDict];
//Initialize the copy array.
copyListOfItems = [[NSMutableArray alloc] init];
//Set the title
self.navigationItem.title = #"Countries";
//Add the search bar
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
searching = NO;
letUserSelectRow = YES;
i feel as though i'm still not actually telling it to parse the data from the plist. i've only init'd it. thoughts?
Your code seems very incomplete, it doesn't bear much relation to the plist. Here are a few issues
as noted by H2CO3 and Fogmeister, the plist as you show it is missing a closing </array> tag (but lets assume that is a typo in the question)
you load the entire array into a single entry in a countriesToLiveIn dictionary (against the key "definition")
countriesToLiveIn becomes a single object in the array listOfItems
you initialise a copyOfListItems array but then don't do anything with it
Then you do not indicate where the table is getting it's date from.
If it is from copyOfListItems, well that array is empty .: empty table.
If it is from listOfItems you will be parsing the countriesToLiveIn dictionary somehow, but you don't show how.
If it is directly from the plist array countriesToLiveInArray then that missing </array> tag could be a clue. You would also need to be parsing the array's contained dictionaries somehow, and you don't show us that code, there could be something wrong there.
To get further with this I suggest copious use of NSLog to find out how far the data gets in to your objects. Perhaps you could expand your question with the results if you are still getting stuck.
update
Following your updated code, my first suspicion is that there was a problem with your URL.
in your previous edit this is the suspect line
NSMutableArray *wordListArray = [[NSMutableArray alloc] initWithContentsOfURL: [NSURL URLWithString:#"http://url.com/dictpPlist.plist"]];
You need to NSLog right after it:
NSLog (#"wordListArray %#", wordListArray);
To confirm that you are not picking up the plist here. At least then we isolate the problem to this point in your code.
Then we need to question the URL - is it correct? how did the plist get there? can you verify it independently? Is it a local file URL or a network URL?
If you are accessing a network resource, this is quite likely your problem. The initWithContentsOfURL methods should only really be used with local filesystem URLs. See for example
initwithcontentsofurl methods considered harmful.
You should be using NSURLConnection asynchronously instead. Apple is a little cagey about this also:
aURL: The location of a file containing a string representation of an array produced by the writeToURL:atomically: method.
Assuming this is your issue, why don't you get it working with a local filesystem plist first.
Write one in code from your listOfItems array:
- (void) createPlist
{
NSFileManager* fManager = [NSFileManager defaultManager];
NSError* error;
NSURL* docsURL = [fManager URLForDirectory:NSDocumentDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:NO
error:&error];
NSURL* plistURL = [docsURL URLByAppendingPathComponent:#"testlist.plist"];
[listOfItems writeToURL:plistURL atomically:YES];
}
Read it back in, verify it works, then sort out how to do the same over a network.
try below code
// Path to the plist (in the application bundle)
NSString *path = [[NSBundle mainBundle] pathForResource:
#"dictpPlist" ofType:#"plist"];
// Build the array from the plist
NSMutableArray *array2 = [[NSMutableArray alloc] initWithContentsOfFile:path];
// Show the string values
for (NSString *str in array2)
NSLog(#"--%#", str);

Change text of a label

I have a array that reads a .txt file and when you click a button the label changes in one of the words of the .txt file, but the label doen't change.
This is the code:
if(sender == self.button) {
NSArray *words = [[NSArray alloc] initWithObjects:#"words.txt", nil];
[randomLabel setText:[words objectAtIndex:random() % [words count]]];
}
What should I do so the label changes when I press the button?
What file do I use?
A few things here:
Reading in file into an array
Well, for starters you're not reading in the contents of the .txt file.
NSArray *words = [[NSArray alloc] initWithObjects:#"words.txt", nil];
This creates a 1 element array, with that one element being #"words.txt". I don't know the format of your .txt file, so I can't say for sure how you have to load it in. See How do I format a text file to be read in using arrayWithContentsOfFile on how to potentially do this.
Setting button text
Also, you need to make sure randomLabel actually refers to the label contained within the button, otherwise the button text won't change. Typically for a button, you'd change the title using the method:
- (void)setTitle:(NSString *)title forState:(UIControlState)state
So in your instance, it'd be:
NSString* newTitle = [words objectAtIndex:random() % [words count]];
[self.button setTitle:newTitle forState:UIControlStateNormal];
Is the code actually being called?
Double check that sender == self.button evaluates to true (for readability and clarity, I'd use [sender isEqual:self.button]). Use the debugger to step through the code, to see if that particular piece of code is being called. See http://mobile.tutsplus.com/tutorials/iphone/xcode-debugging_iphone-sdk/ on how to achieve this.
You should try using
(id)initWithContentsOfFile:(NSString *)aPath

Why wont [NSTextStorage appendAttributedString: ] accept my NSAttributedString's attributes?

I am trying to put text with a specific font and color into an NSTextView. I can put the text in just fine, but it loses my attributes:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSFont fontWithName:#"Monaco" size:10], #"NSFontAttributeName",
[NSColor blueColor], #"NSForegroundColorAttributeName",
nil];
NSAttributedString *string = [[NSAttributedString alloc] initWithString:someNSString
attributes: dict];
[someNSTextStorage appendAttributedString:string];
I've read the all the relevant class references (NSTextView, NSTextStorage, NSAttributedString, etc...) and I still don't know why it doesn't work as I expect.
What am I doing wrong/missing?
Found your problem: You've enclosed NSForegroundColorAttributeName in quotes. So instead of a macro you're passing an NSString literal. Same goes for your NSFontAttributeName as well. Get rid of those and you're set.

best way to get text from a plain .txt file into a Scroll View

Can someone please help me out with this I'm actually going nuts!
What is the best way to get text from a plain .txt file into a Scroll View, thats all I need just text.
I've tried so many different solutions but can't get any of them working I was hoping someone could give me a fresh overview.
Is the file a resource in your application or are you loading it from a network resource? If embedded, you can load it into an NSString object and then set the text property of the UITextView with that. Something like:
UITextView *myTextView = [[UITextView alloc] init];
NSString *pathToFile = [[NSBundle mainBundle] pathForResource:#"yourTextFile" ofType:#"txt"];
NSString *theText = [NSString stringWithContentsOfFile:pathToFile encoding:NSUTF8StringEncoding error:nil];
myTextView.text = theText;