Archive

Posts Tagged ‘pictures’

A Groovy Flickr API

March 30th, 2009

A long time ago I wanted to write a desktop GUI interface for Flickr. At the time I had just learned Java and thought it would be really cool to write it using swing. Little did I know how not cool working with swing would be :(

About halfway through the project I heard about a cool new dynamic way to write Java code called Groovy. From that day on Groovy has been making my life a whole lot easier. I didn’t need all the functionality in the flickrj library, so I decide to write a few methods for my app using Groovy. The hardest part of the whole thing was figuring out how to post images to Flickr, for that, I used the flickrj code as a reference. If source code was not available, I don’t think I would have ever figured it out. So a big thanks to all the folks working on that project!

This is not a complete API for Flickr, but should provide enough to get started. Also, here is a link to a text file with the below code for an easier way to view the source.

import java.io.IOException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.ArrayList
import java.util.Date
import java.util.Hashtable
import javax.imageio.ImageIO
import org.w3c.dom.Element
import org.w3c.dom.NodeList
import java.io.File;
import java.net.*;
import java.io.IOException;
import org.xml.sax.SAXException;
public class FlickrAPI {
String nsid = ""

private String secret = "your secret"

/**
* api key
*/
private String akey = "your key goes here"

private String sig = ""

private String url = ""

String authToken = ""

private String frob = ""

private String restString = "http://flickr.com/services/rest/?method="

public FlickrAPI() {
println("Created FlickerAPI")
}

public void authNewUser() {
constructFrobUrl()
createAuthURL()
getToken()
}
private String constructUrl(String flickrMethod,Map m,boolean authCall =false){
String s= this.restString+flickrMethod+"&api_key="+this.akey
m.each{key,value->
s+=key+value
}
if(authCall){s+="&auth_token=${this.authToken}&api_sig=${this.sig}"}
return s
}
def mapFlickrUser(){

}
//if bool is true then this is a Authenticated call
public void setSig(String method,boolean bool = false){
String sigString="${this.secret}api_key${this.akey}"
try {
if(bool){
sigString +="auth_token${this.authToken}${method}"
println "Sig is true"
}else{sigString+=method}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace()
}
println "sig is " +sigString
this.sig = calcMD5(sigString)
}

def jupload(String filePath,Map parameters=[:]){
println("parameters ${parameters.inspect()}")
def paramMessages=[]
int paramLength=0

if(parameters==[:]){
this.sig = calcMD5("${this.secret}api_key${this.akey}auth_token${this.authToken}")
}else{
//sort them and add them to the signature
String p=""
parameters.keySet().toList().sort().each{key->
//if the key ='tags' make it into space separated string
p+= "${key}${parameters[key]}"
paramMessages.add(addParameter([key,parameters[key]]) )
}
this.sig = calcMD5("${this.secret}api_key${this.akey}auth_token${this.authToken}${p}")
paramMessages.each{stringMsg->paramLength+=stringMsg.length()}
}

File file=new File(filePath)
String CrLf = "\r\n";
def url = new URL("http://api.flickr.com/services/upload/")
//def connection = url.openConnection()
HttpURLConnection conn = url.openConnection()
def is = new FileInputStream(file)
def flength= file.length()
byte[] imgData= new byte[(int)flength]

int offset = 0;
int numRead = 0;
while (offset < imgData.length && (numRead=is.read(imgData, offset, imgData.length-offset)) >= 0) {
offset += numRead;
}

// Ensure all the bytes have been read in
if (offset < imgData.length) {
throw new IOException("The file was not completely read: "+file.getName());
}
println "filesize ->${imgData.length}"
// Close the input stream, all file contents are in the bytes variable
is.close();
String message01=addParameter(['api_key',this.akey])
String message02 = addParameter(['auth_token',this.authToken])
String message03 = addParameter(['api_sig',this.sig])

String message1 = "";
message1 += "---------------------------6d72u458s1587" + CrLf;
message1 += "Content-Disposition: form-data; name=\"photo\"; filename=\""+filePath+"\"" + CrLf;
message1 += "Content-Type: image/jpeg" + CrLf;
message1 += CrLf;

// the image is sent between the messages in the multipart message.

String message2 = "";
message2 += CrLf + "---------------------------6d72u458s1587--" + CrLf;

def totalLength = String.valueOf((message01.length() + message02.length() + message03.length() + message1.length() + message2.length() + imgData.length+ paramLength))
conn.setRequestMethod("POST")
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=-------------------------6d72u458s1587");
conn.setRequestProperty("Host", "api.flickr.com");
conn.setRequestProperty("Content-Length",totalLength );
conn.setDoOutput(true)

System.out.println("open os");
def os = conn.getOutputStream();

System.out.println(message01);
os.write(message01.getBytes());

System.out.println(message02);
os.write(message02.getBytes());
//write the params here before the image
paramMessages.each{msg->os.write(msg.getBytes())}

System.out.println(message03);
os.write(message03.getBytes());

System.out.println(message1);
os.write(message1.getBytes());
os.write(imgData,0 ,imgData.length)

os.write(message2.getBytes());

println "end writing"
os.flush()
os.close()

conn.connect()
conn.disconnect()
println conn.content.text

}
//[name value]
private String addParameter(List para){
String CrLf = "\r\n";
String message01 = "";
message01 += "---------------------------6d72u458s1587" + CrLf;
message01 += "Content-Disposition: form-data; name=\"${para[0]}\"" + CrLf;
message01 += CrLf;
message01 += para[1] + CrLf;
return message01
}

public void constructFrobUrl() {
setSig("methodflickr.auth.getFrob")
this.url = "http://flickr.com/services/rest/?method=flickr.auth.getFrob&api_key=${this.akey}&api_sig=${this.sig}"
println("here is url-> ${this.url}")
def node = new XmlParser().parse(this.url)//dom.parseXML("frob")
this.frob = node['frob'].text().toString()
println("frob =>${this.frob}\n\n")
}

/**
* This function will calculate an MD5 sum of String Signature and return
* the String value of the Hash via strBuildup
*
* @param signature
* @throws NoSuchAlgorithmException
* @returns strBuildup
*/
private String calcMD5(String signature) throws NoSuchAlgorithmException {
// get Instance from Java Security Classes
String strBuildup = ""
MessageDigest md5 = MessageDigest.getInstance("MD5")
byte[] md5summe = md5.digest(signature.getBytes())
for (int k = 0; k < md5summe.length; k++) {
byte b = md5summe[k]
String temp = Integer.toHexString(b & 0xFF)
/*
* toHexString has the side effect of making stuff like 0x0F only
* one char F(when it should be '0F') so I check the length of
* string
*/
if (temp.length() < 2) {
temp = "0" + temp
}
temp = temp.toUpperCase()
strBuildup += temp
}
return strBuildup
}

/**
* get the authentication token
*
* @return
*/
public checkToken(){
setSig("methodflickr.auth.checkToken",true)
this.url=constructUrl('flickr.auth.checkToken',[:],true)
println(this.url)
def node = new XmlParser().parse(this.url)
println("done parsing check Token INFO ===>${node.children()}")
}
public void getToken() {
println("Entering getToken\n\n")
setSig("frob${this.frob}methodflickr.auth.getToken")
this.url = "${this.restString}flickr.auth.getToken&api_key=${this.akey}&frob=${this.frob}&api_sig=${this.sig}"
//println(this.url)
def node = new XmlParser().parse(this.url)
//need to get the nsid and the authtoken
this.authToken = node['auth']['token'].text()
this.nsid = node['auth']['user'].'@nsid'.text()
println "token is ${this.authToken}"
println("Token =>${node['auth']['token'].text()}")
println("nsid =>${node['auth']['user'].'@nsid'.text()}")
println("perms =>${node['auth']['perms'].text()}")

// set user nsid
println("Exiting GET Token")
}

public void createAuthURL() {
setSig("frob${this.frob}permsdelete")
String cmd = "open http://flickr.com/services/auth/?api_key="+ this.akey + "&perms=delete" + "&frob=" + this.frob + "&api_sig=" + this.sig
try {
Process proc = cmd.execute()
proc.waitForOrKill(10000)
sleep(2000)
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace()
}
}

/***************************************************************************
* AUTH
**************************************************************************/
/***************************************************************************
* ACTIVITIES
**************************************************************************/
//POLL ONLY ONCE AN HOUR!!!!!
public activityGetUserComments(){
setSig("methodflickr.activity.userComments",true)
this.url=constructUrl('flickr.activity.userComments',[:],true)
println(this.url)
def node = new XmlParser().parse(this.url)
println("done parsing GET user Comments INFO ===>${node.children()}")
}
/***************************************************************************
* BLOGS
**************************************************************************/
/***************************************************************************
* CONTACTS
**************************************************************************/
public void contactsGetList(){
setSig("methodflickr.contacts.getList",true)
this.url=constructUrl('flickr.contacts.getList',[:],true)
println(this.url)
def node = new XmlParser().parse(this.url)
println("done parsing GET contact List INFO ===>${node.children()}")
}
/***************************************************************************
* FAVORITES
**************************************************************************/
/***************************************************************************
* GROUPS
**************************************************************************/
/***************************************************************************
* GROUP POOLS
**************************************************************************/

/***************************************************************************
* INTERESTINGNESS
**************************************************************************/

/***************************************************************************
* PHOTOS
*what if a return back an array of pictures?
**************************************************************************/
def photosGetNotInSet(){
List piclist=[]
setSig("methodflickr.photos.getNotInSet",true)
this.url=constructUrl('flickr.photos.getNotInSet',[:],true)
println(this.url)
def node = new XmlParser().parse(this.url)
println("done parsing GET Not in Set INFO ===>${node.children()}\n\n\n")
/* test=f.photosGetNotInSet()
println test.photos.each{it-> it.each{p-> println p}} //list of nodes

test.photos.photo[3].attributes()
test.photos.photo.each{it-> println it.attribute('isfamily')} //gets the individual attr
test.photos.photo.each{it-> picList.push(new Picture(it))} //push a node into picture contructor

*/

return node
}

def photosGetContactsPhotos(){
setSig("methodflickr.photos.getContactsPhotos",true)
this.url=constructUrl('flickr.photos.getContactsPhotos',[:],true)
def node = new XmlParser().parse(this.url)
return node
}

def photosGetRecentlyUploaded() {
setSig("methodflickr.photos.getRecent",true)
//this.url = "flickr.photos.getRecent&api_key",[:],true)
this.url= constructUrl('flickr.photos.getRecent',[:],true)
def node = new XmlParser().parse(this.url)
println("done parsing RecentPhotos ===>${node.children()}")
return node
}
public void photosGetInfo(){

}
/***************************************************************************
* PEOPLE
**************************************************************************/
def contactsGetList(){
setSig("methodflickr.contacts.getList",true)
this.url=constructUrl('flickr.contacts.getList',[:],true)
def node = new XmlParser().parse(this.url)
//println("done parsing GET contact List INFO ===>${node.children()}")
return node
}
def peopleGetUploadStatus(){
setSig("methodflickr.people.getUploadStatus",true)
this.url=constructUrl('flickr.people.getUploadStatus',[:],true)
def node = new XmlParser().parse(this.url)
println("done parsing GET upload Status INFO ===>${node.children()}")
return node
}
def peopleGetPublicPhotos() {
setSig("methodflickr.people.getPublicPhotosuser_id${this.nsid}",true)
this.url=constructUrl('flickr.people.getPublicPhotos',['&user_id=':"${this.nsid}"],true)
def node = new XmlParser().parse(this.url)
//def peepsInfo = node['auth']['peeps'].text()
println("done parsing GET Public Photos ===>${node.children()}")
return node
}
def peopleGetPeopleInfo() {
setSig("methodflickr.people.getInfouser_id${this.nsid}",true)
this.url=constructUrl('flickr.people.getInfo',['&user_id=':"${this.nsid}"],true)
def node = new XmlParser().parse(this.url)
//def peepsInfo = node['auth']['peeps'].text()
return node
}

/********************************************
* photosets
************************/
def photosetsGetList(String uid){
setSig("methodflickr.photosets.getListuser_id${uid}",true)
this.url=constructUrl('flickr.photosets.getList',['&user_id=':"${uid}"],true)
def node = new XmlParser().parse(this.url)
//def peepsInfo = node['auth']['peeps'].text()
return node

}
def photosetsGetPhotos(String setID){
setSig("methodflickr.photosets.getPhotosphotoset_id${setID}",true)
this.url=constructUrl('flickr.photosets.getPhotos',['&photoset_id=':"${setID}"],true)
println this.url
def node = new XmlParser().parse(this.url)
//def peepsInfo = node['auth']['peeps'].text()
return node

}
/**
Upload photos

http://api.flickr.com/services/upload/

*/
//get the picture when supplied the proper args
//http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[mstb].jpg

public String getPicture(String farmId, String serverId, String photoid, String secret,String size ="s"){
return "http://farm${farmId}.static.flickr.com/${serverId}/${photoid}_${secret}_${size}.jpg"

}

Groovy, code, java , , , , , , , ,

Adding and Resizing Images with Grails

January 24th, 2009

Here is a quick post on how to upload images within your Grails project to your file system(rather than your database). It seems simple enough, but I ran into a few snags as I was working on one of my projects. Just wanted to provided a working example for those that are entering the Grails territory for the first time. Happy Coding!

I am using the imageTools plugin which you can read more about here

NOTE: The imageTools plugin has been criticized for its low quality of output. ImageMagick may be a better fit for you project(s). My particular project didn’t call for high quality pictures. A quick google search for “imagemagick for grails” should get you started on your way.

I am using version 1.0.3 in the example below

to install, I ran the following command from my grails application’s root directory

grails install-plugin http://www.arquetipos.co.cr/blog/files/grails-image-tools-1.0.3.zip

Domain-Class

class Picture {
byte[] imagefile
//Any other stuff you want to track

}

Controller Code for Saving an image

def save = {

def downloadedfile = request.getFile('imagefile')
def pictureInstance = new Picture(params)
def imageTool = new ImageTool()

if(downloadedfile && pictureInstance.save()){
String imagepath = grailsAttributes.getApplicationContext().getResource("images/").getFile().toString() + File.separatorChar + "${pictureInstance.id}.jpg"
downloadedfile.transferTo(new File(imagepath))

imageTool.load(imagepath)
imageTool.thumbnail(140)

imageTool.writeResult(imagepath, "JPEG")
imageTool.square()
flash.message = "Picture ${pictureInstance.id} created"
redirect(action:show,id:pictureInstance.id)
}
else {
render(view:'create',model:[pictureInstance:pictureInstance])
}
}

Code for displaying the image in both the ’show’ and ‘list’ views

<td><img src="${createLinkTo(dir:'images', file: pictureInstance.id+'.jpg' )}" /> </td>

Grails, Groovy, code , , , , , ,