1

In my application, I use an intent to get an image filename from the gallery and im trying to load this filename into a TImage. I tried to load it with LoadFromFile as well as getting the JBitmap, converting it to TBitmap and Assign it to my TImage. This only work with bitmap with a maximum size of 98 x 98 pixels... if the width or the height is bigger than 99 or 98 pixel MOST OF THE TIME I get an error message 'Bitmap size too big'. Sometime I can go up to 250 x 250...

IM trying to find why since 3 days...

Here is the code :

var

  jBitmapD, jSmallBitmap: JBitmap;
  BitmapD : TBitmap;
  imgW, imgH:Integer;

begin

...
    jBitmapD := TJBitmapFactory.JavaClass.decodeFile(StringToJString(imgGallerieChm));

    ...

    jSmallBitmap := TJBitmap.JavaClass.createScaledBitmap(jBitmapD, 98, 98, True);

    //jSmallBitmap := TJBitmap.JavaClass.createScaledBitmap(jBitmapD, 101, 101, True);
    //jSmallBitmap := TJBitmap.JavaClass.createScaledBitmap(jBitmapD, 1234, 567, True);
    ...

    imgH := jSmallBitmap.getHeight;
    imgW := jSmallBitmap.getWidth;

    bitmapD := TBitmap.Create; //Work if jSmallBitmap if smaller than 99 x 99

    //bitmapD.Create(98,98); //Work  if jSmallBitmap if smaller than 99 x 99
    //bitmapD.Create(222,333); //Don't work

    try
       bitmapD.SetSize(imgW,ImgH); //without this, its not working and it should be 99 x 99 or less... most of the time
       bitmapD := JBitmapToBitmap(jSmallBitmap);
       imgLepObs.Bitmap.Assign(bitmapD);
    finally
       bitmapD.Free;
    end;

The next function work if AImage and TBitmap are smaller than 99 x 99 most of the time

function TfrmMain.JBitmapToBitmap(const AImage: JBitmap): TBitmap;
var
  bitmapSurface :TBitmapSurface;
begin
  bitmapSurface := TBitmapSurface.Create;
  try
    if JBitmapToSurface(AImage, bitmapSurface) then
      begin

      Result.Assign(bitmapSurface);
      end;
  finally
  bitmapSurface.Free;
  end;
end;

Thank you for your help... im about to giveup...

I tried downscaling my bitmap with this :

bfOptions.inSampleSize := StrToInt(Edit1.Text); //
bfOptions.inJustDecodeBounds := False;
jSmallBitmap := TJBitmapFactory.JavaClass.decodeFile(StringToJString(imgGallerieChm), bfOptions);

It work most of the time... the smaller the resulting bitmap, the higher chance of success... for a given size, it sometime work, sometime not, and sometime it work right after I restart my application...

mjn
  • 36,362
  • 28
  • 176
  • 378
JoSyl
  • 13
  • 1
  • 4

3 Answers3

2

I have got a similar problem. The problem was a known bug in delphi RTL for android. If you create an image within a thread you will get an exception: TBitmap.Create raises 'Bitmap size too big'. It is because the canvas factory can't get the right canvastype. It must be fixed by EMB. I create my bitmap in a main thread, that works for now.

Enny
  • 759
  • 5
  • 8
  • This is exactly my problem. Can you explain ". I create my bitmap in a main thread, that works for now" ? – JoSyl Nov 07 '14 at 14:57
  • 1
    It work very well on the main thread ! Thank you for the help ! I don't need to load the JImage, I just need to get the path name and then in a procedure in my main thread, I just have to use LoadFromFile ! – JoSyl Nov 07 '14 at 16:23
  • Ok. Sorry for late reply. I hope EMB will fix it soon. – Enny Nov 07 '14 at 21:34
  • I load image into stream and create Bitmap in TThread.Synchronize – sliwinski.lukas Oct 01 '15 at 07:26
0

The solution i would propose for you is to decode the larger image.

BitmapFactory class provides several decoding methods (decodeByteArray(), decodeFile(), decodeResource(), etc.).

Refer to the below SO link for my answer. I have provided the steps and code sample to decode an image.

OutOfMemoryError with image selection in Android. How to resize image before decoding it to bitmap?

Community
  • 1
  • 1
Prem
  • 4,823
  • 4
  • 31
  • 63
  • Thanks for your answer. I currently use your method to load my bitmap but nothing changed... I can't work with bitmap bigger than around 100 x 100 pixels... – JoSyl Nov 07 '14 at 14:55
