Forum Archive

UIImageJPEGRepresentation

Cethric

I am attempting to save the currently visible ui.View to a JPEG image file however when it saves it always returns a blank white JPEG image. My current code.

def captureNow(sender):
    print "Capture Screen"
    layer = v.layer()
    UIGraphicsBeginImageContext(layer.bounds().size)
    layer.renderInContext_(UIGraphicsGetCurrentContext())
    # v.drawViewHierarchyInRect_afterScreenUpdates_(v.bounds(), True)
    image = ObjCInstance(UIGraphicsGetImageFromCurrentImageContext())
    UIGraphicsEndImageContext()

    vt = ui.View()
    vt.width = 800
    vt.height = 600

    UIImageView = ObjCClass('UIImageView')
    iview = UIImageView.alloc().initWithImage_(image)
    iview.setFrame_(ObjCInstance(vt).bounds())

    print iview

    ObjCInstance(vt).addSubview_(iview)
    vt.present('sheet')

    UIImageJPEGRepresentation(image, 1.0).writeToFile_atomically_('test.jpg', True)
def UIImageJPEGRepresentation(image, compressionQuality):
    func = c.UIImageJPEGRepresentation
    func.argtypes = [ctypes.c_void_p, ctypes.c_float]
    func.restype = ctypes.c_void_p
    return ObjCInstance(func(image.ptr, compressionQuality))

I have attempted to check to see if it is the result of saving it from a UIImage object to NSData and then to a file by trying to show the UIImage in a UIImageView however I cannot get that to work.

omz

That (mostly) works for me. Maybe your view doesn't have actual content? drawViewHierarchyInRect: etc. only work within the view hierarchy, i.e. it wouldn't render any views that are on top of (but not children) of the view you're rendering, even though they appear inside the view on screen...

Aside: ui.View module already has a draw_snapshot method that essentially does the same thing (edit: just noticed this is undocumented)

Cethric

@omz, thank you for the information however after a little bit of research I think it has something to do with the AVCaptureVideoPreviewLayer layer that I am trying to save.

omz

Ah, yeah, those are a bit special... I think it should be possible to get a video frame from the camera some other way, but I haven't yet had the time to look into it. The low-level camera APIs are somewhat difficult to work with via ctypes...

Cethric

So I have noticed. I have found two solutions, one involving blocks and one involving a ObjC protocol (which from apples documentation does not subclass NSObject like most other ObjC classes can) but rather subclasses nothing so I cannot create a protocol based delegate object myself (I don't think).
I will do some further research and post any findings.

Cethric

I have been able to create a delegate class to get a sampleImageBuffer I am now working on getting the image from that. I think it will work. (Trying to make a CGContext at the moment).

Cethric

It was going so well until I got to creating a CGBitmapContext
Code:

def CGBitmapContextCreate(baseAddress, width, height, param_0, bytesPerRow, colorSpace, flags):
    func = c.CGBitmapContextCreate
    func.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_void_p, ctypes.c_int32]
    func.restype = ctypes.c_void_p
    print ObjCInstance(colorSpace).ptr
    result = func(baseAddress, width, height, param_0, bytesPerRow, ObjCInstance(colorSpace).ptr, flags)
    print result
    if result is not None:
        return result
    else:
        raise RuntimeError('Failed to create context')

Will always fail. Is there some way that I can get an error log on why this is failing other than me throwing a RuntimeError?

Cethric

I solved the issue, with information from here however I would still like to know if I can get detailed log information.

JonB

did you check all of your inputs?

http://stackoverflow.com/questions/10895160/cgbitmapcontextcreate-returns-null

colorspace/bytesperrow seems to be a common mistake.

Cethric

Ok I have got it to render the image to a file however the render image is still incorrect.
Script available here

EDIT:
It now renders in black and white.

Any ideas?