Question

i'm developing an app i which users can upload images from the camera to an event, i did it in the usual way, but when i got to the part of rotating it according to the Exif interface i would sometimes get OOM errors, which were really frustrating, i decided to try and use JniBitmapOperations library which seemed to work fine (i wouldn't get OOM errors) but when trying to rotate the image it gets corrupt and messed up :/ heres pictures

enter image description here

enter image description here

as you can see the picture above is rotated to the correct position but is all corrupt the one below is the original

here is the part of the code that is relevant:

        Options options = new Options();
            options.inJustDecodeBounds = true;
            options.inPreferredConfig = Config.ARGB_8888;
            Bitmap srcBitmap = BitmapFactory.decodeFile(tempImageFilePath, options);

            options.inSampleSize = calculateInSampleSize(options);

            options.inJustDecodeBounds = false;
            srcBitmap = BitmapFactory.decodeFile(tempImageFilePath, options);

            ImageLoader.getInstance().clearMemoryCache();
            ImageLoader.getInstance().clearDiscCache();
            final JniBitmapHolder bitmapHolder = new JniBitmapHolder(srcBitmap);
        //if we comment this part out, the image comes out fine but not rotated correctly
            switch (angleFix) {
            case 90:
                bitmapHolder.rotateBitmapCw90();
                break;
            case 180:
                bitmapHolder.rotateBitmapCw90();
                bitmapHolder.rotateBitmapCw90();
                break;
            case 270:
                bitmapHolder.rotateBitmapCcw90();
                break;
            }

            srcBitmap = bitmapHolder.getBitmapAndFree();
//this is the old way which caused OOM errors occasionally
            // Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), m, true);

            try {
                FileOutputStream out = new FileOutputStream(tempImageFilePath);
                srcBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (srcBitmap != null) {
                GetImageUploadUrl getUrl = new GetImageUploadUrl();
                getUrl.execute();
            }
        }
    }

i would appreciate any help!

Was it helpful?

Solution

ok, the bug was with setting the wrong width and height for the rotation functions.

i've now updated the code. now it should work.

I am very sorry for this bug. was sure that i've fixed it before. i've now added the ability to also rotate by 180 degrees, so that you won't need to rotate twice (a little more efficient).

and just to say that the sample code wasn't for nothing, here's a nicer sample code.

it will go over all of your camera images, and rotate them in any of the 3 ways, and put the result files into Android/data/PACKAGE_NAME .

here's the code:

public class MainActivity extends Activity
  {
  @Override
  protected void onCreate(final Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final File picFolder=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
    final int screenWidth=getResources().getDisplayMetrics().widthPixels;
    final int screenHeight=getResources().getDisplayMetrics().heightPixels;
    final File outputDir=getExternalFilesDir(null);
    final ProgressDialog progressDialog=ProgressDialog.show(this,"please wait","processing");
    new AsyncTask<Void,Void,Void>()
      {
        @Override
        protected Void doInBackground(final Void... params)
          {
          final File[] listFiles=outputDir.listFiles((FileFilter)null);
          for(final File file : listFiles)
            file.delete();
          final List<String> imageFilesPaths=new ArrayList<String>();
          getPicturesPaths(picFolder.getAbsolutePath(),imageFilesPaths);
          final JniBitmapHolder bitmapHolder=new JniBitmapHolder();
          int i=0;
          final Options options=new Options();
          for(final String filePath : imageFilesPaths)
            {
            options.inJustDecodeBounds=true;
            options.inPreferredConfig=Config.ARGB_8888;
            prepareForDownsampling(options,screenWidth,screenHeight);
            Bitmap b=BitmapFactory.decodeFile(filePath,options);
            bitmapHolder.storeBitmap(b);
            b.recycle();
            switch(i++%3)
              {
              case 0:
                bitmapHolder.rotateBitmapCw90();
                break;
              case 1:
                bitmapHolder.rotateBitmap180();
                break;
              case 2:
                bitmapHolder.rotateBitmapCcw90();
                break;
              }
            b=bitmapHolder.getBitmapAndFree();
            final File imageFile=new File(outputDir.getAbsoluteFile()+File.separator+System.currentTimeMillis()+".jpg");
            imageFile.getParentFile().mkdirs();
            FileOutputStream stream=null;
            try
              {
              stream=new FileOutputStream(imageFile);
              b.compress(CompressFormat.JPEG,80,stream);
              stream.flush();
              stream.close();
              }
            catch(final Exception e)
              {
              e.printStackTrace();
              }
            finally
              {
              if(stream!=null)
                try
                  {
                  stream.close();
                  }
                catch(final IOException e)
                  {
                  e.printStackTrace();
                  }
              }
            }
          return null;
          }

        @Override
        protected void onPostExecute(final Void result)
          {
          super.onPostExecute(result);
          progressDialog.dismiss();
          finish();
          }
      }.execute();
    }

  private static void prepareForDownsampling(final Options bitmapOptions,final int reqWidth,final int reqHeight)
    {
    final int inSampleSize=calculateInSampleSize(bitmapOptions,reqWidth,reqHeight);
    // as much as possible, use google's way to downsample:
    bitmapOptions.inSampleSize=1;
    bitmapOptions.inDensity=1;
    bitmapOptions.inTargetDensity=1;
    bitmapOptions.inJustDecodeBounds=false;
    while(bitmapOptions.inSampleSize*2<=inSampleSize)
      bitmapOptions.inSampleSize*=2;
    // if google's way to downsample isn't enough, do some more :
    if(bitmapOptions.inSampleSize!=inSampleSize)
      {
      // downsample by bitmapOptions.inSampleSize/originalSampleSize .
      bitmapOptions.inTargetDensity=bitmapOptions.inSampleSize;
      bitmapOptions.inDensity=inSampleSize;
      }
    }

  public static int calculateInSampleSize(final BitmapFactory.Options options,final int reqWidth,final int reqHeight)
    {
    final int height=options.outHeight;
    final int width=options.outWidth;
    int inSampleSize=1;
    if(height>reqHeight||width>reqWidth)
      {
      final int heightRatio=Math.round((float)height/(float)reqHeight);
      final int widthRatio=Math.round((float)width/(float)reqWidth);
      inSampleSize=heightRatio<widthRatio ? heightRatio : widthRatio;
      }
    return Math.max(inSampleSize,1);
    }

  private static void getPicturesPaths(final String path,final List<String> filesPaths)
    {
    final Options options=new Options();
    options.inJustDecodeBounds=true;
    File f=new File(path);
    if(f.isFile())
      {
      BitmapFactory.decodeFile(path,options);
      if(options.outHeight>=0&&options.outWidth>=0)
        filesPaths.add(path);
      return;
      }
    if(!f.isDirectory())
      return;
    final String[] childrenPaths=f.list();
    for(final String fileName : childrenPaths)
      {
      if(fileName.startsWith("."))
        continue;
      f=new File(path+File.separator+fileName);
      final String fullFilePath=f.getAbsolutePath();
      if(f.isFile())
        {
        BitmapFactory.decodeFile(fullFilePath,options);
        if(options.outHeight>=0&&options.outWidth>=0)
          filesPaths.add(fullFilePath);
        continue;
        }
      getPicturesPaths(fullFilePath,filesPaths);
      }
    }
  }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top