ofImage::setFromPixels() causes crash on iOS

Hi, I just figured out calling ofImage::setFromPixels() causes crash on iOS while it works fine on MacOS.

Here’s my test code.

ofFbo fbo;
ofImage img;

//--------------------------------------------------------------
void ofApp::setup(){

    ofSetBackgroundColor(0);
    
    //allocate an image space
    img.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR_ALPHA);
    
    //clear and allocate a fbo
    fbo.begin();
    ofClear(0,0,0,0);
    fbo.end();
    fbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA);
    
    //draw an ellipse to the fbo
    fbo.begin();
    ofClear(0,0,0,0);
    ofSetColor(255);
    ofDrawEllipse(ofGetWidth()/2, ofGetHeight()/2, ofGetWidth(), ofGetHeight());
    fbo.end();
    
    //copy pixels from fbo to image
    ofPixels pixels;
    fbo.getTexture().readToPixels(pixels);
    img.setFromPixels(pixels);
}

//--------------------------------------------------------------
void ofApp::update(){
    
}

//--------------------------------------------------------------
void ofApp::draw(){
    
    //draw the image
    img.draw(0, 0, ofGetWidth(), ofGetHeight());
}

And this is the result you will see if you run the code on MacOS.

However, if you run the same code on iOS, it crashes on startup with the following error.

It doesn’t produce any error if I comment out img.setFromPixels(pixels);

Should I report this on github?
And Is there any other way to copy pixels from ofFbo to ofImage?
Thanks!

Hi! The app I work on does that successfully on iOS. But we allocate using OF_PIXELS_RGBA (=4) instead of OF_IMAGE_COLOR_ALPHA (=0x02).

Oh wait, I got confused: your pixels are actually not allocated. I was looking at img above. Maybe that’s the reason?

Hi, @hamoid

I added pixels.allocate(ofGetWidth(), ofGetHeight(), OF_PIXELS_RGBA); after ofPixels pixels;

And it no longer crashed but I cannot see the white ellipse and all I see is just a black screen.

Is it necessary to allocate ofPixels before calling ofTexure::readToPixels()?
Shouldn’t this method internally allocate the size too?

Not sure if it should be allocated automatically. I just look at how it’s done in the app I’ve been working on since last year.

I remember another issue: we don’t initialize things inside setup, instead we do this:

// update
if(ofGetFrameNum() == 5) {
  // my setup stuff
}

It looks silly, but it fixed some initialization issues with FBOs. This is what I wrote in a commit on June 1st: “Delay setup for a few frames. Delaying setup might help on iOS with FBOs”.

See Fbo.begin() inside setup breaks rendering on iOS

Thanks for the tip.
I tried it but it didn’t fix the problem.

Could you show your updated code?

//--------------------------------------------------------------
void ofApp::setup(){	

    ofSetBackgroundColor(0);
}

//--------------------------------------------------------------
void ofApp::update(){
    
    if (ofGetFrameNum() == 5) {
     
        //allocate an image space
        img.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR_ALPHA);
        
        //clear and allocate a fbo
        fbo.begin();
        ofClear(0,0,0,0);
        fbo.end();
        fbo.allocate(ofGetWidth(), ofGetHeight(), GL_RGBA);
        
        //draw an ellipse to the fbo
        fbo.begin();
        ofClear(0,0,0,0);
        ofSetColor(255);
        ofDrawEllipse(ofGetWidth()/2, ofGetHeight()/2, ofGetWidth(), ofGetHeight());
        fbo.end();
        
        //copy pixels from fbo to image
        ofPixels pixels;
        pixels.allocate(ofGetWidth(), ofGetHeight(), OF_PIXELS_RGBA);
        fbo.getTexture().readToPixels(pixels);
        img.setFromPixels(pixels);
    }
}

//--------------------------------------------------------------
void ofApp::draw(){

    if (ofGetFrameNum() > 5) {
    
        //draw the image
        img.draw(0, 0, ofGetWidth(), ofGetHeight());
    }
}

This doesn’t crash but doesn’t draw properly as I said.
if you remove pixels.allocate(ofGetWidth(), ofGetHeight(), OF_PIXELS_RGBA); it still crashes.

I would not call ofClear() before allocating the fbo. But I don’t know what can be the issue :confused:

I tried it but didn’t help either… :disappointed:

I just tested this on Android and the same problem occurred.
Just like on iOS, It crashes when calling img.setFromPixels(pixels);
And if I add pixels.allocate(ofGetWidth(), ofGetHeight(), OF_PIXELS_RGBA); after ofPixels pixels; it doesn’t crash but doesn’t draw properly. All I see is a black screen.

What about your main.mm file? Ours:

    //  here are the most commonly used iOS window settings.
    //------------------------------------------------------
    ofiOSWindowSettings settings;
    settings.enableRetina = true; // enables retina resolution if the device supports it.
    settings.enableDepth = false; // enables depth buffer for 3d drawing.
    settings.enableAntiAliasing = false; // enables anti-aliasing which smooths out graphics on the screen.
    settings.numOfAntiAliasingSamples = 4; // number of samples used for anti-aliasing.
    settings.enableHardwareOrientation = true; // enables native view orientation.
    settings.enableHardwareOrientationAnimation = true; // enables native orientation changes to be animated.
    settings.glesVersion = OFXIOS_RENDERER_ES2; // type of renderer to use, ES1, ES2, etc. we need es2 for IMGui
    //ofCreateWindow(settings);

    ofAppiOSWindow * window = (ofAppiOSWindow *)(ofCreateWindow(settings).get());

Hey Thanks for your help @hamoid

I could fix the problem by changing fbo.getTexture().readToPixels(pixels); to fbo.readToPixels(pixels); on iOS.

It also fixed the problem on Android.
Thanks for help!

https://github.com/openframeworks/openFrameworks/issues/5790

1 Like