Scaling NSTextAttachment in NSPasteboard - cocoa

I have an NSTextAttachment which contains an NSImage. What I would like to do is scale this image so that it's smaller in dimensions but will keeping the same number of pixels. Then moving it to the general pasteboard. Once it's pasted (into whatever app) I would like it to paste with the same dimensions I just set. The problem I am having is that pasting it in any other app always puts it at is original dimensions. I have tried the following things and none seem to fully work
First is simply resizing the image and then copying. This retains the proper dimensions (let's say 100 x 100 pt) but the image is very blurry and the resolution is 72 dpi.
//variable im is an NSImage object that is present
//variable newsize is an NSSize which is calculated to give the image proper resolution
im.lockFocus()
im.size = newsize
im.unlockFocus()
The second thing I have tried is use the techniques listed on this page. None of which do anything once I paste the TextAttachment to another app (such as Pages for example). Subclassing NSTextAttachment has no effect. Also changing the bounds of the attachment seems to have no effect once it's pasted.
The last thing I tried is after the iterating through the NSAttributedString which holds the attachments, and setting each one's bounds. Still no effect when pasting into other apps.
So the ultimate question: is there a way to have a scaled NSImage inside and NSTextAttachment copy to the clipboard?
func copy() {
let pboard = NSPasteboard.general()
pboard.clearContents()
let rtf = NSMutableAttributedString()
//self.images is an array that contains a bunch of images
//note that it is required that I use a RTF to copy/paste my images
//because there is text mixed with the images
//for simplicity I have removed the text from this code
//removing it from my app and doing the same code has no effect
for im in self.images {
let a = NSTextAttachment() //subclassing NSTextAttachment has no effect on pasted image size
a.image = im
a.bounds = NSMakeRect(0,0,100,100) //has no effect on pasted image size
//if I resize the image prior to copying (using the code above)
//the pasted image has correct dimensions but is very blurry.
let str = NSAttributedString(attachment: a)
rtf.append(str)
}
pboard.writeObjects([rtf])
}

Related

Qml Item grabToImage save image error

I'm using the
Item.grabToImage()
But I'm getting the following error.
QML ItemX: grabToImage: item has invalid dimensions
This is because I'm using height and width properties like so:
width: {
// return with * 0.4; based for some condition
// for eg
return parent.width * 0.4;
}
// and something similar with height
The only time that I can get the following code working is when I put in a static heigth and width:
grabToImage(
function(result)
{
result.saveToFile("/path/project-name/tmp/something.png");
}
);
Any ideas of why and how do I get around this problem?
Thank you
I'm not a 100% sure why, But it was something about the dynamic width of the parent.
In the program I wrote I has set the anchors of the image to the left and right of the preview container.
So when I tried to get the image capture from another item that was overlaying the image to cut out smaller parts of the image it was not letting me.
How I fixed this was to set a fixed image size of the source image and then just anchor it to the center of the preview section.
The only thing is now it will not size up if you scale the window.
I'm sure I could implement and on size change to the main program window and then set the width of the image (Not tested).
Last thing I should mention is that if the image is small then the cut out images from sections of the source image will be blurry and not good quality.
I fixed this by setting the "sourceSize.width" to a very large image and then used the "scale" property to scale down the image to fit within the preview item.

Adding Text to Cycle Tiles (Windows Phone 8)

I'm writing an app whose sole purpose is to periodically download some images and display them in a live tile. I want to be able to update the tile with 4-8 images every thirty minutes or so, so I need to use a CycleTile. Downloading the images and getting them into a live tile is pretty straight forward. The real kicker is adding text on each image.
If it was just two images, I would use a flip tile, displaying one on the front and one on the back. Then I would add the text by assigning a different tile title to the front and back. However, since I need to display more than 2 images, I need to use the CycleTile. And this approach won't work with the CycleTile. (but please, correct me if I'm wrong!)
So my next thought was to overlay a TextBlock on a WriteableBitmap. This could work, but i think it would get complicated quickly taking into account factors like: different image resolutions, medium/large tile layouts, and varying screen PPIs. I'm sure I could figure it out, but it seems... messy.
Is there a better way to do this? Are there some Tile features I'm overlooking?
To sum it up my requirements are:
Display 4-8 images using a live tile.
Each image needs to have some text associated with it.
Update the images every thirty minutes or so.
Needs to scale to wide tiles.
Needs to scale to phones with higher PPI screens.
For item one, you should be able to merge as many images together using the Blit method from the WriteableBitmapEx project. Since you can merge your images together in any way you want, you can ensure they cover wide tile widths and any ppi you need.
To cover the second item, the following will overlay text on an image:
private static ImageSource createBitmapImageWithImage(string text, int x, int y, Color textColor, BitmapSource bitmapSource)
{
using(var mem = new MemoryStream())
{
//Create Formatted Text
var textBlock = new TextBlock
{
Text = text,
Foreground = new SolidColorBrush(textColor),
FontFamily = new FontFamily("Courier New"),
FontSize = 40
};
//Moves an object two dimensionally
var tf = new TranslateTransform
{
X = x,
Y = y
};
//Overlay text on existing image
var bmpImage = new WriteableBitmap(bitmapSource);
bmpImage.Render(textBlock, tf);
bmpImage.Invalidate();
//Convert back into bitmap
bmpImage.SaveJpeg(mem, bmpImage.PixelWidth, bmpImage.PixelHeight, 0, 100);
mem.Seek(0, SeekOrigin.Begin);
var image = new BitmapImage();
image.SetSource(mem);
return image;
}
}
Of course you can pass in the text block too, or the options to configure the text block. But I wanted to show how you can format the text however you want.
Your third request is covered by background tasks. In your phone solution, add a new project and you can select background task. It is fairly straightforward to have this call your code to update the images. Nokia even created a walk through on how to add one with code examples.

