Android Twitter getting profile image size issue - android

I'm trying to get the profile images of my followers for use within a ListView as thumbnails.
These thumbnails are around 125x125, but the standard twitter4j call of User.getProfileImageURL(); returns much smaller size of 48x48 and is also recommended to not be used as the image source.
I've tried creating a ProfileImage object and supplying it as a parameter, User.getProfileImageURL(profile image object.Original),
But this code takes some time to simply retrieve the url, which when loading a list of thumbnails, is inefficient.
Any suggestions on how to go about this?

Edit
Twitter API v1 has been disabled, so my old answer is no longer valid. Refer to API v1.1, which I believe requires authentication.
If you know the screen name, the twitter api allows for you to fetch the profile image at 4 different resolutions;
https://api.twitter.com/1/users/profile_image?screen_name=Krylez&size=mini
https://api.twitter.com/1/users/profile_image?screen_name=Krylez&size=normal
https://api.twitter.com/1/users/profile_image?screen_name=Krylez&size=bigger
https://api.twitter.com/1/users/profile_image?screen_name=Krylez&size=original
The "bigger" image is 73x73, which is going to interpolate in your 125x125 container. If you're not okay with this, you can try to fetch the "original" photo, but this photo could be very large (slow) and it's not necessarily a square.
Whatever method you choose, make sure you're not fetching and/or decoding Bitmaps on the UI thread. The Android API documentation has excellent guidelines for the correct way to do this.
Also we can make use of the Twitter4j using:
mTwitter.getUserProfileImage();

From the official doc:
You can obtain a user’s most recent profile image from GET users/show. Within the user object, you’ll find the profile_image_url
and profile_image_url_https fields. These fields will contain the
resized “normal” variant of the user’s uploaded image. This “normal”
variant is typically 48x48px.
By modifying the URL, you can retrieve other variant sizings such as
“bigger”, “mini”, and “original”.
Following the code:
TwitterApiClient twitterApiClient = TwitterCore.getInstance().getApiClient();
twitterApiClient.getAccountService().verifyCredentials(false, false, new Callback<User>() {
#Override
public void success(Result<User> userResult) {
String name = userResult.data.name;
String email = userResult.data.email;
// _normal (48x48px) | _bigger (73x73px) | _mini (24x24px)
String photoUrlNormalSize = userResult.data.profileImageUrl;
String photoUrlBiggerSize = userResult.data.profileImageUrl.replace("_normal", "_bigger");
String photoUrlMiniSize = userResult.data.profileImageUrl.replace("_normal", "_mini");
String photoUrlOriginalSize = userResult.data.profileImageUrl.replace("_normal", "");
}
#Override
public void failure(TwitterException exc) {
Log.d("TwitterKit", "Verify Credentials Failure", exc);
}
});
For further information refer to Twitter API Documentation | Profile Images and Banners
To create a custom size pic, for example 90x90 you can use the createScaledBitmap() method.
private final int PROFILE_PIC_SIZE = 90;
Bitmap originalPic = null;
Bitmap resizedPic = null;
try {
InputStream in = new java.net.URL(photoUrlOriginalSize).openStream();
originalPic = BitmapFactory.decodeStream(in);
resizedPic = Bitmap.createScaledBitmap(originalPic, PROFILE_PIC_SIZE, PROFILE_PIC_SIZE, false);
} catch (Exception exc) {
Log.e("Error", exc.getMessage());
exc.printStackTrace();
}

You can use getOriginalProfileImageURL() for example. This is as large as it gets.
Smaller ones are getBiggerProfileImageURL() and getProfileImageURL().
These are the urls you retrieve:
http://pbs.twimg.com/profile_images/NUMBER/c62p-cAD_normal.jpeg
http://pbs.twimg.com/profile_images/NUMBER/c62p-cAD_bigger.jpeg
http://pbs.twimg.com/profile_images/NUMBER/c62p-cAD.jpeg

Related

How do I upload file using Salesforce Mobile SDK for android?

