I'm trying to upload an image to Picasa from a Google Chrome Extension and running into some trouble constructing the POST.
This is the protocol google specifies for uploading an image to Picasa (link):
Content-Type: multipart/related; boundary="END_OF_PART"
Content-Length: 423478347
MIME-version: 1.0
Media multipart posting
--END_OF_PART
Content-Type: application/atom+xml
<entry xmlns='http://www.w3.org/2005/Atom'>
<title>plz-to-love-realcat.jpg</title>
<summary>Real cat wants attention too.</summary>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/photos/2007#photo"/>
</entry>
--END_OF_PART
Content-Type: image/jpeg
...binary image data...
--END_OF_PART--
And this is what I've cobbled together to attempt to do that, borrowing code from here and the extension "clip-it-good":
function handleMenuClick(albumName, albumId, data, tab) {
chrome.pageAction.setTitle({
tabId: tab.id,
title: 'Uploading (' + data.srcUrl.substr(0, 100) + ')'
});
chrome.pageAction.show(tab.id);
var img = document.createElement('img');
img.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0);
var dataUrl = canvas.toDataURL();
var dataUrlAdjusted = dataUrl.replace('data:image/png;base64,', '');
var builder = new WebKitBlobBuilder();
builder.append(Base64.decode(dataUrlAdjusted).buffer);
function complete(resp, xhr) {
chrome.pageAction.hide(tab.id);
if (!(xhr.status >= 200 && xhr.status <= 299)) {
alert('Error: Response status = ' + xhr.status +
', response body = "' + xhr.responseText + '"');
}
} // end complete
OAUTH.authorize(function() {
OAUTH.sendSignedRequest(
'http://picasaweb.google.com/data/feed/api/' +
'user/default/albumid/' + albumId,
complete,
{
method: 'POST',
headers: {
'Content-Type': 'multipart/related; boundary=END_OF_PART',
'MIME-version': '1.0'
},
parameters: {
alt: 'json'
},
body: constructContentBody_('title.jpg', 'photo',
builder.getBlob('image/png'),
'image/jpeg', 'lolz')
}
);
});
} // end onload
img.src = data.srcUrl;
}
function constructAtomXml_(docTitle, docType, docSummary) {
var atom = ['<entry xmlns="http://www.w3.org/2005/Atom">',
'<title>', docTitle, '</title>',
'<summary>', docSummary, '</summary>',
'<category scheme="http://schemas.google.com/g/2005#kind"',
' term="http://schemas.google.com/docs/2007#', docType, '"/>',
'</entry>'].join('');
return atom;
};
function constructContentBody_(title, docType, body, contentType, summary) {
var body_ = ['--END_OF_PART\r\n',
'Content-Type: application/atom+xml;\r\n\r\n',
constructAtomXml_(title, docType, summary), '\r\n',
'--END_OF_PART\r\n',
'Content-Type: ', contentType, '\r\n\r\n',
eval(body), '\r\n',
'--END_OF_PART--\r\n'].join('');
return body_;
};
This returns "Error: Response status = 400, response body = "Invalid kind on entry.""
I'm not sure if I'm doing something wrong with WebKitBlobBuilder or if my POST is improperly formed. Any suggestions would be welcome!
1) Install the extension Save Images to Google™ Photos 2) Right Click the image you wish to save and choose the "Save Images to Google™ Photos" option Our software is 100% free and a great way to save your photos to Google™ Photos without having to download the photo and uploading it again from your computer to Google™ ...
My multipart approach looks pretty much the same, except that I load the file through FileReader.readAsBinaryString(file). However, Picasa returns a Bad Request with "Not an Image" (for JPG/PNG files) or "Not a valid image" for BMP files.
If you instead post the picture directly, it does work (201 Created). The following code works for me:
function upload_image(file, albumid) {
// Assuming oauth has been initialized in a background page
var oauth = chrome.extension.getBackgroundPage().oauth;
var method = 'POST';
var url = 'https://picasaweb.google.com/data/feed/api/user/default/albumid/' + albumid;
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.setRequestHeader("GData-Version", '3.0');
xhr.setRequestHeader("Content-Type", file.type);
xhr.setRequestHeader("Authorization", oauth.getAuthorizationHeader(url, method, ''));
xhr.onreadystatechange = function(data) {
if (xhr.readyState == 4) {
on_image_sent(data, xhr);
}
};
xhr.send(file);
Where file is a HTML5 file object from the FileIO API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With