Writing a contact's photo into a vcf file, android - java

I am using a code in which a list of all contacts is shown. When I select a contact from the list, details of the contact are shown and saved in a .vcf file (in proper vcard format), working fine. when I select a contact which has a photo as well, it shows the photo in imageView, but I don't know how to write the photo in vcf file.
I have used these lines,
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,Integer.parseInt(item));
Bitmap photoBitmap;
ContentResolver cr = getContentResolver();
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(cr, photoUri);
photoBitmap = BitmapFactory.decodeStream(is);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
photoBitmap.compress(CompressFormat.JPEG, 100 , bos);
byte[] bitmapdata = bos.toByteArray();
imageEncoded = Base64.encodeToString(bitmapdata,Base64.DEFAULT);
String content = "BEGIN:VCARD\nVERSION:3.0\nCLASS:PUBLIC\nPRODID:-//class_vcard from TroyWolf.com//NONSGML Version 1//EN\nFN:"+contactName+"\nTEL;TYPE=cell,voice:"+number+"\nPHOTO;TYPE=JPEG;ENCODING=BASE64:"+imageEncoded+"\nTZ:+0000\nEND:VCARD";
But I am getting error while reading the contact("Failed to parse vCard for unexpected reason, Invalid line:")
Can anyone please help me solve the problem!

Try changing the value of the ENCODING parameter from BASE64 to B. B is the correct value to use in 3.0 vCards.
Also, the correct newline sequence for vCards is \r\n, not \n.
You might be interested in using a vCard library to generate your vCard. ez-vcard is one such library (disclaimer: I am the author).
VCard vcard = new VCard();
vcard.setClassification("PUBLIC");
vcard.setProdId("-//class_vcard from TroyWolf.com//NONSGML Version 1//EN");
vcard.setFormattedName(contactName);
TelephoneType tel = vcard.addTelephoneNumber(number);
tel.addType(TelephoneTypeParameter.CELL);
tel.addType(TelephoneTypeParameter.VOICE);
PhotoType photo = new PhotoType(bitmapdata, ImageTypeParameter.JPEG);
vcard.addPhoto(photo);
vcard.setTimezone(new TimezoneType(0, 0));
String content = Ezvcard.write(vcard).version(VCardVersion.V3_0).prodId(false).go();

