I have an image which needs to be sent to the server. Is there a way to convert a bitmap(jpg) to base64 string in blackberry?
-
first convert the bitmap to byte array. Then convert it to base64 string – Rince Thomas Jan 02 '13 at 06:07
-
i tried to convert my bitmap to byte array, but converting it first to byte array consumes a lot of memory. – Jj Tuibeo Jan 02 '13 at 06:09
-
so using big size images ? – Rince Thomas Jan 02 '13 at 06:10
-
why do this? for uploading images, you really want to conserve bandwidth, especially for mobile devices. can you not change the server API? – Nate Jan 02 '13 at 06:12
-
i use getRGB565(...) to get the byte array. yes the image is quite big. – Jj Tuibeo Jan 02 '13 at 06:12
-
@Nate change server API ? – Rince Thomas Jan 02 '13 at 06:14
-
this is how my program works. i need to capture an image from the camera then send it to the server. but when i'm using a portrait screen blackberry device it rotates 90degrees counter clockwise. so my solution is get the bitmap of it from the bytearray then rotate it first, then get the bytearray from the rotated image then send the byte array of the rotated image to the server. – Jj Tuibeo Jan 02 '13 at 06:16
-
do you have any suggestion to solve the issue on capturing image using portrait screen device on blackberry? – Jj Tuibeo Jan 02 '13 at 06:17
-
Convert your image in ByteArray and the compress it after compressing pass it to convert in Base64 encoded String data. – Puneet Jan 02 '13 at 06:18
-
1@Signare, the BlackBerry app is the client here. It may be that the server specifies how the image must be uploaded. The person asking this question may, or may not, have any control over the server side implementation. So, he/she may not have any choice how the server wants to receive the data. But, encoding in Base64 does increase the size of the data you need to upload. – Nate Jan 02 '13 at 06:20
-
You say you have `an image`, `a bitmap(jpg)`. So what "starting point" do you have exactly? Is it a jpeg file taken by the Camera or what? What exactly does your server expect to get - a Base64-encoded data of (1) raw bitmap binary (4 bytes per one image pixel) or (2) jpeg-encoded binary? – Vit Khudenko Jan 02 '13 at 11:34
-
@Arhimed: it is an image taken by the camera. i used the VideoControl.getSnapshot(...) to use the camera of the device. it returns a byte[]. then i get the bitmap(jpeg) of an image from the byte[] so that i can rotate the image. i need to send the rotated image to the server. the server expect to get a Base64-encoded data of raw bitmap binary. what should i do to convert the rotated image to a type that the server will accept? thanks. – Jj Tuibeo Jan 03 '13 at 00:23
-
Hm.. You are saying you need "to get a Base64-encoded data of raw bitmap binary" and at the same time you're posting Bitmap->PNG code. These are completely different things. I am puzzled with what exactly you expect (or better to say what exactly your server expects)... – Vit Khudenko Jan 03 '13 at 09:10
-
3BTW, if this is under your control it would be better to move image processing on server side. When you get image from camera it's a JPEG compressed image (say 1MByte for 3MPx image), so the data to send on server is as small as possible, but when you get a raw bitmap, then data size will take in times more (3MPx * 4 = ~12MBytes) and even worse - when you apply Base64 encoding it will get another +33% (~16MBytes). Upload can be slower in 16 times.. Another concern is memory - it is not so easy to manipulate a 12MBytes array without the risk of getting `OutOfMemoryError`. – Vit Khudenko Jan 03 '13 at 09:19
-
Thanks for the useful information. – Jj Tuibeo Jan 04 '13 at 00:46
3 Answers
What you request is a bit vague and odd, however I hope this can help:
With the following piece code it's possible to get a JPEG binary data for a Bitmap
(note, it is a compressed one, so the size of the data is as small as possible if compare to raw bitmap):
Bitmap bmp = ...; // your bitmap
int quality = 85;
EncodedImage encodedImg = JPEGEncodedImage.encode(bmp, quality);
byte[] data = encodedImg.getData();
Then you can encode it with Base64OutputStream
. See the API for sample code on how to encode.

