Create an image with ofFbo and ofImage bigger than the screen

Hello,

I try to create an image bigger than the screen :
`
ofApp.h :

ofImage ,imgSaver,imgLoader;
ofFbo fbo;
ofPixels pix;

`

`
ofApp.cpp :

	imgLoader.load("input.jpg");
	pix.allocate(3840,2560,OF_IMAGE_COLOR);
	fbo.allocate(3840,2560);

	fbo.begin();

	fbo.clear();
	for(int x=0;x<121;x++){
		for(int y=0; y<81; y++){
			imgLoader.drawSubsection(32*x,32*y,32,32,384,0,32,32);
		}
	}
	fbo.readToPixels(pix);
	ofSaveImage(pix,"output.jpg",OF_IMAGE_QUALITY_BEST);

	fbo.end();

`

But the output is only grey. I have found a lot of answer in the forum ( so here ).
It work fine, but alone for the size of the window. Is it possible to save an image bigger than the window ?

Hi, give this a shot, if you get 4k images saved into your data folder when you hit space then the problem is elsewhere.

#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp
{

	public:

		// -------------------------
		void setup()
		{
			fbo.allocate(4096,4096);
			saveNextFrame = false;
		}
	
		// -------------------------
		void update()
		{
			if( saveNextFrame )
			{
				ofPixels tmpPixels;
				fbo.readToPixels( tmpPixels );
				ofSaveImage( tmpPixels, ofGetTimestampString() + ".png" );
				saveNextFrame = false;
			}
		}
	
		// -------------------------
		void draw()
		{
			fbo.begin();
			ofClear( ofColor::black );
			for( int i = 0; i < 10; i++ )
			{
				ofSetColor( ofFloatColor::fromHsb( ofRandom(1), 1, 1) );
				ofDrawCircle( ofRandom(fbo.getWidth()),ofRandom(fbo.getHeight()), fbo.getWidth() / 10 );
			}
			fbo.end();
			
			ofSetColor( ofColor::white );
			fbo.draw(0,0,ofGetWidth(),ofGetHeight());
		}

		// -------------------------
		void keyPressed(int key)
		{
			if( key == ' ' )
			{
				saveNextFrame = true;
			}
		}

		ofFbo fbo;
		bool saveNextFrame;
};
1 Like

Ok, i’m beginner in c++ and with openframework. The problem come from me.
Here is my last test, and it’s working fine.

The code for another beginner who search to solve this problem :

classMap.h

	#include "ofMain.h"

	class classMap{
		private :
			ofImage arbre,boue,eau,herbe,rocher,lac;
			ofFbo fbo;
		
		
		
		public :
			classMap();
			void saveMap();
			bool remplirHerbe();
			bool ajoutLac( int x, int y);
		

	};

classMap.cpp

#include "classMap.h"

// constructeur
classMap::classMap(){
	arbre.loadImage("arbre.png");
	boue.loadImage("boue.jpg");
	eau.loadImage("eau.jpg");
	herbe.loadImage("herbe.jpg");
	rocher.loadImage("rocher.png");
	lac.loadImage("lac.jpg");
	fbo.setUseTexture(false);
	fbo.allocate(3840,2560);
}

bool classMap::remplirHerbe(){

	fbo.begin();
	//dessine un lac carré partout sur la map
	for(short int x=0;x<120;x++){
		for(short int y=0;y<80;y++){
			if ( y == 0 ){
				eau.draw(x*32,y*32,32,32);
			} else {
				herbe.draw(x*32,y*32,32,32);
			}
		}
	}
	fbo.end();
	return true;

}

bool classMap::ajoutLac( int x, int y){

	// on verifie que le lac sort pas de la map
	if ( x > 124 || x < 0 || y > 74 || y < 0){
		ofLog(OF_LOG_ERROR,"Coordonnees incorrect, le lac sort de la map");
		return false;
	} else {
		for (int cx=0;cx<5;cx++){
			for (int cy=0;cy<5;cy++){
				fbo.begin();
				lac.drawSubsection((32*cx)+(x*32),(32*cy)+(y*32),32,32,cx*64,cy*64,64,64);
				fbo.end();
			}
		}
	}

}

void classMap::saveMap(){

	//on stock les pixels de l'image en low-level pour passer d'un objet à l'autre
	// PUTAIN C'ETAIT CHIANT A COMPRENDRE CA !   
	unsigned char* pixels = new unsigned char[3840*2560*3];  ;  
	ofImage saveImage;  
	saveImage.allocate(3840,2560,OF_IMAGE_COLOR);  
	saveImage.setUseTexture(false);  

	// On copie les pixel de FBO vers OFIMAGE qui possède la fonction d'enregistrement en fichier
	fbo.begin();
	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glReadPixels(0, 0, fbo.getWidth(), fbo.getHeight(), GL_RGB, GL_UNSIGNED_BYTE, pixels);    
	saveImage.setFromPixels(pixels, fbo.getWidth(), fbo.getHeight(), OF_IMAGE_COLOR);    
	saveImage.saveImage("output.jpg", OF_IMAGE_QUALITY_MEDIUM);  
	fbo.end();  
	ofLog(OF_LOG_VERBOSE, "Image is safe ! Coffe time !"); 
}

ofApp.h

#pragma once

#include "ofMain.h"
#include "../classMap.h"

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();

		void keyPressed(int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y );
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void mouseEntered(int x, int y);
		void mouseExited(int x, int y);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);

		classMap test1;	
};

ofApp.cpp

#include "ofApp.h"

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

	// J'veux tout savoir sur les logs ! Oui on est fou et on aime ça :D
	 ofSetLogLevel(OF_LOG_VERBOSE);
 
	 bool succes = false;

	 succes = test1.remplirHerbe();
	 ofLogVerbose() << "remplirHerbe => "<< succes;
	 succes = test1.ajoutLac(10,10);
	 ofLogVerbose() << "ajoutLac(10,10) => "<< succes;
	 succes = test1.ajoutLac(25,10);
	 ofLogVerbose() << "ajoutLac(25,10) => "<< succes;
	 succes = test1.ajoutLac(25,25);
	 ofLogVerbose() << "ajoutLac(25,25) => "<< succes;
	 succes = test1.ajoutLac(50,30);
	 ofLogVerbose() << "ajoutLac(50,30) => "<< succes;
	 // Try with bad value
	 succes = test1.ajoutLac(150,100);
	 ofLogVerbose() << "ajoutLac(150,100) => "<< succes;
	 succes = test1.ajoutLac(-50,-35);
	 ofLogVerbose() << "ajoutLac(-50,-35) => "<< succes;

	 //save
	 test1.saveMap();
 

}[...]

main.cpp

#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
	ofSetupOpenGL(1024,768,OF_WINDOW);			// <-------- setup the GL context

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp(new ofApp());

}
1 Like