I am using the Salesforce SDK (4.1.x) in a native Android app. I use the RestClient.sendAsync method to post my form data to a custom object. That part is working fine. Now I need to upload and attach a photo that was taken by the mobile user. I see that RestClient has an uploadFile method. Is this the correct method? If so then how do I connect the uploaded file to the custom form data?
Ok. I figured this out. First, create the parent object (the main form data) using the following.
request = RestRequest.getRequestForCreate(apiVersion, objectType, fields);
client.sendAsync(restRequest, new RestClient.AsyncRequestCallback() {...
In the onSuccess method you will get the id of the new object from the response. There are plenty of examples that show how to get the JSON object and the id. Armed with this parentId we can now create the attachment. The code looks something like this.
private void postImageAsAttachment(String parentId, String title) {
Map<String, Object> fields = new HashMap<String, Object>();
fields.put("Name", title);
fields.put("ParentId", parentId);
fields.put("Body", ImageHelper.getBase64FromImage(mCurrentPhotoPath));
RestRequest request = null;
try {
request = RestRequest.getRequestForCreate(apiVersion, "Attachment", fields);
} catch (Exception ex) {
Log.d(TAG, "sendRequest: ", ex);
Toast.makeText(MainActivity.this, "The file upload failed: " + ex.toString(), Toast.LENGTH_LONG).show();
}
client.sendAsync(request, new RestClient.AsyncRequestCallback() {...
I'm using a simple class called ImageHelper that simply loads the image file, performs image compression (if necessary), and base64 encodes the image data. The result is that an "Attachment" object is created as a child of the parent object.
I hope this helps the next person.

Generate pre-signed url of private Image and load to a image view - S3 Client android

I am trying to load image from my S3 Bucket in my android application. My images are private so I won't be having any specific link for each image.
I'm using link generator,
s3Client.generatePresignedUrl(Constants.S3_BUCKET_NAME, key, expiration);
It generates a URL with let's say 1 hour or 2 min expiration.
Now I have problem in loading the url. I tried loading it by using picasso ,
Picasso.with(context).load(url.toString()).resize(30,38).into(holder.photo);
but it's not quite seems to be working. When I tried that link on browser I got following error
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
Try to attach error listener to Picasso and see what's going on. Also read logcat. Print URL which you pass to Picasso, does it correct?
Picasso.Builder builder = new Picasso.Builder(getApplicationContext());
builder.listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso arg0, String err) {
Log.e("Picasso Error", "Errored " + err);
}
});
builder.loggingEnabled(true);
Picasso pic = builder.build();
pic.load("image.jpg").into(iv);

Universal-Image-Loader Custom FileNameGenerator based on local file name

I am using Universal Image Loader to display images downloaded from a URI or already available in a disk cache implementation.
I want to display music album covers, but more than one track might have the same URI for a cover (i.e. tracks from the same album). I want that even if the image is the same it's stored each time for each different track with the track name, because I want users to be able to replace the default covers with a custom one, even for each single track.
For instance
01 - Track 01.mp3
02 - Track 02.mp3
Belong to the same album and the cover URI is http://something/img.jpg, on disk cache I want to have
01 - Track 01.jpg
02 - Track 02.jpg
even if it's the same image.
So I've coded a FileNameGenerator that stores a Set of hashes for each Uri, where the hash is the SHA-1 of the absolute path of the file.
Here is my implementation:
public MyFileNameGenerator(String ext) {
super();
this.ext = ext;
}
HashMap<String,HashSet<String>> names = new HashMap<String, HashSet<String>>();
#Override
public String generate(String imageUri) {
if(imageUri==null) return null;
if (imageUri.startsWith("file:///")) {
return FilenameUtils.removeExtension(Uri.parse(imageUri)
.getLastPathSegment()) + "."+ext;
}
//How to recognize the correct hash?
//return FilenameUtils.removeExtension(Data.currentFiles
// .get(names.get(imageUri)).getName()) + "." + ext;
}
public void setTrackData(String uri, String hash) {
if(!names.containsKey(uri))
names.put(uri, new HashSet<String>());
names.get(uri).add(hash);
}
But I'm at a dead end, because it's impossible to understand for which file I'm displaying the image, as generate only takes imageURI as parameter and more hashes can belong to the same uri.
How could I circumvent this issue?
I think I've found a solution for this.
Whenever I call my ImageLoader instance to show an image, I use
if (uri != null && !uri.isEmpty()) {
uri = Uri.parse(uri).buildUpon()
.appendQueryParameter("myhashkeyparameter", "myHashValue").toString();
}
mImageLoader.displayImage(uri,mImageView);
This code will append to a vaild uri a query parameter, the uri will become:
http://someuri/image.jpg?myhashkeyparameter=myHashValue
Then in the FileNameGenerator's generate method I can use
String hash = Uri.parse(imageUri).getQueryParameter("myhashkeyparameter");
to retrieve the wanted file without relying on using the imageUri as key.
Full code:
#Override
public String generate(String imageUri) {
if(imageUri==null||imageUri.isEmpty()) return "";
if (imageUri.startsWith("file:///")) {
return FilenameUtils.removeExtension(Uri.parse(imageUri)
.getLastPathSegment()) + "."+ext;
}
String hash = Uri.parse(imageUri).getQueryParameter("myhashkeyparameter");
if(null==hash||hash.isEmpty()) return "";
if(Data.currentFiles.containsKey(hash)){
return FilenameUtils.removeExtension(Data.currentFiles.get(hash).getName())+".png";
}
else return "";
}
You just have to be careful that the string used as queryparameter is not already used in the http URL, so avoid traditional names like name,hash,h,title and so on.

User Generated Image for Open Graph from Android

I've been following the tutorial to create an open graph story here. Everything works nicely, but I'd like the uploaded image to be large i.e. "user generated".
My problem is in actually implementing that. Here's the code that gets the image from the SD card:
// If uploading an image, set up the first batch request
// to do this.
// Set up image upload request parameters
Bundle imageParams = new Bundle();
Bitmap image = BitmapFactory.decodeFile(getActivity().getIntent().getStringExtra("image_for_facebook"));
// Set up the image upload request callback
Request.Callback imageCallback = new Request.Callback() {
#Override
public void onCompleted(Response response) {
// Log any response error
FacebookRequestError error = response.getError();
if (error != null) {
dismissProgressDialog();
Log.i(TAG, error.getErrorMessage());
}
}
};
// Create the request for the image upload
Request imageRequest = Request.newUploadStagingResourceWithImageRequest(Session.getActiveSession(),
image, imageCallback);
// Set the batch name so you can refer to the result
// in the follow-on object creation request
imageRequest.setBatchEntryName("imageUpload");
// Add the request to the batch
requestBatch.add(imageRequest);
And here's the bit which subsequently gives the graph object its properties:
// Set up the OpenGraphObject representing the book.
OpenGraphObject book = OpenGraphObject.Factory.createForPost("books.book");
// Set up the book image; if we uploaded the image, it is the "uri" result from the previous
// batch request, otherwise it is just a URL.
String imageUrl = "{result=imageUpload:$.uri}";
book.setImageUrls(Arrays.asList(imageUrl));
book.setTitle("A Game of Thrones");
book.setUrl("https://facemash.biz/books/a_game_of_thrones/");
book.setDescription("In the frozen wastes to the north of Winterfell, sinister and supernatural forces are mustering.");
// books.book-specific properties go under "data"
book.getData().setProperty("isbn", "0-553-57340-3");
What do I have to do to set the "user_generated" parameter of the image shown here to be true? (Assuming of course that I'm right in thinking that that's all I have to do to get a large image rather than a thumbnail).
Thanks!
Have a look at the Scrumptious sample, in SelectionFragment.java, the getImageObject method. Basically, you need to create a graph object with the "url" and the "user_generated" properties:
GraphObject imageObject = GraphObject.Factory.create();
imageObject.setProperty("url", "{result=imageUpload:$.uri}");
imageObject.setProperty("user_generated", "true");
GraphObjectList<GraphObject> images = GraphObject.Factory.createList(GraphObject.class);
images.add(imageObject);
book.setImage(images);
Ming's answer came very close for me. In order to attach an image to an OpenGraphAction, I had to do the following:
GraphObject imageObject = GraphObject.Factory.create();
imageObject.setProperty("url", imageUrl);
imageObject.setProperty("user_generated", true);
List<JSONObject> images = new ArrayList<JSONObject>();
images.add(imageObject.getInnerJSONObject());
action.setImage(images);
Open Graph Actions have the method setImage(List<JSONObject> images), but I couldn't find a setImage(GraphObjectList<GraphObject>) method. I'm using Facebook SDK v3.6, so that may have changed.

Need suggestion about a mixed "Uri / int id" images ambient

I have the following problem:
suppose that until now, I am using R.drawable.img to set the image in some imageviews
with
imgView.setImage(aProduct.getImgId());
the simplified product class look like this:
class Product{
int imgId;
....
public void setImgId(int id){
this.imgId=id;
}
public int getImgId(){
return this.imgId
}
...
}
my application is now "evolved" because the user can add customized products
taking the img from the camera and getting the Uri of the picture.
and to set the image on the ImageView imgView.setImgURI(Uri)
Now my question is:
what would be the best approach to have a mixed int/Uri image resources ambient?
can I obtain the Uri of a "R.drawable.img"?
I'm not sure if my question is clear, I mean:
I have to check, before to set the imageview, if my product has an Uri or an int Id,
and then make an "if" to call the appropriate method, or there is a simpler solution?
Thank you for reading, and sorry for my english.
Regards.
Your problem is that there are basically 3 types of image resources:
R.id... resources: internal resources, such as icons you put into the res folder
content URI's: local files or content provider resources such as content:// or file:///sdcard/...
remote file URL's: images on the web, such as http://...
You are looking for a way to pass around one identifier that can deal with all three. My solution was to pass around a string: either the toString() of the URI's, or just the string respresentation of the R.id integer.
I'm using the following code, for example, to deal with this and make the code work with it:
public static FastBitmapDrawable returnAndCacheCover(String cover, ImageRepresentedProductArtworkCreator artworkCreator) {
Bitmap bitmap = null;
Uri coverUri = null;
boolean mightBeUri = false;
//Might be a resId. Needs to be cached. //TODO: problem: resId of default cover may not survive across versions of the app.
try {
bitmap = BitmapFactory.decodeResource(Collectionista.getInstance().getResources(), Integer.parseInt(cover));
} catch (NumberFormatException e) {
//Not a resId after all.
mightBeUri=true;
}
if(bitmap==null || mightBeUri){
//Is not a resId. Might be a contentUri.
try {
coverUri = Uri.parse(cover);
} catch (NullPointerException ne) {
//Is null
return null;
}
}
if(coverUri!=null){
if(coverUri.getScheme().equals("content")){
//A contentUri. Needs to be cached.
try {
bitmap = MediaStore.Images.Media.getBitmap(Collectionista.getInstance().getContentResolver(), coverUri);
} catch (FileNotFoundException e) {
return null;
} catch (IOException e) {
return null;
}
}else{
//Might be a web uri. Needs to be cached.
bitmap = loadCoverFromWeb(cover);
}
}
return new FastBitmapDrawable(bitmap);
}
You might be interested to take over the logic part. Ofcourse cover is the string in question here.
Forget android.resource:// as a replacement for the R.id... integer. Claims are going round it does not work: http://groups.google.com/group/android-developers/browse_thread/thread/a672d71dd7df4b2d
To find out how to implement loadCoverFromWeb, have a look around in other questions or ping me. This web stuff is kind of a field of it's own.
(Based on GPLv3 code out of my app Collectionista: https://code.launchpad.net/~pjv/collectionista/trunk)

Categories

Resources