This is a really late post, but I couldn't find any working solution on StackOverflow without using the library, so I thought it would be good to share my findings.
Changing the encoding parameter and correcting a newline sequence weren't enough to construct .vcf file with a photo. I also had to remove the line breaks after encoding to base64.
Sample code to convert Uri to base64 format (replace imageStream initialization as needed).
// string you can use to write to vcf file (3.0 vCards)
String.format("PHOTO;ENCODING=B;TYPE=JPEG: ,%s\r\n", convertUriToBase64(context, photoUri));
private String convertUriToBase64(Context context, String photoUri) {
InputStream imageStream = null;
try {
imageStream = context.getContentResolver().openInputStream(Uri.parse(photoUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
byte[] bitmapData = bos.toByteArray();
// line break has to be removed, so it is on the same line as PHOTO
return Base64.encodeToString(bitmapData, Base64.DEFAULT).replaceAll("\n", "");
}

Here's what I did to get a photo to send as part of the vCard...
Important things to consider:
1) Equipment: ZTE Axon 7 running Android 6.01
2) Couldn't get vCard 3.0 or 4.0 to function properly, could only use vCard 2.1
File vcfFile = new File(DisplayContactActivity.this.getExternalFilesDir(null), "generated.vcf");
try
{
/**Only Version 2.1 worked for me with or without PHOTO**/
FileWriter fw = new FileWriter(vcfFile);
fw.write("BEGIN:VCARD\r\n");
fw.write("VERSION:2.1\r\n");
fw.write("FN:" + "Contact 7" + "\r\n");
/*Getting the name of the File as I had saved it*/
String file_name = ("current_contact_image" + CONTACT_ID);
/*Get the bitmap that we stored in a File*/
Bitmap bitmap = getContactImage(file_name);
/*Convert bitmap to Base64*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String image_encoded = Base64.encodeToString(b, Base64.DEFAULT);
/*Write the encoded version of image to vCard 2.1, NOTICE that no determining whether the image is GIF or JPEG is needed*/
fw.write("PHOTO;ENCODING=BASE64:" + image_encoded + "\r\n");
/*Write some other stuff to the vCard also just trying to give whoever needs this a starting point*/
fw.write("TEL;Primary:" + "(586) 268-3437" + "\r\n");
fw.write("TEL;OTHER:" + "(313) 313-4545" + "\r\n");
fw.write("ADR;OTHER:" + "12345 AnyLane Dr." + "\r\n");
fw.write("ADR;OTHER:" + "54321 AnyPlace Av." + "\r\n");
fw.write("EMAIL;OTHER:" + "email#yahoo.com" + "\r\n");
fw.write("EMAIL;OTHER:" + "email#wowway.com" + "\r\n");
fw.write("END:VCARD\r\n");
fw.close();
Intent i = new Intent();
i.setAction(android.content.Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(vcfFile), "text/x-vcard");
startActivity(i);
}
catch (Exception e)
{
Log.i(TAG, "Exception: " + e);
}
public Bitmap getContactImage(String file_name)
{
Log.i(TAG, "Running getContactImage() with file name: " + file_name);
Bitmap thumbnail = null;
//------------------------------------------------------------------------------------------
try
{
File filePath = getBaseContext().getFileStreamPath(file_name);
FileInputStream fis = new FileInputStream(filePath);
thumbnail = BitmapFactory.decodeStream(fis);
}
catch (Exception e) //Use scaled_bitmap_for_storage instead of the current_contact_image file name
{
/*Error getting user-selected image, set boolean to get default image*/
Log.i(TAG, "Exception while running getContactImage() for file name: " + file_name + " with error message: " + e);
}
//------------------------------------------------------------------------------------------
return thumbnail;
}

Related

SmbFileOutputStream write creating corrupted jpg files

I'm using JCIFS SmbFileOutputStream write to upload jpg (and mp4) files to a share on a local Windows network. While this works well most of the time, I sometimes find that the resulting files are corrupt - e.g. if it's a jpg perhaps only the top part of the photo will be legible/visible.
I have the upload in a try/catch block, but it is not throwing an exception. Is there any way that I can verify that a file has been uploaded correctly?
try {
if (debugging_on) {
logger.info("UploadService.011 UploadFiles: uploading file:" + destFileName);
}
SmbFileOutputStream sfos = new SmbFileOutputStream(sFile);
FileInputStream fileInputStream = new FileInputStream(new File(
sSourceFilePath));
byte[] buf = new byte[16 * 1024 * 1024];
int len;
while ((len = fileInputStream.read(buf)) > 0) {
sfos.write(buf, 0, len);
}
fileInputStream.close();
sfos.close();
// Update the database to include the date/time of this upload
millisStart = Calendar.getInstance().getTimeInMillis();
sql = "UPDATE upload_history SET file_uploaded_date = "
+ millisStart + " WHERE filename = '" + filename + "'";
db.execSQL(sql);
} catch (Exception e) {
mNotifyBuilder.setContentText("Upload error - check folder permissions");
mNotificationManager.notify(1, mNotifyBuilder.build());
return "WriteFailure";
sfos.close();
needs to go before
fileInputStream.close();
Close the output before you close the input,
Adding 'sfos.flush()' couldn't hurt.

Saving multi-layered TIFF images without losing layer information in Java

I'm trying to save tiff images uploaded via browser using Spring and JAI ImageIO. I can save the image using the code below but the problem is that the saved image doesn't have the layers(the ones that tiff images consist of) which it has before uploading.
Are there any other parameters to ensure that the saved image also has the layers?
private void saveTiffImage(byte[] bytes, String uuid) throws Exception {
SeekableStream stream = new ByteArraySeekableStream(bytes);
String[] names = ImageCodec.getDecoderNames(stream);
ImageDecoder dec =
ImageCodec.createImageDecoder(names[0], stream, null);
RenderedImage im = dec.decodeAsRenderedImage();
String fileName = uuid + ".tif";
com.sun.media.jai.codec.TIFFEncodeParam params = new com.sun.media.jai.codec.TIFFEncodeParam();
params.setCompression(com.sun.media.jai.codec.TIFFEncodeParam.COMPRESSION_PACKBITS);
FileOutputStream os = new FileOutputStream(IMG_LOCATION + fileName);
javax.media.jai.JAI.create("filestore", im, IMG_LOCATION + fileName, "TIFF", params);
os.flush();
os.close();
}
I've found the solution using the answer here : How to combine two or many tiff image files in to one multipage tiff image in JAVA.
private Object[] saveTiffImage(byte[] bytes, String uuid) throws Exception {
SeekableStream stream = new ByteArraySeekableStream(bytes);
String[] names = ImageCodec.getDecoderNames(stream);
ImageDecoder dec =
ImageCodec.createImageDecoder(names[0], stream, null);
// Here we get the other pages.
Vector vector = new Vector();
int pageCount = dec.getNumPages();
for (int i = 1; i < pageCount; i++) {
RenderedImage im = dec.decodeAsRenderedImage(i);
vector.add(im);
}
String fileName = uuid + ".tif";
com.sun.media.jai.codec.TIFFEncodeParam params = new com.sun.media.jai.codec.TIFFEncodeParam();
params.setCompression(com.sun.media.jai.codec.TIFFEncodeParam.COMPRESSION_PACKBITS);
// Then set here
params.setExtraImages(vector.iterator());
// This is the first page
RenderedImage im = dec.decodeAsRenderedImage(0);
FileOutputStream os = new FileOutputStream(IMG_LOCATION + fileName);
javax.media.jai.JAI.create("filestore", im, IMG_LOCATION + fileName, "TIFF", params);
os.flush();
os.close();
}

Convert base64 string to image

I am trying to crop/resize user profile image using jquery plugin namely crop.js which sends user image as base64 via ajax to my controller as
$.ajax({
type: "post",
dataType: "json",
url: "${g.createLink(controller: 'personalDetail', action:'uploadUserImage')}",
data: { avatar: canvas.toDataURL() }
});
but I unable to decode this base64
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAADwCAYAAAA+VemSAAAgAEl...=='
string as Image,Can you guys guide me how can I save my base64 string as image on my server?.
In the server, do something like this:
Suppose
String data = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAADwCAYAAAA+VemSAAAgAEl...=='
Then:
String base64Image = data.split(",")[1];
byte[] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(base64Image);
Then you can do whatever you like with the bytes like:
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imageBytes));
This assumes a few things, that you know what the output file name will be and that your data comes as a string. I'm sure you can modify the following to meet your needs:
// Needed Imports
import java.io.ByteArrayInputStream;
import sun.misc.BASE64Decoder;
def sourceData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPAAAADwCAYAAAA+VemSAAAgAEl...==';
// tokenize the data
def parts = sourceData.tokenize(",");
def imageString = parts[1];
// create a buffered image
BufferedImage image = null;
byte[] imageByte;
BASE64Decoder decoder = new BASE64Decoder();
imageByte = decoder.decodeBuffer(imageString);
ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
image = ImageIO.read(bis);
bis.close();
// write the image to a file
File outputfile = new File("image.png");
ImageIO.write(image, "png", outputfile);
Please note, this is just an example of what parts are involved. I haven't optimized this code at all and it's written off the top of my head.
ImageIO.write() will compress the image by default - the compressed image has a smaller size but looks strange sometimes. I use BufferedOutputStream to save the byte array data - this will keep the original image size.
Here is the code:
import javax.xml.bind.DatatypeConverter;
import java.io.*;
public class ImageTest {
public static void main(String[] args) {
String base64String = "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAHkAAAB5C...";
String[] strings = base64String.split(",");
String extension;
switch (strings[0]) {//check image's extension
case "data:image/jpeg;base64":
extension = "jpeg";
break;
case "data:image/png;base64":
extension = "png";
break;
default://should write cases for more images types
extension = "jpg";
break;
}
//convert base64 string to binary data
byte[] data = DatatypeConverter.parseBase64Binary(strings[1]);
String path = "C:\\Users\\Ene\\Desktop\\test_image." + extension;
File file = new File(path);
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file))) {
outputStream.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Simplicity is:
import java.util.Base64;
To decode:
byte[] image = Base64.getDecoder().decode(base64string);
To encode:
String text = Base64.getEncoder().encodeToString(imageData);
Server side encoding files/Images to base64String ready for client side consumption
public Optional<String> InputStreamToBase64(Optional<InputStream> inputStream) throws IOException{
if (inputStream.isPresent()) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
FileCopyUtils.copy(inputStream.get(), output);
//TODO retrieve content type from file, & replace png below with it
return Optional.ofNullable("data:image/png;base64," + DatatypeConverter.printBase64Binary(output.toByteArray()));
}
return Optional.empty();
}
Server side base64 Image/File decoder
public Optional<InputStream> Base64InputStream(Optional<String> base64String)throws IOException {
if (base64String.isPresent()) {
return Optional.ofNullable(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(base64String.get())));
}
return Optional.empty();
}
public Optional<String> InputStreamToBase64(Optional<InputStream> inputStream) throws IOException{
if (inputStream.isPresent()) {
ByteArrayOutputStream outpString base64Image = data.split(",")[1];
byte[] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(base64Image);
Then you can do whatever you like with the bytes like:
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imageBytes));ut = new ByteArrayOutputStream();
FileCopyUtils.copy(inputStream.get(), output);
//TODO retrieve content type from file, & replace png below with it
return Optional.ofNullable("data:image/png;base64," + DatatypeConverter.printBase64Binary(output.toByteArray()));
}
return Optional.empty();
Hi This is my solution
Javascript code
var base64before = document.querySelector('img').src;
var base64 = base64before.replace(/^data:image\/(png|jpg);base64,/, "");
var httpPost = new XMLHttpRequest();
var path = "your url";
var data = JSON.stringify(base64);
httpPost.open("POST", path, false);
// Set the content type of the request to json since that's what's being sent
httpPost.setRequestHeader('Content-Type', 'application/json');
httpPost.send(data);
This is my Java code.
public void saveImage(InputStream imageStream){
InputStream inStream = imageStream;
try {
String dataString = convertStreamToString(inStream);
byte[] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(dataString);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
// write the image to a file
File outputfile = new File("/Users/paul/Desktop/testkey/myImage.png");
ImageIO.write(image, "png", outputfile);
}catch(Exception e) {
System.out.println(e.getStackTrace());
}
}
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
This is Ayano's excellent answer, but in Clojure:
(:import (java.awt.image BufferedImage)
(javax.xml.bind DatatypeConverter)
(java.io File BufferedOutputStream FileOutputStream))
(defn write-svg-encountered-image [svg-img-data base-filename]
(let [[meta img-data] (str/split svg-img-data #",")
extension (case meta
"data:image/jpeg;base64" ".jpeg"
"data:image/png;base64" ".png"
(throw (Error. (format "Unrecognised image metadata in SVG:" meta))))
path (str base-filename extension)
file (File. path)
data-bytes (DatatypeConverter/parseBase64Binary img-data)
os (BufferedOutputStream. (FileOutputStream. file))]
(.write os data-bytes)))
To Convert all file types
String[] strings = expense.getAttchBase64().split(",");
String extension;
switch (strings[0]) {//check image's extension
case "data:image/jpeg;base64":
extension = "jpeg";
break;
case "data:image/png;base64":
extension = "png";
break;
case "data:application/pdf;base64":
extension = "pdf";
break;
case "data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64":
extension = "docx";
break;
default://should write cases for more images types
extension = "jpg";
break;
}
//convert base64 string to binary data
byte[] data = DatatypeConverter.parseBase64Binary(strings[1]);
String fileName = UUID.randomUUID().toString();
String path = "C:\\floridatrading\\" + fileName + "." + extension;
File file = new File(path);
try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file))) {
outputStream.write(data);
} catch (IOException e) {
e.printStackTrace();
}
if you need to add any new type just add It in switch .

