iOS: Printing PNG files to Google Cloud Print using GTM

384 views Asked by At

I have tried numerous combinations here but it continuously fails unless I add a content URL param and set the contentType param to text/plain. That's cool and all but useless. I need to print PNG files and that won't fit in the URL.

I'm using gtm-http-fetcher so auth is easily handled. Here is my print implementation:

@implementation EBCloudPrint
    +(void) printFile:(NSString *)file{
        [EBCloudPrint printImage:[NSData dataWithContentsOfFile:file]];
    }

    +(void) printImage:(NSData *)image{
        NSString *printer = [EBPreferences getUserPreference:PREFERENCE_GOOGLE_CLOUD_PRINTER];
        if (printer == nil) {
            NSLog(@"Ignoring print: no printer selected");
            return;
        }
        GTMOAuth2Authentication *auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:GOOGLE_KEYCHAIN_NAME
                                                                                              clientID:GOOGLE_CLIENT_ID
                                                                                          clientSecret:GOOGLE_CLIENT_SECRET];

        // Return immediately if we haven't auth
        if (![auth canAuthorize]) {
            return;
        }

        [GTMHTTPFetcher setLoggingEnabled:YES];

        GTMMIMEDocument *doc = [GTMMIMEDocument MIMEDocument];

        [doc addPartWithHeaders:@{@"Content-Disposition": @"form-data; name=\"ticket\""}
                           body:[@"{\"version\": \"1.0\", \"print\": {}}" dataUsingEncoding:NSUTF8StringEncoding]];

        [doc addPartWithHeaders:@{@"Content-Disposition": @"form-data; name=\"content\"; filename=\"eb.png\"", @"Content-Type": @"image/png"}
                           body:image];

        NSInputStream *stream = nil;
        [doc generateInputStream:&stream
                          length:NULL
                        boundary:NULL];

        if (stream) {
            NSString *url = [NSString stringWithFormat:@"%@?output=json&printerid=%@&contentType=image/png&title=eb&tag=eb_ios", CLOUD_PRINT_JOB_URL, printer];

            NSLog(@"Printing to: %@", url);

            GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithURLString:url];

            [fetcher setPostStream:stream];
            [fetcher setAuthorizer:auth];

            [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
                if (data) {
                    NSLog(@"data: %@", [NSString stringWithUTF8String:[data bytes]]);
                }
                if (error) {
                    NSLog(@"---- error: %@", error.localizedDescription);
                }
            }];

            stream = nil;
            fetcher = nil;
        }
    }

    +(NSArray *) getPrinters{
        return [[NSArray alloc] init];
    }
@end

Here is the response from the server:

{
  "success": false,
  "message": "Document missing.",
  "request": {
    "time": "0",
    "users": [
      "..."
    ],
    "params": {
      "": [
        "\\r/@R\\r`\\u0015\\u003c`_\\u001d\\u0018\\u0016Z\\u0002\\u00072d\\fEr\\rG \\u000bk7\\u001c\\u003d'k^4j?\\u001a\\u0014' yd#A\\u0016\\u0000*\\\"q\\u0004\\u0015H\\u00035\\u001fYLWN@1p"
      ],
      "title": [
        "eb"
      ],
      "\\r\\n--END_OF_PART\\r\\nContent-Disposition: form-data; name": [
        "\\\"ticket\\\"\\r\\n\\r\\n{\\\"version\\\": \\\"1.0\\\", \\\"print\\\": {}}\\r\\n--END_OF_PART\\r\\nContent-Disposition: form-data; name\\u003d\\\"content\\\"; filename\\u003d\\\"eb.png\\\"\\r\\nContent-Type: image/png\\r\\n\\r\\nPNG\\r\\n\\u001a\\n\\u0000\\u0000\\u0000\\rIHDR\\u0000\\u0000\\u0000\\u0019\\u0000\\u0000\\u0000\\u0019\\b\\u0006\\u0000\\u0000\\u0000c\\u0000\\u0000\\u0000\\u001ciDOT\\u0000\\u0000\\u0000\\u0002\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\r\\u0000\\u0000\\u0000(\\u0000\\u0000\\u0000\\r\\u0000\\u0000\\u0000\\f\\u0000\\u0000\\u0002\\u0010~\\u0000\\u0000\\u0002KIDATH\\rb`\\u0003V\\u001d;Y5uoBj9ek.'-zo\\u0014\\u0013\\u0006A y:\\u003cj5w3yg8~`\\u001a\\u0007A@q"
      ],
      "e": [
        "ggW\\r0n\\u0001`1B\\u003cH\\u001dH\\u003dH\\u001fH?}oX%..\\u000bt!0Xp\\u001a2z\\u003e~9"
      ],
      "tag": [
        "eb_ios"
      ],
      "printerid": [
        "45..."
      ],
      "contentType": [
        "image/png"
      ],
      "Cy\\u0007_S5]KoE\\u0018\\u0006\\u0019l\\n bQ\\u003cC@@A": [
        "wmI\\u001f\\u0016\\u0000#\\u001b\\u001c$js[.\\u0001[f\\u0010;\\u001f @C}rI\\bE\\u000f\\n\\u000f\\u0012\\u0017W\\u000bh\\tsvxL[y%a\\u003ez@\\t\\u0004d\\u001e\\\\Ep]Y9d\\u0016`uf\\u0003\\u003e)a`4(A\\u0003\\u000b2w\\u0018P\\u0000/L\\u00112\\r\\u0007k\\u001a,w_n\\u0003-\\u000fd\\u001eGc\\u0018J'Z"
      ],
      "output": [
        "json"
      ],
      ",;mJl\\u0016,\\u0005\\u00032\\u000fd.a`": [
        "wmI\\t@\\u001a-S\\u0016b5H?\\u001cy(\\u00168\\u0007_S5]K\\u000f\\\"S,0[\\u0012\\u0005  s@aX\\u0002\\u0012w50 l\\u0004\\u0001b\\u003e~9X-\\tn?tY%gYPP\\u0005!\\u000eW,\\u0003\\u0019\\u000e\\u0007\\u0003\\u0007\\u0003En5w3\\u003d`\\u0003P\\u000b@\\u00022\\u0018D q\\u003cH\\u001dH\\u003dAC)Xu\\u0018g\\t-[\\u0004\\f*\\tD q\\u003cH\\u001d601\\u0000tI\\u0016:^\\u0000\\u0000\\u0000\\u0000IENDB`\\r\\n--END_OF_PART--\\r\\n"
      ],
      "NK@'-~\\u0000_A^Cv\\u00012\\u001b\\u0014\\u003eEnYP\\u003ei70?4\\u0000s3Xq\\t2\\u0003d.|\\u0000\\u0000\\u0000\\u0000x\\u0001l$\\u0000\\u0000\\u0001IDATc0OZ8~X1P\\\\Y?3@A\\u0003\\u003c,q\\u0011V} @'-~[v\\\\\\nA^,is`tz@@\\u0016P:a2IiM\\u0013\\\\K@\\u0005hrFx\\f\\u0013O\\u0012}\\u00022\\u000fd.|s\\u001c2\\u000bo4#/^}\\u0012\\u0016\\\\v\\\\\\t%6\\f\\u0005\\u003c \\u0017\\u001e.\\u000e(#\\u0001dY}": [
        ""
      ]
    },
    "user": "...."
  },
  "errorCode": 412
}

