NSImage drawInRect: to draw directly to a view.

I am learning about NSImage as well as drawing in AppKit. My work involves applications/scripts that present an NSWindow containing various types of views (NSTextView, NSImageView,etc.) The documentation I have read states that an NSImage can be drawn into a view using drawInRect: I have seen several excellent examples in MacScripter posts (many thanks, as always, to Shane for many of them), but those cases were for writing the image to a file. In that situation, the NSGraphicsContext currentContext was a bitmap. I don’t see how to set currentContext to a view. LockFocus on views has been depreciated and caused the script to crash.

So, is it possible to use NSImage drawInRect: to draw directly in a view? My approach has been to either start with an existing image or create a new, empty image, lockFocus on it, draw NSBezierPath’s and such onto it, and then add it to an NSImageView, which is then added as a subview to the window. It is not a bad method.

I have see many statements about using drawInRect: to draw directly to a view. There is either something I don’t understand about working with images in windows, or I am mis-understanding the documentation.

Thanks much for any assistance.

I suspect you’re getting confused with drawRect:, which is an instance method of NSView that you can override to customise drawing.

Creating an NSImage and adding it to an NSImageView is the way to go.

I think he’s looking to draw on top of the image.

If your not needing to reuse or export the image.
Just set the image in a NSImageView
Create a new view on top of the ImageView (NSWindowPositionAbove)
Then do your custom drawing into that NSView.

You can create your own subclass of NSView
Then you do your drawing in the sublass’s
drawRect: method.

Maybe your Also thinking of

drawInRect:fromRect:operation:

Which would allow you to have the NSImage as the receiver.
InRect theDestination you want to draw into.
fromRect: a rect containing what you want to add.
operation: The compositing type of drawing.
Like Photoshops later compositioms
Over, add, multiple and think you can also set the opacity as eell

I wrote here one practical example. It is starting point, and should be executed as application. You have to add drawing methods on the existing image yourself:


use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property NSScreen : a reference to current application's NSScreen
property NSView : a reference to current application's NSView
property NSWindow : a reference to current application's NSWindow
property NSWindowController : a reference to current application's NSWindowController
property NSTitledWindowMask : a reference to current application's NSTitledWindowMask
property NSNormalWindowLevel : a reference to current application's NSNormalWindowLevel
property NSBackingStoreBuffered : a reference to current application's NSBackingStoreBuffered
property NSColor : a reference to current application's NSColor
property NSImage : a reference to current application's NSImage
property NSImageView : a reference to current application's NSImageView

-- Create window
set aScreen to NSScreen's mainScreen()
set aFrame to {{0, 0}, {600, 200}}
set aBacking to NSTitledWindowMask
set aDefer to NSBackingStoreBuffered
set aWin to my createWindow(aScreen, aFrame, aBacking, aDefer)

-- Create NSWindowController
set wController to NSWindowController's alloc()
wController's initWithWindow:aWin

-- Choose image file, Load the image (as NSImage)
set imageFile to POSIX path of (choose file of type {"public.image"})
set theNSImage to NSImage's alloc()'s initWithContentsOfFile:imageFile

-- ADD your DRAWING HERE.   (Following is drawing example):
-- make NSString of the text, and define text attributes
set theNSString to current application's NSString's stringWithString:"Hello world"
set theNSFont to current application's NSFont's fontWithName:"Helvetica" |size|:12
set theNSColor to NSColor's redColor()
set attributesNSDictionary to current application's NSDictionary's dictionaryWithObjects:{theNSFont, theNSColor} forKeys:{current application's NSFontAttributeName, current application's NSForegroundColorAttributeName}
-- draw
theNSImage's lockFocus()
theNSString's drawAtPoint:{0, 0} withAttributes:attributesNSDictionary
theNSImage's unlockFocus()

-- Create custom NSImageView (aNSV), Add the NSImage to it
set aNSV to NSImageView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, 600, 200))
aNSV's setImage:theNSImage

-- add custom view to window
aWin's setContentView:aNSV
wController's showWindow:me

delay 10 -- to see visually, 10 seconds

on createWindow(aScreen, aFrame, aBacking, aDefer)
	-- create window
	set aWin to NSWindow's alloc()
	(aWin's initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
	aWin's setTitle:"You are welcome! This is  your image."
	aWin's setDelegate:me
	aWin's setDisplaysWhenScreenProfileChanges:true
	aWin's setHasShadow:true
	aWin's setIgnoresMouseEvents:false
	aWin's setLevel:(NSNormalWindowLevel)
	aWin's setOpaque:false
	aWin's setAlphaValue:1.0
	aWin's setReleasedWhenClosed:true
	aWin's |center|()
	aWin's setBackgroundColor:(NSColor's blueColor())
	aWin's makeKeyAndOrderFront:(me)
	return aWin
end createWindow

NOTE: you can improve my script by getting the dimensions of the image + setting same dimensions for NSWindow and NSImageView instead of hardcoded (0, 0, 600, 200).

I appreciate each of you taking the time to respond. An example of the documentation for which I did not understand how to implement is in the Cocoa Drawing Guide (https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Images/Images.html#//apple_ref/doc/uid/TP40003290-CH208-BCIIBDAD)
where it states:

“Once you have an image, there are many ways you can use it. The simplest thing you can do is draw it into a view as part of your program’s user interface.”
And…
“The NSImage class defines several methods for drawing an image into the current context. The two most commonly used methods are:
drawAtPoint:fromRect:operation:fraction:
drawInRect:fromRect:operation:fraction:”

I did not understand how to make a view the current context. For example, as with an NSImage object, with which one can lock focus on it and subsequently draw into the image context.

The responses confirm that an NSImage with which I have been working is best displayed in a window by putting the image into an NSImageView object by setting its image property.

As you noted the NSImage class defines those methods.
Not an NSView class.

(EDITTED upon further reading about graphic contexts,
This is a convenience method that creates a graphics context
From the NSImage, Also I was wrong about the fromRect:)

Those methods are operating on a NSImage object.
Which is a conceince method using the NSImage as the context
to draw into will draw at point/Rec
From the rect (What you want you Add) with the compositing options.

Then set that into a NSImageView.

Or if you have another imageRep you used as the context.
Or as explained here. Draw the imageRep into a Rect or the view.

Think of graphicContexts as offscreen canvas where you do your drawing operations.
Once yiuve completed the operations then you can place it into a view.
Or draw into the “contextRefs” in your views

https://developer.apple.com/documentation/appkit/nsimage/1519904-drawrepresentation?language=objc

I don’t know why the user insists on “draw directly to a view”. It seems to me that they does not understand that they can “draw” (that is, edit zeros and ones) in the context (a piece of RAM memory) indefinitely, but it will be a useless exercise until there is no graphical interface to show the result. This graphical interface is windows (NSWindow). That is, in order to see something, you cannot do without them.

The examples from the documentation omit this step - creating firstly the window. That is all.

@David Brown

The first thing you need to do if you want help, is to explain in a short and brief description, what you’re trying to do, and where you’re trying to do it.

For example, are you loading the image from a file ? or are you working in Xcode and the image is a resource in your project ?
Are you wanting to display the image directly on the screen ?, or are you trying to display the image on a window’s background, or on another view within the window.

Without a simple and concise explanation of what you’re trying to do, everyone will just be guessing.
And you won’t get the help you need and want.

Just a suggestion.

Regards Mark