displaying image data

I’m new to AS Studio. I’m trying to figure out how to set an image view to the image data stored in a variable/property. I’m trying to “push” the current iTunes artwork to my app. Tried this –

tell application “iTunes” to set theArtwork to data of artwork 1 of current track
set image of image view 1 of window 1 to [image/image data/data/load image] theArtwork

– to no avail. Any ideas?

Hm, okay. Just fount this thread: http://bbs.applescript.net/viewtopic.php?id=13958, where I guess I should have posted my question in the first place. But I’m leaving this thread open, since its a slightly diffent question. Let me rephrase it: is it really impossible to set an image view to property data? Do you really have to first extract the data, save it to a file and then read it again? Sounds kludgy to me :confused:

No, you do not necessarily have to write to a temporary file, then read it. I’ve never worked with itunes artwork, so you’ll need to clarify some things for me. Is the artwork saved in separate files, or is it embedded in the songs themselves? If there are jpg files somewhere then obviously finding a way to identify and read them is best. If they are embedded, then you’ll have to deal with that first. Once you’ve found a way to extract the raw data from the music file (as a string), then you can use the following code to display it in an image view. It can not be done in plain AS, you’ll have to write a custom method which will do all of the work for you in obj-c. You’ll need to extract the picture data, so you arrive with a string that contains the raw image data for the picture, the equivalent to doing something like set rawImageData to read file “Path:To:Some:File.jpg” as string in the AS code below.

Once you have a variable containing the data as a string, then you can create your subclass. In my test project, I created a subclass of NSObject and named it MYMethods. For this example, I only created the implementation file (MYMethods.m) to keep it simple. In the file, paste the following…

[code]#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>

@interface MYMethods : NSObject
+(void)displayImageDataString:(NSString *)theImageDataString inImageView:(NSImageView *)theImageView;
@end

@implementation MYMethods
+(void)displayImageDataString:(NSString )theImageDataString inImageView:(NSImageView )theImageView {
NSData
theImageData = [NSData dataWithBytes:[theImageDataString cString] length:[theImageDataString cStringLength]];
NSImage
img = [[[NSImage alloc] initWithData: theImageData] autorelease];
[theImageView setImage:img];
}
@end[/code]
Once you’ve got your subclass created, you can set the contents of your image view by calling your new displayImageDataString:inImageView: method from your AS code, like this…

set rawImageData to ">> YOUR DATA HERE <<" --> This is where you supply your raw image data as a string
set myImageView to (image view "myImageView" of window "myWindow") --> Identify which image view you want to display it in
call method "displayImageDataString:inImageView:" of class "MYMethods" with parameters {rawImageData, myImageView}

Obviously, the code above is pretty simple and straightforward. The hard part may be obtaining your image data. A little creativity and/or a search on google should be able to help with that, as there are undoubtedly lots of people who want to get at their itunes artwork. If I had any songs on this machine that had artwork I’d look into this further… but I don’t. Sorry.

Good luck,
j

Well THANK YOU, jobu :D! This is so much more than the pointer I was hoping for. The artwork is embedded in the mp3, and you can easily get it from iTunes by simply asking for it (“get data of artwork”). Only problem is the string coersion. The obvious solution (return data of artwork 1 of current track as string) doesn’t work. But that part really shouldn’t be a problem. I’ll try your code as soon as I have figured it out. Thanks again!

Hi,

I think the images are stored in the itunes.rsrc file, but not sure. When they store the pict in the data fork, they add a 512 byte header for applications to use (whatever that means). When they stored it in the resource fork, there is no 512 byte header. When you get the data from an iTunes artwork, you get the data without the header. So, you need to add the 512 byte header to the data.

What I came up with is to store a blank pict somewhere in the project and write to that file. You want to store it in the project before running the app, so you can get it’s path at run time. I think jj or jobu posted to use unix touch command to create the file, since this adds no file type or creator type. Then, this file may be written to using the read/write commands.

I had forgotten about this post when my computer went down, but am working on it again. If you want to see an example, I have a working one with some kinks in it still.

gl,

Anyone ever make any progress with this?

It’s easy to get the data of the artwork, but I can’t figure out how to coerce it into a string.

It would be nice to do this without writing out to a file

I’m also trying to coerce a raw data image into something I can load into an imagecell.

For example, I’d like to load images from Address Book into an imagecell, but it only returns raw data TIFFs and I cannot get those to load into an imagecell. I’m going to try to implement Jobu’s implementation file (MYMethods.m) above. But I know a trick for coercing things to string. Maybe this is what you’re looking for?

on coerceImageDataToString(theData)
	try
		return theData as string
	on error x
		set {TID, text item delimiters} to {text item delimiters, "«data "}
		set {x, text item delimiters} to {item 2 of every text item of x, "»"}
		set {x, text item delimiters} to {item 1 of every text item of x, TID}
		return x
	end try
end coerceImageDataToString

So for example…

tell application "Address Book" to set theImage to image of my card
return my coerceImageDataToString(theImage)

returns a long data string that begins with something like…

"TIFF4D4D002A00000E10803FE …

daehl,

The problem is that applescript studio doesn’t always handle the passing of data very well between scripts and obj-c. It can do basic foundation types easily, but when you start passing data back and forth, such as images, it doesn’t always do what you expect. This was the case in our discussion of handling iTunes artwork, where we had to handle the data entirely within obj-c instead of getting the data in AS and then passing it to the subclass. Such is also the case when dealing with AB images. You can’t get the “image” from the card and then just pass it to the image view or to the subclass as described above. It’s actually a data object and it doesn’t seem to want to do what you’re asking of it.