Take a path of a bitmap image and convert it into Base64

I'm trying to take a path of an image like:
"content://media/external/images/media/3"
and convert it into a base64 string.
Here is the code I have now:
public String ConvertandSetImagetoBase64(String imagePath) {
String base64 = null;
byte[] input = null;
try{
FileInputStream fd = new FileInputStream(imagePath);
Bitmap bmt = BitmapFactory.decodeFileDescriptor(fd.getFD());
try{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Bitmap tmp = ProfileActivity.scaleDownBitmap(bmt, 10, this);
tmp.compress(Bitmap.CompressFormat.JPEG, 10, stream);
input = stream.toByteArray();
base64 = Base64.encodeToString(input, Base64.DEFAULT);
//LocalProfileActivity.input = input;
}catch(Exception e){
Log.e(LOG_TAG,"[ONACTIVITYRESULT] Could not bind input to the bytearray: " + e.getMessage());
}
}
catch (Exception e){
Log.e("LocalProfile", "ConvertandSetImagetoBase64: Could not load selected profile image");
}
return base64;
}
content://media/external/images/media/3 is what I'm passing into the the method. Can anyone help me?
Since you are specifying the location as a URI, you could try something like:
URL url = new URL(imagePath);
Bitmap bmt = BitmapFactory.decodeStream(url.openStream());