- 28,288
- 10
- 63
- 91
-
Sir thank you very much, this one is much better than what I've found. I don't need to create another class to convert my image, plus I can modify the quality of the encoded image. – Jj Tuibeo Jan 04 '13 at 00:30
-
1Glad, I was helpful. So finally it turns out you don't need "to get a Base64-encoded data of `raw bitmap binary`". :) – Vit Khudenko Jan 04 '13 at 08:48
package com.covidien.screens;
import java.io.OutputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.CDMAInfo;
import net.rim.device.api.system.GPRSInfo;
import net.rim.device.api.system.IDENInfo;
import net.rim.device.api.system.RadioInfo;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import org.kobjects.base64.Base64;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransport;
public final class ImageScreen extends MainScreen
{
/** The down-scaling ratio applied to the snapshot Bitmap */
private static final int IMAGE_SCALING = 5;
private static final String boundary = "31BF3856AD364E35";
/** The base file name used to store pictures */
private static String FILE_NAME = System.getProperty("fileconn.dir.photos") + "IMAGE";
/** The extension of the pictures to be saved */
private static String EXTENSION = ".png";
/** A counter for the number of snapshots taken */
private static int _counter;
/** A reference to the current screen for listeners */
private ImageScreen _imageScreen;
static String imageName=null;
/**
* Constructor
* @param raw A byte array representing an image
*/
public ImageScreen( final byte[] raw )
{
// A reference to this object, to be used in listeners
_imageScreen = this;
setTitle("IMAGE");
// Convert the byte array to a Bitmap image
Bitmap image = Bitmap.createBitmapFromBytes( raw, 0, -1, IMAGE_SCALING );
// Create two field managers to center the screen's contents
HorizontalFieldManager hfm1 = new HorizontalFieldManager( Field.FIELD_HCENTER );
HorizontalFieldManager hfm2 = new HorizontalFieldManager( Field.FIELD_HCENTER );
// Create the field that contains the image
BitmapField imageField = new BitmapField( image );
hfm1.add( imageField );
// Create the SAVE button which returns the user to the main camera
// screen and saves the picture as a file.
ButtonField photoButton = new ButtonField( "Use" );
photoButton.setChangeListener( new SaveListener(raw) );
hfm2.add(photoButton);
// Create the CANCEL button which returns the user to the main camera
// screen without saving the picture.
ButtonField cancelButton = new ButtonField( "Retake" );
cancelButton.setChangeListener( new CancelListener() );
hfm2.add(cancelButton);
// Add the field managers to the screen
add( hfm1 );
add( hfm2 );
}
/**
* Handles trackball click events
* @see net.rim.device.api.ui.Screen#invokeAction(int)
*/
protected boolean invokeAction(int action)
{
boolean handled = super.invokeAction(action);
if(!handled)
{
switch(action)
{
case ACTION_INVOKE: // Trackball click.
{
return true;
}
}
}
return handled;
}
/**
* A listener used for the "Save" button
*/
private class SaveListener implements FieldChangeListener
{
/** A byte array representing an image */
private byte[] _raw;
/**
* Constructor.
* @param raw A byte array representing an image
*/
SaveListener(byte[] raw)
{
_raw = raw;
}
/**
* Saves the image as a file in the BlackBerry filesystem
*/
public void fieldChanged(Field field, int context)
{
try
{
// Create the connection to a file that may or
// may not exist.
FileConnection file = (FileConnection)Connector.open( FILE_NAME + _counter + EXTENSION );
// If the file exists, increment the counter until we find
// one that hasn't been created yet.
while( file.exists() )
{
file.close();
++_counter;
file = (FileConnection)Connector.open( FILE_NAME + _counter + EXTENSION );
}
// We know the file doesn't exist yet, so create it
file.create();
// Write the image to the file
OutputStream out = file.openOutputStream();
out.write(_raw);
System.out.println("Boundary :::::"+boundary);
//*******************************************************************************************************
String serviceUrl = "URL/Service.asmx";
String serviceNamespace = "http://tempuri.org/";
String soapAction="http://tempuri.org/Upload";
SoapObject rpc = new SoapObject(serviceNamespace, "Upload");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = rpc;
envelope.dotNet = true;
envelope.encodingStyle = SoapSerializationEnvelope.XSD;
rpc.addProperty("contents",Base64.encode(_raw));
imageName="Image" + _counter + EXTENSION;
rpc.addProperty("FileName", imageName );
HttpTransport ht = new HttpTransport(serviceUrl);
ht.debug = true;
String result;
// String str = null;
SoapObject soapObject;
try
{
ht.call(soapAction, envelope);
result = (envelope.getResponse()).toString();
// if((envelope.getResponse()).toString().trim().equals("OK"))
// {
// UiApplication.getUiApplication().pushScreen(new DoctorPopup());
// }
// if(result.length()==2 || result.equalsIgnoreCase("OK"))
// {
// UiApplication.getUiApplication().pushScreen(new DoctorPopup());
// }
if(result.length()==2)
{
UiApplication.getUiApplication().pushScreen(new DoctorPopup());
}
soapObject = (SoapObject) envelope.getResponse();
// Dialog.alert("soapObject" + soapObject);
}
catch(Exception ex)
{
//if we get an exception we'll just write the msg to the screen.
System.out.println(ex.getMessage());
result = ex.toString();
}
// Close the connections
out.close();
file.close();
}
catch(Exception e)
{
WelcomeScreen.errorDialog("ERROR " + e.getClass() + ": " + e.getMessage());
System.out.println(e.getMessage());
}
++_counter;
}
}
/**
* A listener used for the "Cancel" button
*/
private class CancelListener implements FieldChangeListener
{
/**
* Return to the main camera screen
*/
public void fieldChanged(Field field, int context)
{
UiApplication.getUiApplication().popScreen( _imageScreen );
}
}
public final static boolean isCDMA() {
return RadioInfo.getNetworkType() == RadioInfo.NETWORK_CDMA;
}
public final static boolean isIDEN() {
return RadioInfo.getNetworkType() == RadioInfo.NETWORK_IDEN;
}
public static final String getIMEI() {
if (ImageScreen.isCDMA()) {
return ""+CDMAInfo.getESN();
} else if (ImageScreen.isIDEN()){
return IDENInfo.imeiToString(IDENInfo.getIMEI());
} else {
return GPRSInfo.imeiToString(GPRSInfo.getIMEI());
}
}
}
-
4Please don't post your entire app here. Just cut out the code you think should be used to encode the bitmap image. Also, make sure to select **all** of your source code in the edit window, and use the **{ }** button to format it as code. Take a look at your answer in the preview below the editor to make sure it's readable. Thanks. – Nate Jan 02 '13 at 06:38
-
2it doesn't have to wait until next time. there's a little **edit** link below your answer that you can use to go back any time and revise your answer. I often edit my answers many times. – Nate Jan 02 '13 at 06:44
-
I tried for the same page but i dunno it does not work for me, please do formatting once for me. – Puneet Jan 02 '13 at 06:58
-
2Too much code with no explanation of anything. I don't understand the upvotes. – Michael Donohue Jan 06 '13 at 02:39
Found this one, much faster conversion of Bitmap to byte[]. Exactly what I needed.
import java.io.*;
import javax.microedition.lcdui.Image;
import net.rim.device.api.compress.ZLibOutputStream;
public class MinimalPNGEncoder
{
public static Image toImage(int width, int height, byte[] alpha, byte[] red, byte[] green, byte[] blue)
{
try
{
byte[] png = toPNG(width, height, alpha, red, green, blue);
return Image.createImage(png, 0, png.length);
}
catch (IOException e)
{
return null;
}
}
public static byte[] toPNG(int width, int height, byte[] alpha, byte[] red, byte[] green, byte[] blue) throws IOException
{
byte[] signature = new byte[] {(byte) 137, (byte) 80, (byte) 78, (byte) 71, (byte) 13, (byte) 10, (byte) 26, (byte) 10};
byte[] header = createHeaderChunk(width, height);
byte[] data = createDataChunk(width, height, alpha, red, green, blue);
byte[] trailer = createTrailerChunk();
ByteArrayOutputStream png = new ByteArrayOutputStream(signature.length + header.length + data.length + trailer.length);
png.write(signature);
png.write(header);
png.write(data);
png.write(trailer);
return png.toByteArray();
}
public static byte[] createHeaderChunk(int width, int height) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(13);
DataOutputStream chunk = new DataOutputStream(baos);
chunk.writeInt(width);
chunk.writeInt(height);
chunk.writeByte(8); // Bitdepth
chunk.writeByte(6); // Colortype ARGB
chunk.writeByte(0); // Compression
chunk.writeByte(0); // Filter
chunk.writeByte(0); // Interlace
return toChunk("IHDR", baos.toByteArray());
}
public static byte[] createDataChunk(int width, int height, byte[] alpha, byte[] red, byte[] green, byte[] blue) throws IOException
{
int source = 0;
int dest = 0;
byte[] raw = new byte[4*(width*height) + height];
for (int y = 0; y < height; y++)
{
raw[dest++] = 0; // No filter
for (int x = 0; x < width; x++)
{
raw[dest++] = red[source];
raw[dest++] = green[source];
raw[dest++] = blue[source];
raw[dest++] = alpha[source++];
}
}
return toChunk("IDAT", toZLIB(raw));
}
public static byte[] createTrailerChunk() throws IOException
{
return toChunk("IEND", new byte[] {});
}
public static byte[] toChunk(String id, byte[] raw) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(raw.length + 12);
DataOutputStream chunk = new DataOutputStream(baos);
chunk.writeInt(raw.length);
byte[] bid = new byte[4];
for (int i = 0; i < 4; i++)
{
bid[i] = (byte) id.charAt(i);
}
chunk.write(bid);
chunk.write(raw);
int crc = 0xFFFFFFFF;
crc = updateCRC(crc, bid);
crc = updateCRC(crc, raw);
chunk.writeInt(~crc);
return baos.toByteArray();
}
static int[] crcTable = null;
public static void createCRCTable()
{
crcTable = new int[256];
for (int i = 0; i < 256; i++)
{
int c = i;
for (int k = 0; k < 8; k++)
{
c = ((c & 1) > 0) ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
}
crcTable[i] = c;
}
}
public static int updateCRC(int crc, byte[] raw)
{
if (crcTable == null)
{
createCRCTable();
}
for (int i = 0; i < raw.length; i++)
{
crc = crcTable[(crc ^ raw[i]) & 0xFF] ^ (crc >>> 8);
}
return crc;
}
/* This method is called to encode the image data as a zlib
block as required by the PNG specification. This file comes
with a minimal ZLIB encoder which uses uncompressed deflate
blocks (fast, short, easy, but no compression). If you want
compression, call another encoder (such as JZLib?) here. */
public static byte[] toZLIB(byte[] raw) throws IOException
{
//used the BB ZLib ...
ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
ZLibOutputStream compBytes = new ZLibOutputStream(outBytes, false, 10, 9);
compBytes.write(raw, 0, raw.length);
compBytes.close();
return outBytes.toByteArray();
//return ZLIB.toZLIB(raw);
}
}
class ZLIB
{
static final int BLOCK_SIZE = 32000;
public static byte[] toZLIB(byte[] raw) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(raw.length + 6 + (raw.length / BLOCK_SIZE) * 5);
DataOutputStream zlib = new DataOutputStream(baos);
byte tmp = (byte) 8;
zlib.writeByte(tmp); // CM = 8, CMINFO = 0
zlib.writeByte((31 - ((tmp << 8) % 31)) % 31); // FCHECK (FDICT/FLEVEL=0)
int pos = 0;
while (raw.length - pos > BLOCK_SIZE)
{
writeUncompressedDeflateBlock(zlib, false, raw, pos, (char) BLOCK_SIZE);
pos += BLOCK_SIZE;
}
writeUncompressedDeflateBlock(zlib, true, raw, pos, (char) (raw.length - pos));
// zlib check sum of uncompressed data
zlib.writeInt(calcADLER32(raw));
return baos.toByteArray();
}
private static void writeUncompressedDeflateBlock(DataOutputStream zlib, boolean last,
byte[] raw, int off, char len) throws IOException
{
zlib.writeByte((byte)(last ? 1 : 0)); // Final flag, Compression type 0
zlib.writeByte((byte)(len & 0xFF)); // Length LSB
zlib.writeByte((byte)((len & 0xFF00) >> 8)); // Length MSB
zlib.writeByte((byte)(~len & 0xFF)); // Length 1st complement LSB
zlib.writeByte((byte)((~len & 0xFF00) >> 8)); // Length 1st complement MSB
zlib.write(raw,off,len); // Data
}
private static int calcADLER32(byte[] raw)
{
int s1 = 1;
int s2 = 0;
for (int i = 0; i < raw.length; i++)
{
int abs = raw[i] >=0 ? raw[i] : (raw[i] + 256);
s1 = (s1 + abs) % 65521;
s2 = (s2 + s1) % 65521;
}
return (s2 << 16) + s1;
}
}
And this is the method that you need to invoke.
public static byte[] toPNG(Bitmap image) throws IOException {
int imageSize = image.getWidth() * image.getHeight();
int[] rgbs = new int[imageSize];
byte[] a, r, g, b;
int colorToDecode;
image.getARGB(rgbs, 0, image.getWidth() , 0, 0, image.getWidth(), image.getHeight());
a = new byte[imageSize];
r = new byte[imageSize];
g = new byte[imageSize];
b = new byte[imageSize];
for (int i = 0; i < imageSize; i++) {
colorToDecode = rgbs[i];
a[i] = (byte) ((colorToDecode & 0xFF000000) >>> 24);
r[i] = (byte) ((colorToDecode & 0x00FF0000) >>> 16);
g[i] = (byte) ((colorToDecode & 0x0000FF00) >>> 8);
b[i] = (byte) ((colorToDecode & 0x000000FF));
}
return MinimalPNGEncoder.toPNG(image.getWidth(), image.getHeight(), a, r, g, b);
}
This is not mine. I am so grateful to Christian Fr�schlin for creating this and letting other developers to use this. This is the link for the terms.
Before i forgot, this one has a limitation. It can converts successfully a bitmap to byte[] which size is less than or equal to 63kb, but if the size exceeds the limit the converted image will be discolored.

- 773
- 4
- 18