Cocoa questions: NSImage, and more

Discussion in 'Mac Programming' started by altivec 2003, Aug 13, 2005.

  1. altivec 2003 macrumors regular

    Joined:
    Feb 8, 2003
    Location:
    Texas
    #1
    I'm starting a small cocoa application that will convert an image file into a 1-bit text format that is compatible with my z80 assembler (for TI-83+ programs). I already wrote one in Real Basic about a year ago (ay, the shame!), but for various reasons I no longer have it. My problem with the cocoa version is figuring out how to access the pixels/data of a NSImage directly. Does anybody know how this works? Do you have to create and add a bitmap representation to the NSImage, or is there some other way?
    In the Real Basic version, I just looped through all of the pixels performing pixel tests. It wasn't the most efficient method, but it worked well. A quick look at NSImage's documentation, however, provided no equivalent to Real Basic's pixel tests.

    My next question deals with monitoring cpu usage. Is there any way to figure out the current level of cpu activity other than making a NSTask that runs the unix "top" command?

    Finally, is there a way to monitor the audio output of the built in audio controller? I'm thinking of some pointless program that draws a sound-analysis similar to that of iTunes. I wrote the graphing code, but I need data!

    In short, I know nearly nothing about cocoa :eek:
    Thanks
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Moderator! Move this to Mac Programming please :)

    NSImage does not actually contain the pixels itself. If you are working with bitmap images then the NSBitmapImageRep contains the pixel data so you need to work with that if you are doing pixel by pixel manipulation. Once you have your bitmap rep you have getPixel:atX:y: and setPixel:atX:y: to work with (although you may find you don't need to do pixel by pixel work: if you are just compositing your bitmaps then use the standard NSImage methods).

    Getting the CPU usage: do not run top in an NSTask! top uses quite a bit of CPU on it's own. There are system calls (not pure Cocoa) to get this data. I'm not sure what they are though...

    You need to find out what sysctl is using:
    sysctl vm.loadavg
    vm.loadavg: 0.10 0.29 0.48


    Audio Stuff: no idea. I think it's possible (Audio Hijack seems to be able to do all sorts of stuff with the audio subsystems).
     
  3. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #3
    You can use [NSBitmapImageRep imageRepWithData:[myImage TIFFRepresentation]] to get a bitmap rep (assuming myImage is your NSImage).

    As far as the audio goes, you can use CoreAudio or QuickTime to get that data. I assume you mean level/frequency metering capabilities. It's not easy if you're used to Cocoa, though. Both APIs are fairly complex and use procedural C and Carbon calls and variable types. QuickTime is probably a bit easier, see the documentation for functions such as SetMovieAudioVolumeMeteringEnabled(), GetMovieAudioFrequencyMeteringBandFrequencies(), and GetMovieAudioVolumeLevels().
     
  4. altivec 2003 thread starter macrumors regular

    Joined:
    Feb 8, 2003
    Location:
    Texas
    #4
    Ah, I forgot there was a dedicated Mac Programming forum. Thanks for taking the time to move it, whoever did!

    Ok, this looks as though it is what I need for the image problem. I have no idea how I managed to miss that in the documentation, but thanks to you both I now have a starting point here. When I get it done (probably today) I might post a link to show you how much I managed to screw up even with your excellent advice :rolleyes:

    I already looked at CoreAudio and Quicktime a little, but I guess I should just stop being lazy! HiRez, the routines you list look really promising, but do they only work on a movie? Don't worry about me being too used to cocoa, though; I moved from procedural c to objective c/cocoa just a little bit ago.
     
  5. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #5
    I think that in QuickTime anything it can open is a "Movie" so an mp3 would be a Movie to the QuickTime API.
     
  6. altivec 2003 thread starter macrumors regular

    Joined:
    Feb 8, 2003
    Location:
    Texas
    #6
    True. But what I wanted to do is monitor the system audio out, not the audio in a file.

    But back to the image question. I've finally figured out that the getPixel: atX: y: method is only present in Tiger! I'm on Panther, darn it!
    So It looks like I'll have to get the bitmap data pointer from NSBitmapImageRep and do everything myself. Oh well, it shouldn't be THAT hard... NSBitmapImageRep tells me what the width and height are, which makes things easier.
     
  7. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #7
    What are you trying to do with the images that you need pixel by pixel access? It's possible that Cocoa would allow you to do what you want without it using built in methods (which may well be faster).
     
  8. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    Are you sure you don't have
    Code:
    -(void)getPixel:(unsigned int[])pixelData atX:(int)x y:(int)y
    ? My documentation says that
    Code:
    - (NSColor *)colorAtX:(int)x y:(int)y
    was added in 10.4 but does not say that about getPixel:...
     
  9. altivec 2003 thread starter macrumors regular

    Joined:
    Feb 8, 2003
    Location:
    Texas
    #9
    This is what I thought I needed pixel access for :). That .tar includes two sample bitmap images from a calculator game project of mine. I'm sorry if my refusal to follow apple's interface guidelines offended you... I just like brushed metal :cool:

    I wrote the thing by invoking my bitmap rep's bitmapData method. That returns a pointer to the data, which I looped through and reformatted. This is probably a hundred times faster than doing pixel tests anyway (not that speed would be an issue). On my 266 mhz laptop, it converts almost instantly... I was happily surprised. If you have any reason to see the (probably horribly written) source, I can upload it.
     
  10. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    Well, I'm glad you got it to do what you wanted but the App in the .tar you posted does not start for me. I assume you have posted a Development build (ZeroLink) which will not start on anyones machine but yours! Not to worry, I'm not that bothered. I just thought if I knew what you were doing I might be able to suggest a way to do it via the APIs available.
     
  11. altivec 2003 thread starter macrumors regular

    Joined:
    Feb 8, 2003
    Location:
    Texas
    #11
    Yikes, this really shows how little I have done with cocoa...
    Umm, exactly HOW do you change to deployment build mode? Is it in the target settings? :eek:
     
  12. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #12
    There is a drop down on the toolbar of the build window (Shift-Command-B). Once switched to Deployment you need to do a Clean then a Build.
     
  13. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #13
    Eh...you might be right about that, I thought I saw somewhere you could tell it to monitor an output, but it looks like they all operate on a specific movie. Still, I think there must be some way to do that using QuickTime, though I don't know what yet as I've ony recently started dabbling in QuickTime audio. There is a new QTAudioContext type introduced in QuickTime 7, but I can't find any documentation about what it is or what I can do with it. Now I'm sure CoreAudio must be able to do what you ask, but I don't know anything about that and I found the CoreAudio API to be a bear to work with, at least for playing compressed sound data (.MP3, etc.). One thing I did discover is that apparently CoreAudio cannot play back protected AAC files (iTMS), or at least it's not easy to do it, while in QuickTime they open like any other audio file. Anyone know what the deal is there?

    BTW, I got bitten by that "ZeroLink Development builds only run on your own machine" thingy too. Distributed the first alpha of my app and was all excited, only to find that no one could even launch it. It's a good lesson to learn early!
     
  14. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #14
    I have also "released" Development builds for public testing :eek: , twice :eek: :eek:

    For pixel access on an NSBitmapImageRep, it's most efficient to get the bitmap data as a pointer and work directly by dereferencing. I think it would go something like this ...
    Code:
    - (BOOL) manipulateImageRep:(NSBitmapImageRep*)rep {
        int Bpr, spp;
        unsigned byte *data;
        int x, y, w, h;
    
        if ([rep bitsPerSample] != 8) {
            // usually each color component is stored
            // using 8 bits, but recently 16 bits is occasionally
            // also used ... you might want to handle that here
            return NO;
        }
        
        Bpr = [rep bytesPerRow];
        spp = [rep samplesPerPixel];
        data = [rep bitmapData];
        w = [rep pixelsWide];
        h = [rep pixelsHigh];
    
        for (y=0; y<h; y++) {
            unsigned byte *p = data + Bpr*y;
            for (x=0; x<w; x++) {
                // do your thing
                // p[0] is red, p[1] is green, p[2] is blue, p[3] can be alpha if spp==4
                p += spp;
            }
        }
        return YES;
    }
    
     
  15. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #15
    That's the way I do it, but I wonder how efficient the getPixel: method is, perhaps they have optimized it well. Would be simpler.
     
  16. altivec 2003 thread starter macrumors regular

    Joined:
    Feb 8, 2003
    Location:
    Texas
    #16
    Well, that makes me feel a little better, as long as this second attempt works ;)

    *Crosses fingers*

    Your code is actually quite similar to what I came up with, except I used *pointer instead of pointer[0]. Just a habit, I guess. I only needed to deal with one sample per pixel, because I am dealing with black and white bitmaps (unfortunately, my graphing calculator does not have a color screen...).

    Thanks, everyone. I don't like to think what would've happened if I never learned that zerolink-ed builds don't work on other computers!
     
  17. gekko513 macrumors 603

    gekko513

    Joined:
    Oct 16, 2003
    #17
    We should test it ...
     
  18. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #18
    It took me a few days to figure it out, I was tearing my hair out trying to find what would cause that. Xcode should pop up a warning dialog the first time you try that. :cool:
     
  19. caveman_uk Guest

    caveman_uk

    Joined:
    Feb 17, 2003
    Location:
    Hitchin, Herts, UK
    #19
    I've nearly been caught out but I'm lucky enough to have two macs which means I spotted that before I released anything. Handy for checking that you've got all your frameworks built in properly too :D
     

Share This Page