Unable to dynamically resize NSImageView

I have an NSImageView that encloses a dynamically generated NSImage. When I change the image displayed, I would like to dynamically resize the NSImageView so that it precisely wraps the new image, and also have the enclosing window resize so that the space between the NSImageView and every other part of the window remains constant. (Note that the image view's scaling is set to none, as I want its image to always be shown at its physical size.) To illustrate, suppose I begin with a small image in my image view. If I replace it with a large image, I wish for both the NSImageView and enclosing window to resize to accommodate it, without affecting the sizing or spacing of any other element.
Currently, I call the following method whenever the magnification level is changed via the stepper or associated text field. Though regenerating the image and loading it into the NSImageView works fine, resizing the NSImageView and enclosing window do not.
- (void) updateMagnification:(NSUInteger)newMagnification {
// Keep values of stepper and associated text field synchronized.
[self.magnificationStepper setIntegerValue:newMagnification];
[self.magnificationTextField setIntegerValue:newMagnification];
// Regenerate image based on newMagnification and display in image view.
[self.qrGenerator generateWithBlockPixelWidth:newMagnification];
self.imageView.image = self.qrGenerator.image;
// Adjust frame size of image view.
NSLog(#"Old size: frame=%# image=%#", NSStringFromSize(self.imageView.frame.size), NSStringFromSize(self.imageView.image.size));
[self.imageView setFrameSize:NSMakeSize(self.imageView.image.size.width, self.imageView.image.size.height )];
NSLog(#"New size: frame=%# image=%#", NSStringFromSize(self.imageView.frame.size), NSStringFromSize(self.imageView.frame.size));
//[self.window setViewsNeedDisplay:YES];
//[self.imageView setNeedsDisplay:YES];
//[self.imageView.superview setNeedsDisplay:YES];
}
Regardless of whether I increase or decrease the magnification value, causing the image to grow smaller or larger, the size of both the NSImageView and window remains constant. The three setNeedsDisplay: calls that are commented out have no effect even if they're uncommented -- they were my attempt to determine if the problem was related to the controls not redrawing once their size was adjusted, but the calls had no effect. Curiously, my NSLog calls indicate that the imageView's frame does indeed take the requested size, for they yield this output:
2012-06-12 11:02:50.651 Presenter[4660:603] Old size: frame={422, 351} image={168, 168}
2012-06-12 11:02:50.651 Presenter[4660:603] New size: frame={168, 168} image={168, 168}
The actual display, of course, does not change.
Interestingly, changing the imageView's frame style to "none," either in Interface Builder or programatically with [self.imageView setImageFrameStyle:NSImageFrameNone], gives me behaviour closer to what I desire. Making the image larger so that it would otherwise be clipped by the image view does indeed result in the image view and window growing larger. From this point, however, making the image smaller does not result in the image view or window resizing accordingly. "None" is the only image frame style that displays this somewhat correct behaviour -- all four of the bordered styles (i.e., bevel [which is the default], button, groove, and photo) show the same entirely incorrect behaviour described above.
I came across someone with a similar problem. Oddly, he only observed the problematic behaviour when his image view's frame style was set to NSImageFrameNone, when this is the only value that gives me somewhat-correct behaviour. I tried modifying the frame style to a non-none value before the resize and to none afterward, as this resolved the other person's problem, but for me, this yielded the same behaviour as when I simply set the frame style to "none" initially.
Any help you provide will be much appreciated. Thanks!

Change bounds origin + cropping an image

I am a newbie to Cocoa, I have a few doubts regarding NSImage.
Question1:
Changing the bounds origin of an image doesn't seem to have any effect. I expected the image to be drawn from the newly set origin but that doesn't seem to the case. Am I missing something ?
code:
NSImage* carImage = [NSImage imageNamed:#"car"];
[self.imageView setImage:carImage];
//Following line has no effect:
self.imageView.bounds = CGRectMake(self.imageView.bounds.origin.x + 100, self.imageView.bounds.origin.y, self.imageView.bounds.size.width,self.imageView.bounds.size.height);
Note: imageView is an IBOutlet
Question2:
I was trying to crop an image, but it doesn't seem to be cropping the image, I can see the complete image. What is that I am missing ?
code:
NSRect sourceRect = CGRectMake(150, 25, 100, 50);
NSRect destRect = CGRectMake(0, 0, 100, 50);
NSImage* carImage = [NSImage imageNamed:#"car"];
[carImage drawInRect:destRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0];
[self.imageView setImage:carImage];
Thanks
Changing the bounds origin of an image doesn't seem to have any effect. …
//Following line has no effect:
self.imageView.bounds = CGRectMake(self.imageView.bounds.origin.x + 100, self.imageView.bounds.origin.y, self.imageView.bounds.size.width,self.imageView.bounds.size.height);
That's an image view, not an image.
The effect of changing the bounds of a view depends on what the view does to draw. Effectively, this means you shouldn't change the bounds of a view that isn't an instance of a view class you created, since you can't predict exactly how an NSImageView will draw its image (presumably, since it's a control, it involves its cell, but more than that, I wouldn't rely on).
More generally, it's pretty rare to change a view's bounds origin. I don't remember having ever done it, and I can't think of a reason off the top of my head to do it. Changing its bounds size will scale, not crop.
I was trying to crop an image, but it doesn't seem to be cropping the image, I can see the complete image. What is that I am missing ?
[carImage drawInRect:destRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0];
[self.imageView setImage:carImage];
Telling an image to draw does not change anything about the image. It will not “crop the image” such that the image will thereafter be smaller or larger. You are telling it to draw, nothing more.
Consequently, the statement after that sets the image view's image to the whole image, exactly as if you hadn't told the image to draw, because telling it to draw made no difference.
What telling an image to draw does is exactly that: It tells the image to draw. There are only two correct places to do that:
In between lockFocus and unlockFocus messages to a view or image (or after setting the current NSGraphicsContext).
Within a view's drawRect: method.
Anywhere else, you should not tell any Cocoa object to draw.
One correct way to crop an image is to create a new image of the desired/adjusted size, lock focus on it, draw the desired portion of the original image into it, and unlock focus on the new image. You will then have both the original and a cropped version.
Another correct way would be to create your own custom image view that has two properties: One owning an image to draw, and the other holding a rectangle. When told to draw, this custom view would tell the image to draw the given rectangle into the view's bounds. You would then always hold the original image and simply draw only the desired section.

How to overlap (superimpose) an image over a file icon using Cocoa?

I have to make a prototype application where I superimpose a small image over the file icons of a given folder.
Let's say I have a folder /MyDocuments/
and there are three files /MyDocuments/Doc1.rtf /MyDocuments/Doc1.pdf and /MyDocuments/Doc1.jpg
and I have an image myicon.png, now I have to superimpose this image myicon.png over the file icons of all the three files present in /MyDocuments/
I understand that I can use the methods in NSWorkspace sharedWorkspace to get and set the file icons for these files, but I have no idea how to use the image myicon.png and superimpose it over the existing icons of these files.
If anyone has seen the Dropbox application (dropbox.com), then it is similar to the way you see changed icons in your dropbox folder
I assume it would be done using NSImage but I have no idea how to do it.
Note: the image myicon.png will only occupy the top left part of the original icon of these files i.e. the image should not completely overlap with the existing icons but only the 1/4th portion on the top left should be occupied.
Lock focus on the file icon, then draw the badge icon, then unlock focus. You may want to do this to a copy of the file icon, and hang on to the unbadged original.
If the badge is one of the standard badges that come with Mac OS X, don't copy the badge into your app—it'll look outdated if Apple ever changes it. The standard badges are named in IconsCore.h; you can wrap any of those types in a string using the NSFileTypeForHFSTypeCode function, then pass that string to NSWorkspace's iconForFileType: to get the standard badge as an image, from which point you can do the above.
As a supplement to Peter Hosey's answer, here is some slightly modified example code from:
http://cocoadev.com/forums/comments.php?DiscussionID=221
NSImage *origImage = [sourceImage copy]; // Copy to avoid modifying the original.
NSSize previewSize = NSMakeSize([origImage size].width / 4.0, [origImage size].height / 4.0);
NSImage *previewImage = [[NSImage alloc] initWithSize:previewSize];
[previewImage lockFocus];
[origImage drawInRect:NSMakeRect(0, 0, previewSize.width, previewSize.height)
fromRect:NSZeroRect // Draws full image.
operation:NSCompositeSourceOver
fraction:1.0];
[previewImage unlockFocus];

Resources