Deprecated: Function split() is deprecated in /mnt/home/cn/cn-web/songshu/lib/pages/DisplayBlogArticleList.php on line 36
Articles matching: type
ChipmunkNinja
Ninjas are deadly. Chipmunk Ninjas are just weird.
About this blog
Marc Travels
Marc on Twitter
JustLooking on Twitter

Marc Wandschneider is a professional software developer with well over fifteen years of industry experience (yes, he really is that old). He travels the globe working on interesting projects and gives talks at conferences and trade shows whenever possible.

My Publications:

My book, "Core Web Application Programming with PHP and MySQL" is now available everywhere, including Amazon.com

My "PHP and MySQL LiveLessons" DVD Series has just been published by Prentice-Hall, and can be purchased on Amazon, through Informit, or Safari


ABCHKMPRaRoSTVW
xxxxx-xxxxxxxxx

Popular Articles:


Top Tags:


Recent Comments:

cncool wrote:

GLint zeroOpacity = 0;
[[self openGLContext] setValues:&zeroOpacity forParameter:NSOpenGLCPS...
Posted to: Things I've learned about CoreImage (and Quartz, and OpenGL) in two weeks
Oct 26, 2006 | 07:15:59
Cocoa Programming: How to fetch Paper Names, Localised Names, and Page Sizes for a Printer
By marcwan

For a recent project written in Cocoa for Mac OS X, I found myself wanting to get the following set of information for a particular printer:

  • A list of all available paper types
  • Printable names for these paper types
  • Page Sizes
  • Imageable Margins for those same pages.

It turns out that there is no way to get this in Cocoa, and actually it’s not all that easy to find this information in Carbon either.

So, after some research and investimigation on the Intarwebs, as well as much combing through the various PM* header files (buried so deep in a directory on my machine that I had to save the directory name somewhere so I’d be able to find them again!), I’ve come up with the following method to do all the above.

CUTOFF
It returns an NSArray. Each paper type supported by the printer gets one item in the array, which is an NSDictionary set-up to use key/value pairs. There are the following pairs:

  • PAPER_NAME (NSString): The system name for the paper.
  • LOCALISED_PAPER_NAME (NSString): The display name for the paper.
  • PAPER_SIZE (NSValue): The size of the paper in 72dpi User Space Units. Use [NSValue -sizeValue] to get the actual value.
  • PAPER_IMAGEABLE_MARGINS (NSValue): The imageable bounds of the paper in 72dpi User Space Units. Use [NSValue -rectValue] to get the actual value.

I’ve noticed that there are some issues with memory allocation in the following code: If I run it a few hundred thousand times, I start to see some memory leaks, which is most upsetting. Given that I can’t free anything else in this code without crashing it, I worry that it might be a system leak. However, given how rarely this code is ever executed (maaaaayyybe 5-10x per process lifetime in an extremely print happy case), It’s something that can be investigated later.

Here be the code, laddies:


+ (NSArray *)paperSizesAndNamesForPrinter: (NSString *)printerName
{
    PMPrintSession printSession = NULL;
    CFArrayRef printerList = NULL;
    PMPrinter thisPrinter = NULL;
    int numPrinters;
    OSStatus err;
    int i;

    err = PMCreateSession(&printSession);
    if (err != noErr)
        [JLUnknownPrinterErrorException generate];

    @try
    {
        /**
         * Get a list of all printers.
         */
        err = PMServerCreatePrinterList(kPMServerLocal, &printerList);
        if (err != noErr)
            [JLUnknownPrinterErrorException generate];

        /**
         * Now, loop through them until we find the printer we're looking
         * for.  Then we can get the properties.  We throw if the printer
         * isn't found.
         */
        numPrinters = CFArrayGetCount(printerList);
        for (i = 0; i < numPrinters; i++)
        {
            CFStringRef thisPrinterName;
            thisPrinter = (PMPrinter)CFArrayGetValueAtIndex(printerList, i);

            thisPrinterName = PMPrinterGetName(thisPrinter);
            if ([(NSString *)thisPrinterName caseInsensitiveCompare: printerName] == NSOrderedSame)
            {
                CFRelease(thisPrinterName);
                return [NSPrinter extractInfoFromPrinter: thisPrinter];
            }

            CFRelease(thisPrinterName);
            thisPrinter = NULL;
        }
    }
    @finally
    {
        /**
         * Clean up.  Exceptions will still throw back up the stack.
         */
        if (printerList != NULL) CFRelease(printerList);
        PMRelease(printSession);
    }

    return nil;
 }

+ (NSArray *)extractInfoFromPrinter: (PMPrinter)printerInfo
{
    NSMutableArray *outputArray = [NSMutableArray arrayWithCapacity: 10];
    CFStringRef paperName = NULL, localised = NULL;
    NSMutableDictionary *paperProps;
    CFArrayRef paperList;
    PMPaper thisPaper;
    int j, numPapers;
    OSStatus err;

    /**
     * First, get a list of the paper sizes and create an NSArray 
     * for them all.
     */
    err = PMPrinterGetPaperList(printerInfo, &paperList);
    if (err != noErr)
        [JLUnknownPrinterErrorException generate];

    @try
    {
        numPapers = CFArrayGetCount(paperList);
        for (j = 0; j < numPapers; j++)
        {
            NSValue *imageableMargins, *paperSize;
            double paperHeight, paperWidth;
            NSRect adjustedMargins;
            PMPaperMargins margie;

            thisPaper =  (PMPaper)CFArrayGetValueAtIndex(paperList, j);

            /**
             * Get the system non-localised paper name.
             */
            PMPaperGetID(thisPaper, &paperName);


            /**
             * Get the localised paper name.
             */
            err = PMPaperGetName(thisPaper, &localised);
            if (err != noErr)
                [JLUnknownPrinterErrorException generate];

            /**
             * Finally, build up the size.
             */
            err = PMPaperGetHeight(thisPaper, &paperHeight);
            if (err != noErr)
                [JLUnknownPrinterErrorException generate];
                    
            err = PMPaperGetWidth(thisPaper, &paperWidth);
            if (err != noErr)
                [JLUnknownPrinterErrorException generate];

            paperSize = [NSValue valueWithSize: NSMakeSize(paperWidth, paperHeight)];

            /**
             * This gets the imageable margins for the page type, which
             * is very useful.
             */
            PMPaperGetMargins(thisPaper, &margie);
            adjustedMargins = NSMakeRect(margie.left, margie.top,
                                         (paperWidth - margie.left - margie.right),
                                         (paperHeight - margie.top - margie.bottom));
            imageableMargins = [NSValue valueWithRect: adjustedMargins];

            /**
             * Finally, create a dictionary with these values and then add
             * them to da array.
             */
            paperProps = [NSMutableDictionary dictionaryWithCapacity: 3];
            [paperProps setValue: [NSString stringWithString: (NSString *)paperName]
                        forKey: PAPER_NAME];
            [paperProps setValue: [NSString stringWithString: (NSString *)localised]
                        forKey: LOCALISED_PAPER_NAME];
            [paperProps setValue: paperSize forKey: PAPER_SIZE];
            [paperProps setValue: imageableMargins forKey: PAPER_IMAGEABLE_MARGINS];

            [outputArray addObject: paperProps];

            CFRelease(paperName);
            CFRelease(localised);
            paperName = NULL;
            localised = NULL;
        }
    }
    @finally
    {
        if (paperName) CFRelease(paperName);
        if (localised) CFRelease(localised);
    }

    return outputArray;
}


I actually implemented this as a category on NSPrinter. You can do this too by simply creating the following header:


#import <Cocoa/Cocoa.h>

#define PAPER_NAME               @"paper_name"
#define LOCALISED_PAPER_NAME     @"localised_paper_name"
#define LOCALIZED_PAPER_NAME     @"localised_paper_name"
#define PAPER_SIZE               @"paper_size"
#define PAPER_IMAGEABLE_MARGINS  @"printable_margins"

@interface NSPrinter (MyNSPrinterExtensions)

// returns an NSArray of NSDictionaries: see constants above.
+ (NSArray *)paperSizesAndNamesForPrinter: (NSString *)printerName;
+ (NSArray *)extractInfoFromPrinter: (PMPrinter)printerInfo;

@end


Finally, you’d then wrap the above two functions in



@implementation NSPrinter (MyNSPrinterExtensions)

...
..
.

@end


Sorry if you’ve got a small screen and this article scrolls horizontally. I’ve decided that, unlike other languages that I can easily keep to 80 columns (or even 65 for writing articles), Objective-C simply requires huge amounts of horizontal real estate.

Also, like most of my code, this uses the new Objective-C structured exception handling, which requires Mac OS X 10.3.9 or greater. If you’re not using it, you should be. I was slow to get into SEH when I first saw them many years back, but now I feel any language is incomplete without them.

[Read Rest of Article]
Copyright © 2005-2008 Marc Wandschneider All Rights Reserved.