The following worked for me…
***EDIT: I added some code below to handle not only the image from “my” card, but also for getting the image from a card of someone else.

on clicked theObject
	if name of theObject is "GetMyImage" then
		set theImageView to (image view "ImageView" of window "Window")
		call method "displayABImageInImageView:" of class "MYMethods" with parameter theImageView
		
	else if name of theObject is "GetPersonImage" then
		set theImageView to (image view "ImageView" of window "Window")
		set thePersonQuery to content of text field "PersonQuery" of window "Window"
		call method "displayABImageInImageView:forPerson:" of class "MYMethods" with parameters {theImageView, thePersonQuery}
		
	end if
end clicked

j

Thanks, Jobu!!!

That worked for me also!

Last night I tried to get your “displayImageDataString” (posted above) to work, but had no luck. I’m sure it was something I did wrong as this example worked on the first try.

I still don’t understand why Applescript Studio can’t use image data objects natively. I mean, I understand it doesn’t, but it SHOULD be made to work. Seems silly for so many apps to provide image data objects that can’t be readily re-used in AS Studio.

Now I just have to take the time to figure out exactly how your subclass implementation works. I know a little C & C++ but haven’t had much practice in recent years. I’ve just discovered AS Studio in recent months and keep getting more and more ideas for new script programs to write. Can’t wait to see what Leopard will offer in the way of Xcode & AS Studio improvements.

Thanks so much for your advice and time!

Wow, this is fun! I just modified Jobu’s method to grab images from iChat as well. Just an case anyone else is looking for something like this…

How to extract an iChat raw data tiff image and place it into an NSimageView object:

on clicked theObject
	if name of theObject is "GetAccountImage" then
		set theImageView to (image view "ImageView" of window "Window")
		set theAccountNumberQuery to content of text field "AccountQuery" of window "Window"
		call method "displayiChatImageInImageView:forAccount:" of class "MYMethods" with parameters {theImageView, theAccountNumberQuery}
	end if
end clicked

daehl,

I thought this was a very interesting approach … and so I tried it to make it work … successfully :wink:
The advantage is in my opinion, that is a more universal solution since it is not necessary to wrap an applescript part in the method:

an NSImageView category:

[code]// NSImageViewAddition.h

#import <Cocoa/Cocoa.h>

@interface NSImageView (setPictDataAddition)

-(BOOL)setArtworkImageFromErrString:(NSString *)errString; // this method adds a 512 Byte header
-(BOOL)setImageFromErrString:(NSString *)errString;

@end

@interface NSData (errStringConversion)

+(NSData *)dataWithErrString:(NSString *)errString;

@end[/code]

[code]// NSImageViewAddition.m

#import “NSImageViewAddition.h”

@implementation NSImageView (showPictAddition)

-(BOOL)setArtworkImageFromErrString:(NSString *)errString{
NSData *theImageData = [NSData dataWithErrString:errString];
NSMutableData imgData = [[NSMutableData alloc] initWithLength:(long)512];
[imgData appendData:theImageData];
NSImage
img = [[[NSImage alloc] initWithData:imgData] autorelease];
[imgData release]; // ###### EDIT ####
if (img == nil) return NO;
[self setImage:img];
return YES;
}

-(BOOL)setImageFromErrString:(NSString *)errString {
NSData theImageData = [NSData dataWithErrString:errString];
NSImage
img = [[[NSImage alloc] initWithData:theImageData] autorelease];
if (img == nil) return NO;
[self setImage:img];
return YES;
}

@end

@implementation NSData (errStringConversion)

+(NSData *)dataWithErrString:(NSString *)errString{
int len = [errString cStringLength];
const char *imgDataBuffer = [errString cStringUsingEncoding:NSUTF8StringEncoding];
char hexnumber[3];
hexnumber[2]=0;
char imgdata[len/2];
int n, m=0;
for (n=0;n<len;) {
hexnumber[0]=imgDataBuffer[n++];
hexnumber[1]=imgDataBuffer[n++];
imgdata[m] = strtol(hexnumber,NULL,16);
m++;
}
return [[[NSData alloc] initWithData:[NSData dataWithBytes:imgdata length:len/2]] autorelease];
}

@end[/code]
the modified coerce handler (we don’'t want the four character data type code at the beginning):

on coerceImageDataToString(theData)
    try
        return theData as string
    on error x
        set {TID, text item delimiters} to {text item delimiters, "«data "}
        set {x, text item delimiters} to {item 2 of every text item of x, "»"}
        set {x, text item delimiters} to {item 1 of every text item of x, TID}
        
        return (text 5 thru -1 of x)
    end try
end coerceImageDataToString

and two examples:

    using terms from application "Address Book"
        tell application "Address Book"
            set mypic to (image of my card)
        end tell
    end using terms from
    set mypicdata to my coerceImageDataToString(mypic)
    set iv to (image view "pic" of window "main")
    call method "setImageFromErrString:" of iv with parameter mypicdata

using terms from application "iTunes"
        tell application "iTunes"
            set aw to data of artwork 1 of current track
        end tell
    end using terms from

    set dta to my coerceImageDataToString(aw)
    set iv to (image view "artwork" of window "main")
    call method "setArtworkImageFromErrString:" of iv with parameter dta

D.

edited in the ‘setArtworkImageFromErrStrin:’ method (forgot a release … :wink: )

Thanks, Dominik!!!

Yes, I do like the option of having a more generalized way of converting raw data images to an image view. Thanks so much for taking the time to make that work. That will definitely come in handy!