0

I need to load image from file to ImageView draw something on it and save to the same file. All of mine modifications are drawn in separate view called mCanvasView. Here is my saving code:

    private void saveResult() {
    OutputStream stream = null;
    try {
        Bitmap result;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inMutable = true;
            result = BitmapFactory.decodeFile(mFilePath, options);
        } else {
            Bitmap bitmap = BitmapFactory.decodeFile(mFilePath);
            result = bitmap.copy(Bitmap.Config.ARGB_8888, true);
            bitmap.recycle();
        }
        float resultWidth = result.getWidth();
        float resultHeight = result.getHeight();
        Canvas canvas = new Canvas(result);
        Bitmap overlay = mCanvasView.getDrawingCache();
        Matrix matrix = new Matrix();
        matrix.setScale(resultWidth / overlay.getWidth(), resultHeight
                / overlay.getHeight());
        canvas.drawBitmap(overlay, matrix, new Paint());
        stream = new FileOutputStream(mFilePath);
        result.compress(CompressFormat.PNG, 100, stream);
    } catch (Exception e) {
        e.printStackTrace();
        leaveActivityWithMissingData();
    } finally {
        IOUtils.closeQuietly(stream);
    }
}

First of all - it's really slow. I don't understand why. Secondly, if image shot in portrait mode then saved image will be rotated. Why? I don't apply any rotation.

I've modified my code like this to use rotation data from EXIF:

    OutputStream stream = null;
    try {
        Bitmap original;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inMutable = true;
            original = BitmapFactory.decodeFile(mFilePath, options);
        } else {
            Bitmap bitmap = BitmapFactory.decodeFile(mFilePath);
            original = bitmap.copy(Bitmap.Config.ARGB_8888, true);
            bitmap.recycle();
        }
        int resultWidth = original.getWidth();
        int resultHeight = original.getHeight();
        int rotation = Utils.getRotation(mFilePath);
        if (rotation % 180 != 0) {
            resultHeight = original.getWidth();
            resultWidth = original.getHeight();
        }
        Bitmap result = Bitmap.createBitmap(resultWidth, resultHeight,
                Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        Matrix rotationMatrix = new Matrix();
        rotationMatrix.setRotate(rotation, resultWidth / 2,
                resultHeight / 2);
        canvas.drawBitmap(original, rotationMatrix, new Paint());
        original.recycle();
        Bitmap overlay = mCanvasView.getDrawingCache();
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(resultWidth / overlay.getWidth(), resultHeight
                / overlay.getHeight());
        canvas.drawBitmap(overlay, scaleMatrix, new Paint());
        overlay.recycle();

        stream = new FileOutputStream(mFilePath);
        result.compress(CompressFormat.PNG, 100, stream);
        result.recycle();
    } catch (Exception e) {
        e.printStackTrace();
        leaveActivityWithMissingData();
    } finally {
        IOUtils.closeQuietly(stream);
    }

But this leads to OOM on every call. What am I doing wrong?

Lingviston
  • 5,479
  • 5
  • 35
  • 67
  • check this out for the orientation of the photo http://stackoverflow.com/questions/16949001/photo-picker-portrait-turns-to-landscape/16949619#16949619 – JRowan Nov 01 '13 at 18:13
  • No real comment on performance, but you may want to check http://stackoverflow.com/questions/4374141 – kiruwka Nov 01 '13 at 18:20

1 Answers1

0

Check this may help to understand performance problem.
Also, don't forget to close your stream after finished compressing.

As for rotation - may be your camera sets original preview mode with setDisplayOrientation(90) or similar ? Then you could always rotate to match image to preview by applying matrix.postRotate(90);

Community
  • 1
  • 1
kiruwka
  • 9,250
  • 4
  • 30
  • 41
  • I'm using default camera via intent. – Lingviston Nov 01 '13 at 18:28
  • @Lingviston This http://stackoverflow.com/questions/14066038 explains how to get info about occurred rotation, using this info you can then rotate your image appropriately – kiruwka Nov 01 '13 at 18:51
  • It looks like all this transformations are rather memory comsuming opertaion. I can't understand they make such a simple operation so difficult. There is no way to "draw" my overlay directly to file with initial image? – Lingviston Nov 01 '13 at 18:54
  • First, are you sure that your file with initial image contains properly oriented image ? Secondly, I would recommend capturing the bitmap, rotating it if needed according to the link above, applying your overlay and then saving it to file – kiruwka Nov 01 '13 at 19:01
  • Capturing and editing are separate actions. They are done via different parts of app. – Lingviston Nov 01 '13 at 19:42
  • @Lingviston Anyway, does orientation of your saved image matches your preview (or your expectations) ? – kiruwka Nov 01 '13 at 19:46
  • before aditing if firstly load image to ImageView (but using third-party library) and it has the same orientation I've captured it. – Lingviston Nov 01 '13 at 21:39