Вопрос

I want to add a limit on uploaded image size (currently images are uploaded to a server).

When anyone gets an image from SDcard or captures image from Camera, I want show message to user that it uploaded max file size - i.e 500kb or can I resize images into smaller sizes. For example 1mb image resize into 400-500kb (like Facebook).

Here is the sample code that I implemented after getting image from SDcard or captured image from Camera.

 FileConnection file = (FileConnection)Connector.open(url);
 if(file.exists())
 {
     try{
         String fileName = url .substring(url.lastIndexOf('/') + 1);
         //String fileName = url ;
         Dialog.alert("fileName  " + fileName);
         InputStream inputStream = file.openInputStream();

         ByteArrayOutputStream bos=new ByteArrayOutputStream();
         int buffersize=1024;
         byte[] buffer=new byte[buffersize];
         int length=0;
         while((length=inputStream.read(buffer))!=-1)
         {
             bos.write(buffer,0,length);
         }
         byte[] imagedata=bos.toByteArray();
         Dialog.alert("Url  " + Url  + " Image Data Byte " + imagedata);
         HttpConnection conn = (HttpConnection) Connector.open(Url, Connector.READ_WRITE);
         conn.setRequestMethod(HttpConnection.POST);
         String boundary = "Some_Unique_Text_Also_Alphanumeric";
         conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE,                    
             HttpProtocolConstants.CONTENT_TYPE_MULTIPART_FORM_DATA
                                 + ";boundary=" + boundary);

             conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH,
                         String.valueOf(imagedata.length));
         conn.setRequestProperty("x-rim-transcode-content", "none");

         ByteArrayOutputStream out = new ByteArrayOutputStream();
         OutputStream finalOut = conn.openOutputStream();

         String newLine = "\r\n";
         out.write(newLine.getBytes());
         out.write("--".getBytes());
         out.write(boundary.getBytes());
         out.write(newLine.getBytes());
         String contDisp = "Content-Disposition:form-data;name=\"image\";fileName=\"Image.jpg\"";
         String contEnc = "Content-Transfer-Encoding: binary";
         String contentType = "Content-Type:image/jpeg";
         out.write(contDisp.getBytes());
         out.write(newLine.getBytes());
         out.write(contentType.getBytes());
         out.write(newLine.getBytes());
         out.write(contEnc.getBytes());
         out.write(newLine.getBytes());
         out.write(newLine.getBytes());
         out.write(imagedata);
         out.write(newLine.getBytes());
         out.write("--".getBytes());
         out.write(boundary.getBytes());
         out.write("--".getBytes());
         out.write(newLine.getBytes());
         finalOut.write(out.toByteArray());

         out.flush();
         out.close();

         finalOut.flush();
         finalOut.close();
         InputStream instream=conn.openInputStream();
         int ch=0;
         StringBuffer buffesr=new StringBuffer();
         while((ch=instream.read())!=-1)
         {
             buffesr.append((char)ch);
             Dialog.alert("Uploaded");
         }
     }
     catch (Exception e) {

         Dialog.alert("Exception " + e);
     }   
 }

Any help ??

Это было полезно?

Решение

The problem is that with Camera pictures, you can't predict what physical image size (pixel width x height) will correspond to a certain size in bytes.

If you have a hard, fixed limit on the size (in bytes) that you can upload, you might need to do something like this:

  • experiment with a few images, and find an approximate image size (width x height) that will produce a JPG file that normally fits within your 400-500KB limit

  • in your app, resize the Camera images to that physical size (width x height, in pixels)

  • check the size of the new JPG data, and see if it fits under your limit

  • if it does not fit, then you'll have to rescale the original image to a smaller size

As you can see, this isn't that simple to do. Most servers that I've seen (e.g. Facebook) tell you the maximum physical size in pixels that your image can be (e.g. 960 pixels as the widest size ... either width or height). If that's good enough for your server, it's much easier to code on the BlackBerry client side.

Restrict to a Fixed Pixel Width and Height

You could use something like this:

FileConnection file;
InputStream inputStream;

try {
    file = (FileConnection) Connector.open(url);  // JPG file:// URL
    if (file.exists())
    {
        inputStream = file.openInputStream();           
        byte[] data = IOUtilities.streamToBytes(inputStream);

        Bitmap original = Bitmap.createBitmapFromBytes(data, 0, data.length, 1);

        Bitmap scaledImg = new Bitmap(640, 480);    // maximum width and height
        original.scaleInto(scaledImg, 
                           Bitmap.FILTER_LANCZOS,   /* LANCZOS is for best quality */
                           Bitmap.SCALE_TO_FIT);  

        // http://stackoverflow.com/a/14147236/119114
        int jpegQuality = 85;
        EncodedImage encodedImg = JPEGEncodedImage.encode(scaledImg, jpegQuality);
        byte[] imageData = encodedImg.getData(); 
        // TODO: send imageData as you already were       
    }
} catch (Exception e) {
    // log exception
} finally {
    try {
        if (file != null) {
            file.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
    } catch (IOException ioe) {
        // nothing can be done here
    }
}

Of course, you should perform all this work on a background thread. Once you know the final image size, if you really want to, you can notify the user with something like:

final uploadSizeKb = imageData.length / 1024;
UiApplication.getUiApplication().invokeLater(new Runnable() {
   public void run() {
      Dialog.alert(uploadSizeKb + "KB uploaded to server");
   }
});

Further Optimizations

As you can probably tell, there's things you can adjust with this algorithm:

  • You could optimize by checking to see if the image file is already small enough, before trying to scale it. (check file.fileSize())

  • You could speed up the image scaling by using Bitmap.FILTER_BILINEAR or Bitmap.FILTER_BOX instead of Bitmap.FILTER_LANCZOS.

  • You can change the JPEG quality factor from 85 when you convert back to JPEG for uploading

  • You might need to check image orientation to avoid wasting too much space when you scale with SCALE_TO_FIT. If the Camera image is in the wrong orientation, just switch the scaledImg bitmap width and height (e.g. 640x480 -> 480x640)

  • You actually can skip a couple steps, and scale directly when reading in the image file, with createBitmapFromBytes(). The last parameter is a scale parameter. Unfortunately, since photographs are all different, it would also be difficult to pick one scale ratio that would work. As I said, it's more common that the server simply specifies a maximum image size, in pixels.

OS < 5.0 Support

If you don't have the image scaling APIs in OS 5.0 available, this older toolkit can be useful.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top