Android post high res image running out of memory

Good day fellow developers.
I'm busy for android to upload images from a app.
I also got it working (code will follow below).
But when i send large images (10 megapixels) my app crashes with an out-of-memory exception.
A solution for this is to use compression but what if i want to send the full size image?
I think perhaps something with a stream but i'm not familair with streams. Perhaps urlconnection might help to but i really have no idea.
I give the filename the name File[0 to 9999].jpg
The post value with the image date is called Filedata
I give a UID for the post value dropboxid
The code below works but i would love to solve my problem that prevents me from sending high res images.
kind regards
try
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.JPEG, 100, bos);
byte[] data = bos.toByteArray();
HttpPost postRequest = new HttpPost(URL_SEND);
ByteArrayBody bab = new ByteArrayBody(data, "File" + pad(random.nextInt(9999) + 1) + ".jpg");
MultipartEntity reqEntity = new multipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("Filedata", bab);
reqEntity.addPart("dropboxId", new StringBody(URLEncoder.encode(uid)));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
String sResponse;
StringBuilder s = new StringBuilder();
while((sResponse = reader.readLine()) != null)
{
s = s.append(sResponse);
}
if(d) Log.i(E, "Send response:\n" + s);
}
catch (Exception e)
{
if(d) Log.e(E, "Error while sending: " + e.getMessage());
return ERROR;
}
When using ByteArrayOutputStream and then calling #toByteArray() you've effectively doubled the amount of memory the JPEG is using. ByteArrayOutputStream keeps an internal array with the encoded JPEG and when you call #toByteArray() it allocates a new array & copies the data from the internal buffer.
Consider encoding large bitmaps to a temporary file & using FileOutputStream and FileInputStream to encode and send the image.
Without "uploading" - your app survives "nicely" with the just the huge bitmap in memory I assume?
Edit: FileBody
File img = new File(this is where you put the path of your image)
ContentBody cb = new FileBody(img, "File" + pad(random.nextInt(9999) + 1) + ".jpg", "image/jpg", null);
MultipartEntity reqEntity = new multipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("Filedata", cb);
reqEntity.addPart("dropboxId", new StringBody(URLEncoder.encode(uid)));

Categories

Resources