Something is amiss. I cannot pinpoint it. If anyone has any insight here or examples of printing images with GTM [El Goog is slim pickin's for iOS], I'd highly appreciate it!

1

There are 1 answers

0
johncblandii On BEST ANSWER

I figured out the problem with help from the Google Cloud Print mailing list. Hopefully I can find time to package this into a Pod and make it easier to work with.

Disclaimer: There are some unfinished/not cleaned up pieces here but focus on the Mime Document, ticket, and NSInputStream.

@implementation EBCloudPrint

+(void) printFile:(NSString *)file completion:(void (^)(void))completion{
    [EBCloudPrint printImage:[NSData dataWithContentsOfFile:file] completion:completion];
}

+(void) printImage:(NSData *)image completion:(void (^)(void))completion{
    NSString *printer = [EBPreferences getUserPreference:PREFERENCE_GOOGLE_CLOUD_PRINTER];
    if (printer == nil) {
        NSLog(@"Ignoring print");
        if (completion) {
            completion();
        }
        return;
    }
    GTMOAuth2Authentication *auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:GOOGLE_KEYCHAIN_NAME
                                                                                          clientID:GOOGLE_CLIENT_ID
                                                                                      clientSecret:GOOGLE_CLIENT_SECRET];

    // Return immediately if we haven't auth
    if (![auth canAuthorize]) {
        if (completion) {
            completion();
        }
        return;
    }

    [GTMHTTPFetcher setLoggingEnabled:YES];

    GTMMIMEDocument *doc = [GTMMIMEDocument MIMEDocument];

    // MediaSize docs: https://developers.google.com/cloud-print/docs/cdd#MediaSize
    NSString *ticketJson = @"{\"version\": \"1.0\", \"print\": { \"media_size\": { \"width_microns\": 101600, \"height_microns\": 152400 }}}"; //media_size: 4x6

    [doc addPartWithHeaders:@{@"Content-Disposition": @"form-data; name=\"ticket\"", @"Content-Type": @"text/json"}
                       body:[ticketJson dataUsingEncoding:NSUTF8StringEncoding]];

    [doc addPartWithHeaders:@{@"Content-Disposition": @"form-data; name=\"content\"; filename=\"eb.png\"", @"Content-Type": @"image/png"}
                       body:image];

    NSString *boundary = nil;
    unsigned long long length = -1;

    NSInputStream *stream = nil;
    [doc generateInputStream:&stream
                      length:&length
                    boundary:&boundary];

    if (stream) {
        NSString *url = [NSString stringWithFormat:@"%@?output=json&printerid=%@&contentType=image/png&title=MyApp&tag=my_app", CLOUD_PRINT_JOB_URL, printer];

        NSLog(@"Printing to: %@", url);

        NSMutableURLRequest *jobSubmitRequest;
        NSTimeInterval timeout = 300.0;

        jobSubmitRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]
                                                        cachePolicy:NSURLRequestReloadIgnoringCacheData
                                                    timeoutInterval:timeout];

        NSString *httpHeaderContentTypeString = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
        [jobSubmitRequest addValue:@"my_app" forHTTPHeaderField:@"X-CloudPrint-Proxy"];
        [jobSubmitRequest addValue:httpHeaderContentTypeString forHTTPHeaderField:@"Content-Type"];
        [jobSubmitRequest setHTTPMethod:@"POST"];

        GTMHTTPFetcher* fetcher = [GTMHTTPFetcher fetcherWithRequest:jobSubmitRequest];
        [fetcher setPostStream:stream];
        [fetcher setAuthorizer:auth];

        [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
            if (data) {
                NSLog(@"data: %@", [NSString stringWithUTF8String:[data bytes]]);
            }
            if (error) {
                NSLog(@"---- error: %@", error.localizedDescription);
            } else if(completion){
                completion();
            }
        }];

        stream = nil;
        fetcher = nil;
    }
}

+(NSArray *) getPrinters{
    return [[NSArray alloc] init];
}

@end