Capturing the Content of a IKImageBrowserView

  • Hello,

    I'm currently trying to capture the content of a IkImageBrowserView but the image resulting from this operation is always blank.

    My code:

    [MyIkImageBrowserView lockFocus];
    NSBitmapImageRep *imageRep = [MyIkImageBrowserView bitmapImageRepForCachingDisplayInRect:[MyIkImageBrowserView frame]];
    [MyIkImageBrowserView cacheDisplayInRect:[MyIkImageBrowserView frame] toBitmapImageRep:imageRep];
    [MyIkImageBrowserView unlockFocus];

    NSImage *image = [[NSImage alloc] initWithSize:sizeOfMyIkImageBrowserView];
    [image addRepresentation:imageRep];


    [imageViewOfTheView setImage:image];

    If someone could give me a better solution i would be more than happy.

    Thanks
    Anthony Mittaz
  • Hello Anthony,

    This is because the IKImageBrowserView renders itself into an openGL
    surface.
    So you can't retrieve the pixels using the usual AppKit code path.

    But instead you can try this:

    //1) allocate a c buffer at the size of the  visible rect of the image
    browser
    NSRect vRect = [yourImageBrowserView visibleRect];
    NSSize size = vRect.size;

    void *buffer = malloc(size.width * size.height * 4);

    //2) read the pixels using openGL
    [yourImageBrowserView lockFocus];
    glReadPixels(0,
                  0,
                  size.width,
                  size.height,
                  GL_RGBA,
                  GL_UNSIGNED_BYTE,
                  buffer);
    [yourImageBrowserView unlockFocus];

    //3) create a bitmap with those pixels
    unsigned char *planes[2];
    planes[0] = (unsigned char *) (buffer);

    NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc]
    initWithBitmapDataPlanes:planes pixelsWide:size.width
    pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES
    isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bitmapFormat:0
    bytesPerRow:size.width*4 bitsPerPixel:32];

    //4) create a temporary image with this bitmap and set it flipped
    (because openGL and the AppKit don't have the same pixels coordinate
    system)
    NSImage *img = [[NSImage alloc] initWithSize:size];
    [img addRepresentation:imageRep];
    [img setFlipped:YES];
    [imageRep release];

    //5) draw this temporary image into another image so that we get an
    image without any reference to our "buffer" buffer so that we can
    release it after that
    NSImage *finalImage = [[NSImage alloc] initWithSize:size];
    [finalImage lockFocus];
    [img drawAtPoint:NSZeroPoint
    fromRect:NSMakeRect(0,0,size.width,size.height)
    operation:NSCompositeCopy fraction:1.0];
    [finalImage unlockFocus];

    //6) release intermediate objects
    [img release];
    free(buffer);

    -- Thomas.

    On Jan 9, 2008, at 5:00 PM, Anthony Mittaz wrote:

    > Hello,
    >
    > I'm currently trying to capture the content of a IkImageBrowserView
    > but the image resulting from this operation is always blank.
    >
    > My code:
    >
    > [MyIkImageBrowserView lockFocus];
    > NSBitmapImageRep *imageRep = [MyIkImageBrowserView
    > bitmapImageRepForCachingDisplayInRect:[MyIkImageBrowserView frame]];
    > [MyIkImageBrowserView cacheDisplayInRect:[MyIkImageBrowserView
    > frame] toBitmapImageRep:imageRep];
    > [MyIkImageBrowserView unlockFocus];
    >
    > NSImage *image = [[NSImage alloc]
    > initWithSize:sizeOfMyIkImageBrowserView];
    > [image addRepresentation:imageRep];
    >
    >
    > [imageViewOfTheView setImage:image];
    >
    > If someone could give me a better solution i would be more than happy.
    >
    > Thanks
    > Anthony Mittaz
  • Thanks this works well except that when I'm using this code the
    resulting image has no shadow under each browser item.

    Is there anything i can add to this code the get back my shadows ;-)

    Here You can see the original IKImageBrowser and the resulting image.

    http://web.mac.com/sync/Site/IKImageBrowserViewProblem.html

    On 10/01/2008, at 2:24 AM, Thomas Goossens wrote:

    > Hello Anthony,
    >
    > This is because the IKImageBrowserView renders itself into an openGL
    > surface.
    > So you can't retrieve the pixels using the usual AppKit code path.
    >
    > But instead you can try this:
    >
    > //1) allocate a c buffer at the size of the  visible rect of the
    > image browser
    > NSRect vRect = [yourImageBrowserView visibleRect];
    > NSSize size = vRect.size;
    >
    > void *buffer = malloc(size.width * size.height * 4);
    >
    > //2) read the pixels using openGL
    > [yourImageBrowserView lockFocus];
    > glReadPixels(0,
    > 0,
    > size.width,
    > size.height,
    > GL_RGBA,
    > GL_UNSIGNED_BYTE,
    > buffer);
    > [yourImageBrowserView unlockFocus];
    >
    > //3) create a bitmap with those pixels
    > unsigned char *planes[2];
    > planes[0] = (unsigned char *) (buffer);
    >
    > NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc]
    > initWithBitmapDataPlanes:planes pixelsWide:size.width
    > pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:4
    > hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
    > bitmapFormat:0 bytesPerRow:size.width*4 bitsPerPixel:32];
    >
    > //4) create a temporary image with this bitmap and set it flipped
    > (because openGL and the AppKit don't have the same pixels coordinate
    > system)
    > NSImage *img = [[NSImage alloc] initWithSize:size];
    > [img addRepresentation:imageRep];
    > [img setFlipped:YES];
    > [imageRep release];
    >
    > //5) draw this temporary image into another image so that we get an
    > image without any reference to our "buffer" buffer so that we can
    > release it after that
    > NSImage *finalImage = [[NSImage alloc] initWithSize:size];
    > [finalImage lockFocus];
    > [img drawAtPoint:NSZeroPoint
    > fromRect:NSMakeRect(0,0,size.width,size.height)
    > operation:NSCompositeCopy fraction:1.0];
    > [finalImage unlockFocus];
    >
    > //6) release intermediate objects
    > [img release];
    > free(buffer);
    >
    > -- Thomas.
    >
    >
    > On Jan 9, 2008, at 5:00 PM, Anthony Mittaz wrote:
    >
    >> Hello,
    >>
    >> I'm currently trying to capture the content of a IkImageBrowserView
    >> but the image resulting from this operation is always blank.
    >>
    >> My code:
    >>
    >> [MyIkImageBrowserView lockFocus];
    >> NSBitmapImageRep *imageRep = [MyIkImageBrowserView
    >> bitmapImageRepForCachingDisplayInRect:[MyIkImageBrowserView frame]];
    >> [MyIkImageBrowserView cacheDisplayInRect:[MyIkImageBrowserView
    >> frame] toBitmapImageRep:imageRep];
    >> [MyIkImageBrowserView unlockFocus];
    >>
    >> NSImage *image = [[NSImage alloc]
    >> initWithSize:sizeOfMyIkImageBrowserView];
    >> [image addRepresentation:imageRep];
    >>
    >>
    >> [imageViewOfTheView setImage:image];
    >>
    >> If someone could give me a better solution i would be more than
    >> happy.
    >>
    >> Thanks
    >> Anthony Mittaz
    >
  • Hi Anthony,

    I've recently become a fan of the CGWindow options (thanks to the
    Jumpy samplecode of Lucas Newman), and wrote the following NSImage
    category based on the Matt Gemmel's NSImage-Quicklook category). This
    allows you to get an NSImage of your window exacty way it appears on
    screen. It wouldn't be difficult to add a NSRect parameter for the
    region of the window using an additional
    CGImageCreateWithImageInRect(image, myRect)) step and passing in the
    imagebrowsers frame, or you could in fact already pass that rect in
    the CGWindowListCreateImage call.
    Cheers,
    Alex

    + (NSImage *)imageOfWindow: (NSInteger)windowNumber listOption:
    (CGWindowListOption)listOption imageOption:
    (CGWindowImageOption)imageOption tightFit: (BOOL)flag{

    //call as [NSImage imageOfWindow: kCGNullWindowID listOption:
    kCGWindowListOptionOnScreenOnly imageOption: kCGWindowImageDefault
    tightFit: NO];
    //or [NSImage imageOfWindow: [myWindow windowNumber] listOption:
    kCGWindowListOptionIncludingWindow imageOption: kCGWindowImageDefault
    tightFit: NO];
    //or [NSImage imageOfWindow: [myWindow windowNumber] listOption:
    kCGWindowListOptionIncludingWindow imageOption:
    kCGWindowImageBoundsIgnoreFraming tightFit: YES];

    //kCGWindowImageDefault = 0,      /* Default behavior: If a rect of
    CGRectNull is used bounds computation includes the framing effects,
    such as a shadow. */
    //kCGWindowImageBoundsIgnoreFraming = (1 << 0),  /* If a rect of
    CGRectNull is used, ignore framing effects for bounds computation */
    //kCGWindowImageShouldBeOpaque = (1 << 1),  /* The captured image
    should be opaque.  Empty areas are white */
    //kCGWindowImageOnlyShadows = (1 << 2)

    //kCGWindowListOptionAll or kCGWindowListOptionOnScreenOnly  /* Use
    all windows that are on screen in this user session. The windowID
    should be kCGNullWindowID. */
    //kCGWindowListOptionOnScreenAboveWindow      /* Use all on-screen
    windows above the specified window ordered from front to back. The
    windowID should be the window number, as from [myWindow windowNumber].
    //kCGWindowListOptionOnScreenBelowWindow      /* Use all on-screen
    windows below the specified window ordered from front to back. The
    windowID should be the window number, as from [myWindow windowNumber].
    //kCGWindowListOptionIncludingWindow      /* Use only the specified
    window to construct the image. The windowID should be the window
    number, as from [myWindow windowNumber].
    //(kCGWindowListOptionOnScreenAboveWindow |
    kCGWindowListOptionIncludingWindow) /* Use all on-screen windows
    including and above the specified window ordered from front to back.
    The windowID should be the window number, as from [myWindow
    windowNumber].
    //(kCGWindowListOptionOnScreenBelowWindow |
    kCGWindowListOptionIncludingWindow) /* Use all on-screen windows
    including and below the specified window ordered from front to back.
    The windowID should be the window number, as from [myWindow
    windowNumber].

    CGImageRef ref = CGWindowListCreateImage((flag ? CGRectNull :
    CGRectInfinite), listOption, windowNumber, kCGWindowImageDefault);

        if (ref != NULL) {
            // Take advantage of NSBitmapImageRep's -initWithCGImage:
    initializer, new in Leopard,
            // which is a lot more efficient than copying pixel data into
    a brand new NSImage.
            // Thanks to Troy Stephens @ Apple for pointing this new
    method out to me.
            NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc]
    initWithCGImage:ref];
            NSImage *newImage = nil;
            if (bitmapImageRep) {
                newImage = [[NSImage alloc] initWithSize:[bitmapImageRep
    size]];
                [newImage addRepresentation:bitmapImageRep];
                [bitmapImageRep release];

                if (newImage) {
                    return [newImage autorelease];
                }
            }
            CFRelease(ref);
        }

        return nil;
    }

    > FROM : Anthony Mittaz
    > DATE : Thu Jan 10 05:03:50 2008
    >
    > Thanks this works well except that when I'm using this code the
    > resulting image has no shadow under each browser item.
    >
    > Is there anything i can add to this code the get back my shadows ;-)
    >
    > Here You can see the original IKImageBrowser and the resulting image.
    >
    > http://web.mac.com/sync/Site/IKImageBrowserViewProblem.html

    **********************************************
              ** Alexander Griekspoor  PhD **
    **********************************************
              mekentosj.com

              4Peaks - For Peaks, Four Peaks
      2004 Winner of the Apple Design Awards
              Best Mac OS X Student Product
              http://www.mekentosj.com/4peaks
    **********************************************
  • I had a look to you screenshot and in fact you have the shadows in
    your NSImage.
    But this shadows are very hard to see because the greys are slightly
    different.
    So this is probably a colorspace issue.
    In my sample code I'm using NSDeviceRGBColorSpace to create the
    NSBitmapImageRep.
    I'm not an expert of colorspaces so maybe I'm wrong here.

    You should try to use a different colorspace when creating the bitmap,
    or you can also try the alternate solution suggested by alexander.

    -- Thomas.

    On Jan 10, 2008, at 5:03 AM, Anthony Mittaz wrote:

    > Thanks this works well except that when I'm using this code the
    > resulting image has no shadow under each browser item.
    >
    > Is there anything i can add to this code the get back my shadows ;-)
    >
    > Here You can see the original IKImageBrowser and the resulting image.
    >
    > http://web.mac.com/sync/Site/IKImageBrowserViewProblem.html
    >
    >
    > On 10/01/2008, at 2:24 AM, Thomas Goossens wrote:
    >
    >> Hello Anthony,
    >>
    >> This is because the IKImageBrowserView renders itself into an
    >> openGL surface.
    >> So you can't retrieve the pixels using the usual AppKit code path.
    >>
    >> But instead you can try this:
    >>
    >> //1) allocate a c buffer at the size of the  visible rect of the
    >> image browser
    >> NSRect vRect = [yourImageBrowserView visibleRect];
    >> NSSize size = vRect.size;
    >>
    >> void *buffer = malloc(size.width * size.height * 4);
    >>
    >> //2) read the pixels using openGL
    >> [yourImageBrowserView lockFocus];
    >> glReadPixels(0,
    >> 0,
    >> size.width,
    >> size.height,
    >> GL_RGBA,
    >> GL_UNSIGNED_BYTE,
    >> buffer);
    >> [yourImageBrowserView unlockFocus];
    >>
    >> //3) create a bitmap with those pixels
    >> unsigned char *planes[2];
    >> planes[0] = (unsigned char *) (buffer);
    >>
    >> NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc]
    >> initWithBitmapDataPlanes:planes pixelsWide:size.width
    >> pixelsHigh:size.height bitsPerSample:8 samplesPerPixel:4
    >> hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
    >> bitmapFormat:0 bytesPerRow:size.width*4 bitsPerPixel:32];
    >>
    >> //4) create a temporary image with this bitmap and set it flipped
    >> (because openGL and the AppKit don't have the same pixels
    >> coordinate system)
    >> NSImage *img = [[NSImage alloc] initWithSize:size];
    >> [img addRepresentation:imageRep];
    >> [img setFlipped:YES];
    >> [imageRep release];
    >>
    >> //5) draw this temporary image into another image so that we get an
    >> image without any reference to our "buffer" buffer so that we can
    >> release it after that
    >> NSImage *finalImage = [[NSImage alloc] initWithSize:size];
    >> [finalImage lockFocus];
    >> [img drawAtPoint:NSZeroPoint
    >> fromRect:NSMakeRect(0,0,size.width,size.height)
    >> operation:NSCompositeCopy fraction:1.0];
    >> [finalImage unlockFocus];
    >>
    >> //6) release intermediate objects
    >> [img release];
    >> free(buffer);
    >>
    >> -- Thomas.
    >>
    >>
    >> On Jan 9, 2008, at 5:00 PM, Anthony Mittaz wrote:
    >>
    >>> Hello,
    >>>
    >>> I'm currently trying to capture the content of a
    >>> IkImageBrowserView but the image resulting from this operation is
    >>> always blank.
    >>>
    >>> My code:
    >>>
    >>> [MyIkImageBrowserView lockFocus];
    >>> NSBitmapImageRep *imageRep = [MyIkImageBrowserView
    >>> bitmapImageRepForCachingDisplayInRect:[MyIkImageBrowserView frame]];
    >>> [MyIkImageBrowserView cacheDisplayInRect:[MyIkImageBrowserView
    >>> frame] toBitmapImageRep:imageRep];
    >>> [MyIkImageBrowserView unlockFocus];
    >>>
    >>> NSImage *image = [[NSImage alloc]
    >>> initWithSize:sizeOfMyIkImageBrowserView];
    >>> [image addRepresentation:imageRep];
    >>>
    >>>
    >>> [imageViewOfTheView setImage:image];
    >>>
    >>> If someone could give me a better solution i would be more than
    >>> happy.
    >>>
    >>> Thanks
    >>> Anthony Mittaz
    >>
    >
previous month january 2008 next month
MTWTFSS
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
Go to today