Printing direct from OF (via CUPs, OSX example)

Hey All,

I couldn’t find any examples of how to print from OF, so I spent today working out how to do it.

Download gutenprint-5.2.3.tar.bz2 from

http://gimp-print.sourceforge.net/MacOSX.php

And the DMG if you want to install the drivers, but it should all be there.

[API-overview-here:–

http://www.cups.org/documentation.php/api-overview.html

How to print here:

http://www.cups.org/documentation.php/api-cups.html

Probably should be using their native api for file IO but couldn’t be bothered.

http://www.cups.org/documentation.php/api-filedir.html]

opened it up, went in and typed

./configure

make

then

sudo make install

Then added it to an OF project by:
In the project window, double-click on the Targets group and control-click on the simple target to show the context menu. Choose Existing Framework… from the Add submenu. When the file chooser sheet appears, press the / key and enter “/usr/lib”. Scroll down the file list and select the libcups.dylib file. Click the Add button in the file chooser and attributes sheets.

Then the following source, with a JPG file in the data folder called bikers.jpg in it, should work. You’ll have to comment out the printing bits the first time around - to get the correct name of the printer. Don’t forget to change it, as it will be different from mine.

All done using a duplicated version of the alladdons project from:

http://www.openframeworks.cc/files/0057-…-ithGui.zip

Source follows:

[testApp.cpp]

  
#include "testApp.h"  
  
  
//--------------------------------------------------------------  
void testApp::setup(){	  
	ofBackground(127,127,127);  
	  
	int i;  
	cups_dest_t *dests, *dest, *correctPrinter;  
	int num_dests = cupsGetDests(&dests);  
	  
	string theRightPrinterName = string("MP620_series__00_00_85_ee_44_3e_");  
	  
	for (i = num_dests, dest = dests; i > 0; i --, dest ++)  
	{  
		const char *value;  
		value = cupsGetOption("printer-info", dest->num_options, dest->options);  
		printf("%s (%s)\n", dest->name, value ? value : "no description");	  
		  
		if(theRightPrinterName == dest->name)  
		{  
			correctPrinter = dest;  
		}  
		  
	}  
	  
	int job_id;  
	  
	/* Print a single file */  
	//job_id = cupsPrintFile(correctPrinter->name, "/usr/share/cups/data/testprint.ps",  
	//					   "Test Print JGL", correctPrinter->num_options, correctPrinter->options);  
	  
	string thePath = ofToDataPath("bikers.jpg");  
	  
	char * cstr;  
	  
	cstr = new char [thePath.size()+1];  
	strcpy (cstr, thePath.c_str());  
	  
	job_id = cupsPrintFile(correctPrinter->name, cstr ,  
						   "Test Print JGL3", correctPrinter->num_options, correctPrinter->options);  
	  
	if (job_id == 0)  
		cout << "Printer error is " << cupsLastError() << endl;  
	  
	  
	cupsFreeDests(num_dests, dests);  
	delete[] cstr;  
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
	ofSetColor(0xffffff);  
	ofDrawBitmapString("This app just prints. Have a look at the console for feedback on printer names.", 100,100);  
}  
  
  
//--------------------------------------------------------------  
void testApp::keyPressed  (int key){   
}  
  
//--------------------------------------------------------------  
void testApp::keyReleased  (int key){   
}  
  
//--------------------------------------------------------------  
void testApp::mouseMoved(int x, int y ){  
}  
  
//--------------------------------------------------------------  
void testApp::mouseDragged(int x, int y, int button){  
}  
  
//--------------------------------------------------------------  
void testApp::mousePressed(int x, int y, int button){  
}  
  
//--------------------------------------------------------------  
void testApp::mouseReleased(){  
  
}  
  

[testApp.h]

  
#ifndef _TEST_APP  
#define _TEST_APP  
  
// JUST TO MAKE SURE IT DOESN'T BREAK ADDONS  
#define OF_ADDON_USING_OFXOPENCV  
#define OF_ADDON_USING_OFXOBJLOADER  
#define OF_ADDON_USING_OFXDIRLIST  
#define OF_ADDON_USING_OFXVECTORMATH  
#define OF_ADDON_USING_OFXNETWORK  
#define OF_ADDON_USING_OFXVECTORGRAPHICS  
#define OF_ADDON_USING_OFXOSC  
#define OF_ADDON_USING_OFXTHREAD  
#define OF_ADDON_USING_OFXXMLSETTINGS  
  
  
#include "ofMain.h"  
#include "ofAddons.h"  
#include <cups/cups.h>  
  
class testApp : public ofSimpleApp{  
	  
	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();  
		  
		// we don't actually use these  
		// just checking to see if they   
		// all work in the same place :)  
		  
		ofxCvGrayscaleImage cvGray;  
		ofxObjLoader obj;  
		ofxDirList dirList;  
		ofxVec2f p;  
		ofxTCPClient client;  
		ofxTCPServer server;  
		ofxOscSender osc_sender;  
		ofxThread thread;  
		ofxXmlSettings settings;  
};  
  
#endif  
	  
  

If CUPs is working correctly then you should be able to type:

http://localhost:631/

Into your browser to look at the printer names, and various print queues, as well as running test prints.

Cheers,

JGL

that’s really awesome –

I just wanted to quickly mention a simple alternative, if you could output whatever you want to print, would be command line printing via the system command, ie:

  
  
system  (  "lp ../../../data/blah.jpg"  );  
  

or something like that –

some info on lp:

http://developer.apple.com/DOCUMENTATIO-…-/lp.1.html

and more detailed info: (this uses lpr, not lp)

http://www.macosxhints.com/article.php?-…-4071837531

take care!
zach

Great, nice to have the command line option too.

Is there a windows alternative to this?

Windows is what I have been using it on.

Or do you mean the command line option?

JGL

i’ve read the thread:
http://msdn.microsoft.com/en-us/library/dd183521%28VS.85%29.aspx
But i haven’t found out how to print image.
I created a HBITMAP like this:
HBITMAP hbit = CreateDIBitmap(hDC,&bmih,CBM_INIT,image.getPixels(),&bmi,DIB_RGB_COLORS);
where image is an instance of ofImage, but the result is tricky.

A long way around but that doesn’t require any win32 knowledge (or love) is to save out \temp\imageToPrint.jpg and then call:

  
system("\\Windows\\System32\\rundll32.exe \\Windows\\System32\\shimgvw.dll, ImageView_PrintTo \\temp\\imageToPrint.jpg <PrinterName>");  

If you’re running this on Vista or 7 then you also need to go into the app properties and find the switch for “Run as Administrator” otherwise all the print requests will just get thrown away with no error or indication that anything has gone wrong.

Not pretty but does the job - check your printer defaults.

S.

Sorry for reopening this thread, but didn’t manage to get this working in latest OF version.

I want to send a generated image to my printer!

can anyone help?

Just printed a.png file inside OF by calling:

  
system("rundll32.exe c:\\Windows\\System32\\shimgvw.dll, ImageView_PrintTo c:\\temp\\a.png \"HP Officejet Pro K850 Series\"");  

i put this code in setup() to check.
it worked.

HP Officejet Pro K850 Series is my default printer connected to my computer ( where OF is running) locally.
and i put a.png file in c:\temp folder.

some more functions

  
void testApp::listPrinters() {   
      
    int i;  
    cups_dest_t *dests, *dest;  
    int num_dests = cupsGetDests(&dests);  
      
    for (i = num_dests, dest = dests; i > 0; i --, dest ++)  
    {  
        if (dest->instance)  
            printf("%s/%s\n", dest->name, dest->instance);  
        else  
            puts(dest->name);  
    }  
      
  
      
    printf("\noptions - - - - %s - - - -\n\n", printerName.c_str());  
  
    cups_dest_t *mydest = cupsGetDest(printerName.c_str(), NULL, num_dests, dests);  
    cups_option_t *option;  
      
	if (mydest){  
          
        for(i = mydest->num_options, option = mydest->options; i > 0; i--, option ++) {  
              
            if (option->value)  
            printf("%s : %s\n", option->name, option->value);  
            else printf("  - - %s\n", option->name);  
        }  
              
  
    }  
   
      
    cupsFreeDests(num_dests, dests);  
}  

  
void testApp::printImage() {   
      
    int num_options = 0;  
    cups_option_t *options = NULL;  
   
    string path = "../../../data/";  
    string currentFile = "test.jpg";  
    string printFile = path + currentFile;  
    string optionen = "landscape";  
    //optionen = "media=DS_PC_size"; //ds40  
      
    //num_options = cupsParseOptions(optionen.c_str(), num_options, &options);  
      
    last_job_id = cupsPrintFile( printerName.c_str(), printFile.c_str(), "Test Print", num_options, options);  
      
    cupsFreeOptions(num_options,options);  
}  

  
void testApp::clearAllJobs() {   
      
    /*  
    cups_job_t *jobs;  
      
    int num_jobs = cupsGetJobs(&jobs, printerName.c_str(), 1, -1);  
    for (int i = 0; i < num_jobs; i ++) {  
          
        cupsCancelJob2(CUPS_HTTP_DEFAULT, printerName.c_str(), jobs[i].id, 1);  
    }  
    cupsFreeJobs(num_jobs, jobs);  
    */  
      
    cupsCancelJob2(CUPS_HTTP_DEFAULT, printerName.c_str(), CUPS_JOBID_ALL, 1);  
      
      
}  

  
void testApp::checkPrinterStatus() {   
      
    //cups_dest_t *dest;  
    cups_job_t *jobs;  
  
    info = "lastJob " + ofToString(last_job_id)+ "\n";  
      
    /* Get my jobs (1) with any state (-1) */  
    int num_jobs = cupsGetJobs(&jobs, printerName.c_str(), 0, CUPS_WHICHJOBS_ALL);  
      
      
    for (int i = 0; i < num_jobs; i ++) {  
          
        ipp_jstate_t job_state = jobs[i].state;  
          
        switch (job_state)  
        {  
            case IPP_JOB_PENDING :  
                info += "Job " + ofToString(jobs[i].id) + " is pending.\n";  
                break;  
            case IPP_JOB_HELD :  
                info += "Job " + ofToString(jobs[i].id) + " is held.\n";  
                break;  
            case IPP_JOB_PROCESSING :  
                info += "Job " + ofToString(jobs[i].id) + " is processing.\n";  
                break;  
            case IPP_JOB_STOPPED :  
                info += "Job " + ofToString(jobs[i].id) + " is stopped.\n";  
                break;  
            case IPP_JOB_CANCELED :  
                info += "Job " + ofToString(jobs[i].id) + " is pending.\n";  
                break;  
            case IPP_JOB_ABORTED :  
                info += "Job " + ofToString(jobs[i].id) + " is aborted.\n";  
                break;  
            case IPP_JOB_COMPLETED :  
                info += "Job " + ofToString(jobs[i].id) + " is completed.\n";  
                break;  
        }  
          
    }   
      
    /* Free the job array */  
    cupsFreeJobs(num_jobs, jobs);  
      
    last_err_info = cupsLastErrorString();  
      
    // get printer state  
      
    //3 = idle;  
    //4 = processing  
    //5 = stopped  
      
    cups_dest_t *dests;  
    int num_dests = cupsGetDests(&dests);  
    cups_dest_t *mydest = cupsGetDest(printerName.c_str(), NULL, num_dests, dests);  
    const char *value;  
      
	if (mydest){  
          
        printerState = cupsGetOption("printer-state", mydest->num_options, mydest->options);  
        printerStateReason = cupsGetOption("printer-state-reasons", mydest->num_options, mydest->options);  
        printer_info = printerStateReason;  
    }  
    else printer_info="no printer info\n";  
      
    cupsFreeDests(num_dests, dests);  
}  

  
bool testApp::isPrinterSane() {   
      
    bool printerOK = true;  
      
    // printer has stopped  
    if(printerState == "5") printerOK = false;  
  
    // printer is offline  
    size_t found=printerStateReason.find("offline");  
    if (found!=string::npos) printerOK = false;    
  
    // printer has anything to tell  
    if (printerStateReason!="none") printerOK = false;    
      
    // there was another error  
    if (last_err_info!="successful-ok") printerOK = false;   
      
    return printerOK;  
}  

commited a simple CUPS wrapper.

https://github.com/motoishmz/ofxCUPS

I’m also trying to print with the system function on
Windows 8.1
OF 0.8.4
visual studio 12

When I run this instruction with cmd prompt (cmd.exe), it works

rundll32 C:\WINDOWS\system32\shimgvw.dll,ImageView_PrintTo        c:\Users\taprik\Desktop\selection\IMG_1178.JPG DS-RX1

My printer is a DS-RX1

When I try to run it in the setup of an OF app, nothing happens, even If I ran the app ass an administrator.
I pass this to the system function.

rundll32.exe   C:\\WINDOWS\\System32\\shimgvw.dll,ImageView_PrintTo
c:\\Users\\taprik\\Bureau\\selection\\IMG_1178.JPG DS-RX1"

And the curious thing is when I try to run the same (first) command line with the windows powershell coming with the application Github for windows, it doesn’t work too.

Is the system() function related to the cmd application ?
Any ideas are welcome
Best

Hello

Take a look at this

I print in a win8 with just this printer DS-RX1

ofSystem("rundll32.exe c:\\Windows\\System32\\shimgvw.dll, ImageView_PrintTo c:\\temp\\test.png \"DS-RX1 (Copiar 2)\"");

Thanks Pandereto,

I can confirm that it’s also working on Win 8.1

I’ve just made a mistake with Bureau and Desktop name (the Bureau folder is called Desktop) :wink:

On thing to consider is that the printer get a name distint on each usb, so truy to plug it all the times in the same usb port, if not you will get multiples names for the printer. Take that in mind because it gives me some hours of frustration until i see this.

Absolutly !
When it’s connected on the first port it’s DS-RX1
on the second DS-RX1 (Copie 1)
on the third DS-RX1 (Copie 2)

I also spend sometimes on that :wink:

Best Regards Panderoto