Post Images To Tumblr Using PhoneGap And jsOAuth

Took over a month but I’m finally posting images to tumblr from my PhoneGap app. What a nightmare! PhoneGap only outputs Base64 encoded images and the Tumblr API only accepts “URL-encoded binary contents" (whatever that means). After a month of trial and error and picking apart a ton of other people’s code I finally got it working. I’ve never worked with raw image data before so there was a ton to learn. Quite honestly, I still don’t understand all the conversions going on. One thing’s for sure, I’ve been manually diffing binary data for too long. You get use to it I guess. I don’t even see the code. All I see is blonde, brunette, redhead.

So PhoneGap hands me Base64 encoded image data that looks like this:

/9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgES
AAMAAAABAAEAAIdpAAQAAAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAK
ACAAQAAAABAAAB9KADAAQAAAABAAAB9AAAAAD/2wBDAAYEBQYFBAY
GBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyY
nKSopGR8tMC0oMCUoKSj/2wBDAQcHBw...

So I Base64 decode it to look like this:

255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255,225,0,88,69,
120,105,102,0,0,77,77,0,42,0,0,0,8,0,2,1,18,0,3,0,0,0,1,0,1,0,0,135,105,
0,4,0,0,0,1,0,0,0,38,0,0,0,0,0,3,160,1,0,3,0,0,0,1,0,1,0,0,160,2,0,4,0,0,
0,1,0,0,1,244,160,3,0,4,0,0,0,1,0,0,...

Sweet I’m done! Right? Wrong! I started getting 401 Auth errors from Tumblr but I knew my auth was good because I had already successfully posted text posts. That is when I discovered this thread. It took 90+ posts and over 3 months of back and forth for these guys to get it working. I must have read this post 1000x before giving up.

The most important piece I got from that thread was this post sayingI needed to convert my decoded image into hex data. A few queries later I found this tool with some clean base 64 decoding and hex conversion scripts in the source. Sweet. Now my image data looked like this:

\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01\x01\x00\x00\x01
\x00\x01\x00\x00\xFF\xE1\x00\x58\x45\x78\x69\x66\x00\x00\x4D\x4D
\x00\x2A\x00\x00\x00\x08\x00\x02\x01\x12\x00\x03\x00\x00\x00\x01
\x00\x01\x00\x00\x87\x69\x00\x04\x00\x00\x00\x01\x00\x00\x...

Still no luck. At this point I had gotten “failed uploading photo" response (or something like that) from tumblr so I knew I was getting closer. Seemed like something was up with their API though (more on that soon). John from Tumblr posted a working python script so I gave that a shot. Seemed to work. Then I modified the script so I could paste my raw hex data into it. IT WORKED! I knew I was on the right track. I dumped the headers and body sent off by the python script and went on a mission to match it exactly (this is where I went a little binary data diffing crazy). The working post data looks like this:

data%5B0%5D=%FF%D8%FF%E0%00%10JFIF%00%01%01%00%00%01
%00%01%00%00%FF%E1%00XExif%00%00MM%00%2A%00%00%00%
08%00%02%01%12%00%03%00%00%00%01%00%01%00%00%87i%
00%04%00%00%00%01%00%00%00%26%00%00%00%00%00%03%A0
%01%00%03%00%00%00%01%00%01%00%00%A0%02%00%04%00%

I couldn’t help but notice that this wasn’t a standard url encoding. That JFIF and Exif made me really worried. I hadn’t produced anything that looked like that yet. So I went digging some more and found a guy who wrote a tumblr photo uploader in Objective C. My buddy Xuan helped me break it down line for line and rewrite it in javascript. A bunch of the conversions like removing < brackets and spaces, converting to ASCII, replacing %20 with + ended up being unnecessary.

%FF%D8%FF%E0%00%10JFIF%00%01%01%00%00%01%00%01%00
%00%FF%E1%00XExif%00%00MM%00%2A%00%00%00%08%00%02
%01%12%00%03%00%00%00%01%00%01%00%00%87i%00%04%00
%00%00%01%00%00%00%26%00%00%00%00%00%03%A0%01%00
%03%00%00%00%01%00%01%00%00%A0%02%00%04%00%00%00
%01%00%

Finally, there are a few oddities with the way Tumblr implemented OAuth. For whatever reason they wouldn’t accept urlencoded ~tilde~ characters in the signature base string. For this I had to hack jsOAuth which I had been trying to avoid. A quick find and replace did the trick:

signatureString = signatureString.replace(/\%257E/g,'~');

As part of creating the signature in OAuth the arguments generally get double url encoded. This is the case with Tumblr’s implementation as well except for the image data and data parameter. The data key/value pairs are encoded once.

In my implementation I only need to post a single image but the API should accept an array of images as the value for data. I couldn’t get this to work so I hardcoded data[0] as the key which seems to fix it but limits me to a single image.

Thats it. Thanks to everyone who helped me get this working, hopefully it helps you too!

Here's a list of other working scripts I found:
php, python, ruby, C#, Objective C

And here’s the final code used for converting the image. It takes a Base64 encoded images and returns “url-encoded binary contents" the way Tumblr likes it.


Get notified next time I post. Three ways to subscribe:
RSS Email Twitter

© 2009 BrainBackup.net | All Rights Reserved.