Base64 encoding of NSImage

  • I am looking at available option to send an NSImage to a webserver. I came across gSoap however its licensing model makes it not suitable. Using REST / JSON seems like an easy option however NSDATA does not seem to be supported by the JSON Serialiser. The one remaining option I considered was to encode the image myself to base64 before including in the JSON request. This could work quite nicely, however there doesn't seem to be a standard method for base64 encoding.

    Any suggestion on how to best achieve this.

    Kind regards
    Alex
  • I think the answers given here will help you out:

    http://stackoverflow.com/questions/392464/any-base64-library-on-iphone-sdk

    [[[Brainchild alloc] initWithName:@"Richard Altenburg"] saysBestRegards];

    Op 1 jul. 2012, om 17:23 heeft Alexander Hartner het volgende geschreven:

    > I am looking at available option to send an NSImage to a webserver. I came across gSoap however its licensing model makes it not suitable. Using REST / JSON seems like an easy option however NSDATA does not seem to be supported by the JSON Serialiser. The one remaining option I considered was to encode the image myself to base64 before including in the JSON request. This could work quite nicely, however there doesn't seem to be a standard method for base64 encoding.
    >
    > Any suggestion on how to best achieve this.
    >
    > Kind regards
    > Alex
  • I think that only cocoa collections can be supported by the JSON serializer.

    Even CLLocations aren't supported since they consist of structs.

    On Jul 1, 2012, at 11:23 AM, Alexander Hartner wrote:

    > I am looking at available option to send an NSImage to a webserver. I came across gSoap however its licensing model makes it not suitable. Using REST / JSON seems like an easy option however NSDATA does not seem to be supported by the JSON Serialiser. The one remaining option I considered was to encode the image myself to base64 before including in the JSON request. This could work quite nicely, however there doesn't seem to be a standard method for base64 encoding.
    >
    > Any suggestion on how to best achieve this.
    >
    > Kind regards
    > Alex
  • Try here.  it is a category for nsdata in this post.
    http://www.thohensee.com/?page_idC5

    Tom

    Sent from my iPhone

    On Jul 1, 2012, at 10:26 AM, Alexander Hartner <alex...> wrote:

    I am looking at available option to send an NSImage to a webserver. I came
    across gSoap however its licensing model makes it not suitable. Using REST
    / JSON seems like an easy option however NSDATA does not seem to be
    supported by the JSON Serialiser. The one remaining option I considered was
    to encode the image myself to base64 before including in the JSON request.
    This could work quite nicely, however there doesn't seem to be a standard
    method for base64 encoding.

    Any suggestion on how to best achieve this.

    Kind regards
    Alex
  • If you want to be sure which one works for you, it is probably best to read how Base64 encoding actually works, maybe you find out you can just as easily roll your own solution. Especially on a fast Mac desktop, it would not have to be the worlds' most efficient solution, it will be fast anyways, and always faster than the web server you are uploading to.

    This might help:

    http://email.about.com/cs/standards/a/base64_encoding.htm

    [[[Brainchild alloc] initWithName:@"Richard Altenburg"] saysBestRegards];

    Op 1 jul. 2012, om 17:46 heeft Alexander Hartner het volgende geschreven:

    > There seem to be a number of options listed on the suggested solution. Hard to see which one is best.
  • On Sun, Jul 1, 2012, at 11:23 PM, Alexander Hartner wrote:
    > I am looking at available option to send an NSImage to a webserver. I
    > came across gSoap however its licensing model makes it not suitable.
    > Using REST / JSON seems like an easy option however NSDATA does not seem
    > to be supported by the JSON Serialiser. The one remaining option I
    > considered was to encode the image myself to base64 before including in
    > the JSON request. This could work quite nicely, however there doesn't
    > seem to be a standard method for base64 encoding.
    >
    > Any suggestion on how to best achieve this.

    If you're in control over both the client and server, I'd suggest
    avoiding sending the image data over JSON. You're going to seriously
    inflate the file size by base64-encoding it, and for what purpose?

    You can be REST without using JSON. It would be much more efficient if
    you could just issue a PUT at a certain URL to upload the image data.

    --Kyle Sluder
  • On Sun, Jul 1, 2012 at 1:05 PM, Kyle Sluder <kyle...> wrote:

    > On Sun, Jul 1, 2012, at 11:23 PM, Alexander Hartner wrote:
    >> I am looking at available option to send an NSImage to a webserver.

    > If you're in control over both the client and server, I'd suggest
    > avoiding sending the image data over JSON. You're going to seriously
    > inflate the file size by base64-encoding it, and for what purpose?
    >
    > You can be REST without using JSON. It would be much more efficient if
    > you could just issue a PUT at a certain URL to upload the image data.

    I completely agree - don't encode it unless you're sure you really
    need that, such as if your webserver were a VAX and didn't understand
    8 bit character encodings.  You're going to balloon the resident
    memory size of the app, possibly dramatically if you're talking
    arbitrary images.

    --Jim
  • On Jul 1, 2012, at 8:23 AM, Alexander Hartner wrote:

    > I am looking at available option to send an NSImage to a web server.

    The simplest way would jut be to PUT the raw JPEG/PNG/whatever data to a URL on the server. No need to encode it.

    > I came across gSoap however its licensing model makes it not suitable.

    Plus, using SOAP for this would be like using an elaborate rickety Rube Goldberg device to swat a fly ;-)

    > Using REST / JSON seems like an easy option however NSDATA does not seem to be supported by the JSON Serialiser.

    Yes, JSON doesn't support binary data, and the serializer doesn't do any magic type transformations for you.

    It's not a good idea to transmit base64-encoded data anyway, if you can possibly avoid it, as it'll make it ⅓ larger.

    —Jens
  • On Jul 1, 2012, at 9:33 AM, Richard Altenburg (Brainchild) wrote:

    > If you want to be sure which one works for you, it is probably best to read how Base64 encoding actually works, maybe you find out you can just as easily roll your own solution. Especially on a fast Mac desktop, it would not have to be the worlds' most efficient solution, it will be fast anyways, and always faster than the web server you are uploading to.

    Bad idea. You've now added some brand new bit-twiddling code to your app, and now you have to test it. Does it handle all lengths of data (there are 3 different cases, IIRC)? Does it work in big-endian and little-endian? Does it work in 64-bit? Does it work if the data is empty or less than 3 bytes long? If you've written a decoder, does it handle embedded line-breaks? Does it fail gracefully if the input is incorrect? Does it parse all lengths of input?

    You get the idea. It's always better to use an already-tested library than to roll your own, if it's feasible. This is especially true of code that might be parsing untrusted input data (such as a base64 decoder) since bugs in that code can often be exploited as attacks.

    [I'm aware that the OP doesn't need a decoder for this purpose; but I'm talking about the more general issues.]

    —Jens
  • Op 1 jul. 2012, om 19:38 heeft Jens Alfke het volgende geschreven:

    > It's always better to use an already-tested library than to roll your own, if it's feasible.

    Often you are not sure about the status of code you find online. Has it really been tested? Does it still work on my system, with my SDK? And worse of all, if something does break, how can I fix it if I don't understand what that code is actually doing? That is my greatest fear: not being able to support my own software because I made it rely on 3rd party code that I do not understand.

    But I get the idea, including more newly written code does of course mean more testing and more possible bugs. So if you find a trusted source for your wanted code, I guess it would be okay to use it, I would also do it. But just look at that stackoverflow.com link I gave earlier, and the discussions about the solutions given. It is not that easy to find quality code that you can build release quality products on, I think...

    I hope I am wrong, I need a few decoders and encoders and socket libraries myself currently ;-)

    [[[Brainchild alloc] initWithName:@"Richard Altenburg"] saysBestRegards];
  • This is what I use. Short and sweet.

    @implementation NSData (Base64)

    - (NSData *)dataWithBase64Encoding
    {
    CFDataRef retval = NULL;
    SecTransformRef encodeTrans = SecEncodeTransformCreate(kSecBase64Encoding, NULL);
    if (encodeTrans != NULL) {
      if (SecTransformSetAttribute(encodeTrans, kSecTransformInputAttributeName, (__bridge CFDataRef)self, NULL))
      retval = SecTransformExecute(encodeTrans, NULL);
      CFRelease(encodeTrans);
    }
    return CFBridgingRelease(retval);
    }

    - (NSData *)dataFromBase64Decoding
    {
    CFDataRef retval = NULL;
    SecTransformRef decodeTrans = SecDecodeTransformCreate(kSecBase64Encoding, NULL);
    if (decodeTrans != NULL) {
      if (SecTransformSetAttribute(decodeTrans, kSecTransformInputAttributeName, (__bridge CFDataRef)self, NULL))
      retval = SecTransformExecute(decodeTrans, NULL);
      CFRelease(decodeTrans);
    }
    return CFBridgingRelease(retval);
    }

    @end
  • On Jul 1, 2012, at 12:16 PM, David Riggle wrote:

    > This is what I use. Short and sweet.

    10.7-only, though. (And not available on iOS.)

    —Jens
  • On 01.07.2012, at 17:23, Alexander Hartner wrote:

    > I am looking at available option to send an NSImage to a webserver. I came across gSoap however its licensing model makes it not suitable. Using REST / JSON seems like an easy option however NSDATA does not seem to be supported by the JSON Serialiser. The one remaining option I considered was to encode the image myself to base64 before including in the JSON request. This could work quite nicely, however there doesn't seem to be a standard method for base64 encoding.

    Well, embedding an image encoded in base64 in a JSON document is not that "RESTful" anyway. You better provide a link (URI) in the JSON to the image resource and load the image data separately (still being RESTful) but using a different transport format which is capable to transmit binary data more efficiently.

    Anyway, if you want to embed the image data into JSON:

    The various JSON libraries define a "mapping" of Foundation types to JSON types. For instance, a NSDictionary maps to a JSON Object, a NSNumber maps to a JSON Number or JSON Boolean (depending on the underlaying type in NSNumber), and so force.

    Usually, a NSImage will not be mapped directly to a JSON type, and especially with NSJSONSerialization you cannot accomplish this. If you try to serialize a hierarchy of Foundation objects which contains an object for which there is no mapping defined, the serialization fails for obvious reasons.

    There are  third party JSON libraries which are capable to customize the mapping, though. For instance, it might suffice to implement a method for a Category for NSImage to accomplish this (JPJson library uses this approach for example). That way, you can serialize a hierarchy of Foundation objects which contains a NSImage - no matter where this occurs in the tree. But note, a NSImage can only be mapped to one of the existing JSON primitive types, which is a JSON String. This in turn requires the mapping method to encode binary data to Unicode, for example base64.
  • On Jul 2, 2012, at 5:08 AM, Andreas Grosam wrote:

    > Well, embedding an image encoded in base64 in a JSON document is not that "RESTful" anyway.

    Sure it is. Plenty of REST-based APIs do this sort of thing (CouchDB and Atom both come to mind.) The REST principles don't dictate any particular transfer format for data, and allow for aggregate URLs that represent multiple resources.

    > There are  third party JSON libraries which are capable to customize the mapping, though. For instance, it might suffice to implement a method for a Category for NSImage to accomplish this (JPJson library uses this approach for example). That way, you can serialize a hierarchy of Foundation objects which contains a NSImage - no matter where this occurs in the tree.

    It's certainly possible to do that, but it doesn't seem like a good idea to me, because there's no unambiguous data format associated with an image. Even choosing between the two most obvious formats (JPEG and PNG) involves a decision about trade-offs between fidelity loss and file size.

    I would instead have the app itself decide how to encode the image as data, and then set up an unambiguous mapping from NSData to base64-encoded JSON strings. (Of course on the other end it's trickier because how does the decoder know what strings should be decoded to NSData and which should be left alone? YAML has type annotations that provide for this, but JSON doesn't.)

    —Jens
  • On Jul 2, 2012, at 8:53 AM, Jens Alfke <jens...> wrote:

    >
    > (Of course on the other end it's trickier because how does the decoder know what strings should be decoded to NSData and which should be left alone? YAML has type annotations that provide for this, but JSON doesn't.)

    All the more reason to just use a plain HTTP PUT with the right Content-type header. Or even a custom header that can carry a UTI (or an entire UTI tag spec).

    --Kyle Sluder
  • On 02.07.2012, at 17:53, Jens Alfke wrote:

    >
    > On Jul 2, 2012, at 5:08 AM, Andreas Grosam wrote:
    >
    >> Well, embedding an image encoded in base64 in a JSON document is not that "RESTful" anyway.
    >
    > Sure it is. Plenty of REST-based APIs do this sort of thing (CouchDB and Atom both come to mind.) The REST principles don't dictate any particular transfer format for data, and allow for aggregate URLs that represent multiple resources.

    Well, I should have been more accurate what I actually meant by this:

    For instance, when we retrieve a list of things (not just images)  or some container object which contains an image - we should NOT return  those objects inlined which itself can be identified by its own URI - but instead providing the URI. Simply because this better implements the idea behind REST. There is actually a statement from Roy Fielding himself, who suggest (or better dictates) this course of action. Please read <>, and countless discussions about the pros and cons, and as well HATEOAS <<A href="http://en.wikipedia.org/wiki/HATEOAS">http://en.wikipedia.org/wiki/HATEOAS>

    In practice however, this is not always optimal for all applications. In case of images though, we can easily see that returning an URI as the result of the very first request is likely the better idea, than returning the whole staff at once. The application can chose later to retrieve any more detail information - using the URIs provided in the first request.

    But eventually, we may need to retrieve the image data through its URI - and this may be accomplished without using JSON, and still being completely RESTful.

    >
    >> There are  third party JSON libraries which are capable to customize the mapping, though. For instance, it might suffice to implement a method for a Category for NSImage to accomplish this (JPJson library uses this approach for example). That way, you can serialize a hierarchy of Foundation objects which contains a NSImage - no matter where this occurs in the tree.
    >
    > It's certainly possible to do that, but it doesn't seem like a good idea to me, because there's no unambiguous data format associated with an image. Even choosing between the two most obvious formats (JPEG and PNG) involves a decision about trade-offs between fidelity loss and file size.
    Thus, you *customize* the mapping - that is, you handle this case application specific. Of course, this shall be in accordance to the "protocol" - the API.

    > I would instead have the app itself decide how to encode the image as data, and then set up an unambiguous mapping from NSData to base64-encoded JSON strings. (Of course on the other end it's trickier because how does the decoder know what strings should be decoded to NSData and which should be left alone? YAML has type annotations that provide for this, but JSON doesn't.)
    Alternatively, you could do this:

    Instead of defining how an NSImage would serialize itself into JSON, you may define how the "owner" of that said image object would serialize itself into a JSON. Since it is assumed that this kind of object has enough context information, it can select the right actions:

    @interface Person  {
    @propery (NSString*) name;
    @propery (NSString*) email;
    @property (NSImage*) image;
    }

    A custom object would usually serialize itself as a JSON Object (aka NSDictionary). How this can be actually accomplished in code, certainly depends on the JSON library - and whether this is possible at all with this library. Furthermore, the object shall of course serialize itself according the API specified for this kind of Web-service.

    Basically, in JPJson library you would need to implement a method for this class Person (either Category or sub-class):
    - (NSInteger) JPJson_serializeTo:(id<JPJsonStreambufferProtocol>) buffer
                            encoding:(JPUnicodeEncoding)encoding
                            options:(JPJsonWriterOptions)options
                              level:(NSUInteger)level;

    Within that method, you would serialize the image - if required, or provide a URI.

    The API may specify all these details.

    Andreas

    >
    > —Jens
previous month july 2012 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today