-2
            public class ImageLoader {

                MemoryCache memoryCache=new MemoryCache();
                FileCache fileCache;
                private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
                ExecutorService executorService; 

                public ImageLoader(Context context){

                    fileCache=new FileCache(context);
                    executorService=Executors.newFixedThreadPool(5);
                }

                final int stub_id=R.drawable.ic_launcher;
                public void DisplayImage(String url, ImageView imageView)
                {
                    imageViews.put(imageView, url);
                    Bitmap bitmap=memoryCache.get(url);
                    if(bitmap!=null)
                        imageView.setImageBitmap(bitmap);
                    else
                    {
                        queuePhoto(url, imageView);
                        imageView.setImageResource(stub_id);
                    }
                }

                private void queuePhoto(String url, ImageView imageView)
                {
                    PhotoToLoad p=new PhotoToLoad(url, imageView);
                    executorService.submit(new PhotosLoader(p));
                }

                private Bitmap getBitmap(String url) 
                {
                    File f=fileCache.getFile(url);

                    //from SD cache
                    Bitmap b = decodeFile(f);
                    if(b!=null)
                        return b;

                    //from web
                    try {
                        Bitmap bitmap=null;
                        URL imageUrl = new URL(url);
                        HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
                        conn.setConnectTimeout(30000);
                        conn.setReadTimeout(30000);
                        conn.setInstanceFollowRedirects(true);
                        InputStream is=conn.getInputStream();
                        OutputStream os = new FileOutputStream(f);
                        Utils.CopyStream(is, os);
                        os.close();
                        bitmap = decodeFile(f);
                        return bitmap;
                    } catch (Throwable ex){
                       ex.printStackTrace();
                       if(ex instanceof OutOfMemoryError)
                           memoryCache.clear();
                       return null;
                    }
                }

                //decodes image and scales it to reduce memory consumption
                private Bitmap decodeFile(File f){
                    try {
                        //decode image size
                        BitmapFactory.Options o = new BitmapFactory.Options();
                        o.inJustDecodeBounds = true;
                        BitmapFactory.decodeStream(new FileInputStream(f),null,o);

                        //Find the correct scale value. It should be the power of 2.
                        final int REQUIRED_SIZE=70;
                        int width_tmp=o.outWidth, height_tmp=o.outHeight;
                        int scale=1;
                        while(true){
                            if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                                break;
                            width_tmp/=2;
                            height_tmp/=2;
                            scale*=2;
                        }

                        //decode with inSampleSize
                        BitmapFactory.Options o2 = new BitmapFactory.Options();
                        o2.inSampleSize=scale;
                        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
                    } catch (FileNotFoundException e) {}
                    return null;
                }

                //Task for the queue
                private class PhotoToLoad
                {
                    public String url;
                    public ImageView imageView;
                    public PhotoToLoad(String u, ImageView i){
                        url=u; 
                        imageView=i;
                    }
                }

                class PhotosLoader implements Runnable {
                    PhotoToLoad photoToLoad;
                    PhotosLoader(PhotoToLoad photoToLoad){
                        this.photoToLoad=photoToLoad;
                    }

                    @Override
                    public void run() {
                        if(imageViewReused(photoToLoad))
                            return;
                        Bitmap bmp=getBitmap(photoToLoad.url);
                        memoryCache.put(photoToLoad.url, bmp);
                        if(imageViewReused(photoToLoad))
                            return;
                        BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
                        Activity a=(Activity)photoToLoad.imageView.getContext();
                        a.runOnUiThread(bd);
                    }
                }

                boolean imageViewReused(PhotoToLoad photoToLoad){
                    String tag=imageViews.get(photoToLoad.imageView);
                    if(tag==null || !tag.equals(photoToLoad.url))
                        return true;
                    return false;
                }

                //Used to display bitmap in the UI thread
                class BitmapDisplayer implements Runnable
                {
                    Bitmap bitmap;
                    PhotoToLoad photoToLoad;
                    public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
                    public void run()
                    {
                        if(imageViewReused(photoToLoad))
                            return;
                        if(bitmap!=null)
                            photoToLoad.imageView.setImageBitmap(bitmap);
                        else
                            photoToLoad.imageView.setImageResource(stub_id);
                    }
                }

                public void clearCache() {
                    memoryCache.clear();
                    fileCache.clear();
                }

            }
Kamuy
  • 177
  • 1
  • 6
  • I used a Java class called Image Loader to set an image in a image view. – Kamuy Nov 07 '14 at 03:05
  • 1
    Please [edit] your answer to provide some textual explanation of why this is necessary. Just providing code with no other content is frowned upon here. You've also posted Java code as an answer to a Delphi question, which isn't proper either. Java != Delphi. – Ken White Nov 07 '14 at 13:33