14

I need to show some Images inside the Frame (Multiple Image Frames), I have left and top coordinates correspondence to each Image.

For example, I have Image coordinates 100 from left and 100 from top, So what i need to do is just to show the image inside the ImageView which starts from (100,100).

Can anyone tell me how could i do that without Bitmap, because i need to show the list of Frames with Multiple Images inside RecyclerView.

I have used TouchImageView.class for Zoom and Move feature for creating the Frame.

1. Below screen shot while i am selecting layout, as you can clearly seen that both the images are quite close to each other. I mean that i am selecting half portion of each image.

enter image description here

2. Next is the Home screen at which i need to replot that image, I am having the left and top coordinate of both the images.But How can i plot that Image inside ImageView by some custom x and y.

enter image description here

Code snippet for populating image inside ImageView from left and top -

 img.setPadding((int) x, (int) y, 0, 0);

But still not working.

Please suggest me something, i have done google search but didn't got the appropriate solution for my requirement.

Suggestions really appreciated.

Many Thanks in advance.

Kind Regards.

Shoeb Siddique
  • 2,805
  • 1
  • 22
  • 42
  • Can you share some wireframe and code snippet? It is a bit hard to visualize what you are trying to achieve. – Hitesh Sahu Feb 21 '17 at 11:35
  • @HiteshSahu I have added more details. – Shoeb Siddique Feb 21 '17 at 12:32
  • You said that you don't want to use Bitmap, because you want to show the list of "frames" inside a RecyclerView. Why does that mean you can't use Bitmap? – DanielLaneDC Feb 21 '17 at 13:43
  • @DanielLaneDC Okay, now i am open to use Bitmap, my concern was only to maintain good performance of the app, but we have no other solutions then at the end we need to go with Bitmap. – Shoeb Siddique Feb 21 '17 at 18:15
  • I've read a few of the other answers and re-read your question. Do you just want to be able to decide where the image inside of an ImageView is drawn with respect to that ImageView? I.e., (-100, -100) would not draw the left-most and top-most 100 pixels and the rest of the image would be drawn with a 100 pixel emptiness along the bottom and the right? – DanielLaneDC Feb 25 '17 at 14:37
  • I just want to redraw the Image, whatever i have choose on the Frame screen. I need to redraw that image with exact same position. – Shoeb Siddique Feb 27 '17 at 05:11

5 Answers5

7

Update: I have added a sample app at the end of this post to illustrate this concept.

Second update: Added some code to to sample app to accommodate xy scaling

I have changed the sample app to include code that will fit the image, whether smaller or larger than the ImageView, to the view size while respecting the aspect ratio. This may not be exactly what you are looking for, but it should get you into the ballpark. This is sample code, so there are assuredly other things to accommodate in an actual application. For instance, xScale and yScale could go negative in extreme cases. I am not sure what happens if they do, but a crash is probably the result, so a bounds check is in order.


If I understand what you are trying to do, you want a fixed size ImageView to show different parts of a larger image by setting custom (x,y) coordinates of the image to sit at the (0,0) coordinate of the ImageView. This is basically a cropping of the image across the top and left edges.

There are probably many different ways to do this and which one works best for you will depend on your exact needs, but here is one way:

Use the following, or some variation, in your code:

float xOffset = -100;
float yOffset = -100;
ImageView imageView = (ImageView) findViewById(R.id.shiftedView);
Matrix matrix = new Matrix();

matrix.setTranslate(xOffset, yOffset);
imageView.setImageMatrix(matrix);

Set up your ImageView something like the following. The key here is android:scaleType="matrix"

<ImageView
    android:id="@+id/shiftedView"
    android:layout_width="200dp"
    android:layout_height="match_parent"
    android:background="#FF00CCCC"
    android:scaleType="matrix"
    android:src="@drawable/image" />

I hope this helps you.

Sample App

Here is a quick mock-up of this concept. This app is composed of the main activity and one layout. You will have to supply an image that is the source for the ImageView to see how this works.

The seven buttons will shift the image left, right, up and down on a click within the layout of the ImageView. The "Fit X" and "Fit Y" buttons will scale the image to the corresponding dimension available within the ImageView. The "Reset" button will set the image back to the original default setting of the ImageView.

MainActivity.java

package com.example.imageshift;

import android.graphics.Matrix;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    ImageView imageView;
    float xOffset = 0f;
    float yOffset = 0f;
    float xScale = 1.0f;
    float yScale = 1.0f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ImageView) findViewById(R.id.shiftedView);
        findViewById(R.id.shiftUp).setOnClickListener(this);
        findViewById(R.id.shiftDown).setOnClickListener(this);
        findViewById(R.id.shiftLeft).setOnClickListener(this);
        findViewById(R.id.shiftRight).setOnClickListener(this);
        findViewById(R.id.shiftReset).setOnClickListener(this);
        findViewById(R.id.fitX).setOnClickListener(this);
        findViewById(R.id.fitY).setOnClickListener(this);
    }

    public void doMatrixTransformations() {
        Matrix matrix = new Matrix();

        matrix.setTranslate(xOffset, yOffset);
        matrix.postScale(xScale, yScale);
        imageView.setImageMatrix(matrix);
    }

    @Override
    public void onClick(View view) {
        final int shiftAmount = 50;

        switch (view.getId()) {
            case R.id.shiftUp:
                yOffset -= shiftAmount;
                break;
            case R.id.shiftDown:
                yOffset += shiftAmount;
                break;

            case R.id.shiftLeft:
                xOffset -= shiftAmount;
                break;

            case R.id.shiftRight:
                xOffset += shiftAmount;
                break;

            case R.id.fitX:
                xScale = (float) imageView.getWidth() / (
                        (float) imageView.getDrawable().getIntrinsicWidth() + xOffset);
                yScale = xScale;
                break;

            case R.id.fitY:
                yScale = (float) imageView.getHeight() /
                        ((float) imageView.getDrawable().getIntrinsicHeight() + yOffset);
                xScale = yScale;
                break;

            case R.id.shiftReset:
                xOffset = 0;
                yOffset = 0;
                xScale = 1.0f;
                yScale = 1.0f;
                break;
        }
        doMatrixTransformations();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.imageshift.MainActivity">

    <ImageView
        android:id="@+id/shiftedView"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:padding="2dp"
        android:scaleType="matrix"
        android:src="@drawable/image" />

    <Button
        android:id="@+id/shiftUp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Up" />

    <Button
        android:id="@+id/shiftDown"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/shiftUp"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Down" />

    <Button
        android:id="@+id/shiftLeft"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/shiftDown"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Left" />

    <Button
        android:id="@+id/shiftRight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/shiftLeft"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Right" />

    <Button
        android:id="@+id/fitX"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/shiftRight"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Fit X" />

    <Button
        android:id="@+id/fitY"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/fitX"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Fit Y" />

    <Button
        android:id="@+id/shiftReset"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/fitY"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@id/shiftedView"
        android:text="Reset" />

</RelativeLayout>
Cheticamp
  • 61,413
  • 10
  • 78
  • 131
  • This technique works in a quick mock up of mine. If my understanding of what you are trying is correct, maybe you can share your relevant code. – Cheticamp Feb 22 '17 at 11:31
  • Your demo looks really good, i have tried your demo. The only issue i got is the Scaling of Image is not correct, i need to set the image as on full ImageView and then i need to translate the image. – Shoeb Siddique Feb 24 '17 at 05:35
  • So the whole image has to fit inside one `ImageView`? If that is the case, what happens to the image when it is shifted? Does it have to expand to continue to fill the entire `ImageView` or does something else happen? I am unclear on this point. – Cheticamp Feb 24 '17 at 13:56
  • Yes, it needs to set as background Image, few portion of Image may be hidden towards left of right or top or bottom. – Shoeb Siddique Feb 24 '17 at 14:19
  • I am still unclear. I think your original posting is confusing me. An new example of what you would like to see with the sample app may be useful. – Cheticamp Feb 24 '17 at 14:34
  • I have posted 2 screen shots in my Post, please see that screen shots. – Shoeb Siddique Feb 24 '17 at 14:51
  • Hello, i am pretty confident with your solution, can you please tell me that why my Image height are getting reduced? – Shoeb Siddique Feb 27 '17 at 07:10
  • Where is you image height getting reduced? The posted short app doesn't reduce the image size at all. It just shifts the image frame around on the image if the image is larger than the `ImageView` frame; if the image is smaller than the `ImageView` then the image will fit entirely inside the view with some blank edges, so it will look shrunken. Is that the issue? Is your image smaller than the `ImageView`? Do you need the image to grow/shrink to fit the `ImageView` before shifting? – Cheticamp Feb 27 '17 at 13:56
  • I believe that the ImageView maintaining some aspect ratio. – Shoeb Siddique Feb 28 '17 at 05:49
3

It sounds like you want to take two images and create a new image based on some combination of the two images.

There are lots of different ways to go about this. The most straightforward ways involve using Bitmaps. There's two main approaches I can see that are straightforward to accomplish this.

  1. Position your image views how you like within some common parent and create a bitmap of that parent to use as your resulting image.

  2. Create a bitmap yourself by drawing the images of your imageviews based on your own calculations that should mimic the layout structure you have.

Since you already seem to be showing the two images on the screen in the way you want the resulting image to look like, the first is going to be the most straightforward and won't require you to redo the calculations that your layouts and imageviews are already performing.

What we're going to do is take advantage of the fact that every view will draw itself onto a canvas and at the end of the day is just translating itself into an image itself. To get a bitmap of your parent layout you can simply create a bitmap of the same size and then tell your parent layout to draw itself onto a canvas of the bitmap, like so:

private Bitmap getCombinedBitmap(View parentView) {
    Bitmap result = Bitmap.createBitmap(parentView.getWidth(), parentView.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(result);
    parentView.draw(canvas);

    return result;
}

If however you would like to not be bound by just whatever the parent layout is drawing to the screen, you can create the bitmap you want by drawing your images onto a similar canvas. Here I have implemented the first layout from your question:

private Bitmap getCombinedBitmap(Bitmap a, Bitmap b) {
    int aWidth = a.getWidth() / 2;
    int bWidth = b.getWidth() / 2;
    int resultHeight = a.getHeight() < b.getHeight()?  a.getHeight() : b.getHeight();
    Bitmap result = new Bitmap(aWidth + bWidth, resultHeight, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(result);

    Rect aRect = new Rect(0, 0, aWidth, resultHeight);
    Rect aResultRect = new Rect(0, 0, aWidth, resultHeight);
    canvas.drawBitmap(a, aRect, aResultRect);

    Rect bRect = new Rect(0, 0, bWidth, resultHeight);
    Rect bResultRect = new Rect(bWidth, 0, bWidth, resultHeight);
    canvas.drawBitmap(b, bRect, bResultRect);

    return result;
}

In this example I opted for clearer code rather than more optimised code. You can optimise this by not creating as many Rects, etc and generally simplifying your calculations. But you can use this approach to recreate any of your layouts onto a single bitmap, you would just need to change the calculations.

What we are doing is first creating a bitmap that has a width of half the first image plus half the second image, and the height of the smallest of the two images. We then take a section of the first image that is the left most half width wise and as high as the result height wise and we draw that onto our result. We then do the same with the second image except this time the section is the right most half width wise.

Hope this helps.

DanielLaneDC
  • 1,731
  • 11
  • 9
  • Thanks for the details description, but i am not combining bitmaps. – Shoeb Siddique Feb 22 '17 at 05:13
  • ImageViews can be converted to Bitmaps by using the first method that I described. Just use the ImageView instead of the parent ViewGroup. Also, the first method would work with ImageViews that are contained within a parent ViewGroup. – DanielLaneDC Feb 22 '17 at 06:58
3

I have to admit that I'm not 100% sure I understand what you want to do. If I understand correctly, what you need is to put an ImageView inside another element (I show an example with FrameLayout but you could use LinearLayout or RelativeLayout too). Then you set the padding on the outer element.

<!-- we put the ImageView inside a Frame so that we can change -->
<!--    the padding size to create borders -->
<FrameLayout
    android:layout_width="140dp"
    android:layout_height="140dp"
    android:id="@+id/image_frame"
    >
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/image_view"
        />
</FrameLayout>

Then in the code: (use frame instead of img)

FrameLayout frame = (FrameLayout)itemLayout.findViewById(R.id.image_frame);
frame.setPadding((int) x, (int) y, 0, 0);

If I understand what you want to do, this will do it.

Gary99
  • 1,750
  • 1
  • 19
  • 33
  • I need to set the position of Image inside the Imageview, your answer setting the position of ImageView not the image inside it. – Shoeb Siddique Feb 23 '17 at 06:56
  • Did you try what I have? Did you replace your current `ImageView` with the `FrameLayout` I have? Think of the `FrameLayout` the same as `ImageView` and the `ImageView` is a container inside it for the actual image, which can be moved anywhere. I think this will do what you need. – Gary99 Feb 23 '17 at 14:29
  • I need to move the container of ImageView not the FrameLayout. – Shoeb Siddique Feb 23 '17 at 14:36
  • Did you try what I have? – Gary99 Feb 23 '17 at 15:02
  • If you have and it doesn't do what you want, then I probably don't understand your problem. If you haven't tried it, you don't know it doesn't work. – Gary99 Feb 23 '17 at 15:09
3

You can do it easily by merging BitMaps.

I have created a test project which loads 2 image bitmaps with Glide and then merges them in one BitMap using canvas and then set it on any ImageView.

You can also save the image in a file on SD Card to avoid heavy calculation each time. It looks like this (Gif - https://github.com/hiteshsahu/Android-Merge-Bitmaps-With-Glide/blob/master/Art/demo.gif ):-

enter image description here

I have used a single Image view as the background of my Frame layout and I have used seek bar to change the relative position of the movie poster Raees. You can change start X and Y coordinates of either of the bitmaps using those seekbars.

How I did it:-

This is the code snippet of how I did it. It is self-explanatory

 Glide.with(context)
                .load(R.drawable.raees)
                .asBitmap()
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {

                        // Add Bitmap in Array and load next bitmap
                        arts[0] = resource;

                        Glide.with(context)
                                .load(R.drawable.raees_edited)
                                .asBitmap()
                                .into(new SimpleTarget<Bitmap>() {
                                    @Override
                                    public void onResourceReady(Bitmap resource1, GlideAnimation<? super Bitmap> glideAnimation) {

                                        // Both Bitmap loaded do the Merging
                                        arts[1] = resource1;

                                        //Set seekbars Max
                                        satrtX1SeekBar.setMax(arts[0].getWidth());
                                        satrtX2SeekBar.setMax(arts[1].getWidth());
                                        satrtY1SeekBar.setMax(arts[0].getHeight());
                                        satrtY2SeekBar.setMax(arts[1].getHeight());

                                        Bitmap bmOverlay = Bitmap.createBitmap(arts[0].getWidth(), arts[0].getHeight(), Bitmap.Config.ARGB_8888);
                                        Canvas canvas = new Canvas(bmOverlay);

                                        if (shouldDrawLeftHalf) {
                                            // Rect(left, top, right, bottom)
                                            canvas.drawBitmap(arts[0],
                                                    new Rect(0, 0, arts[0].getWidth() / 2, arts[0].getHeight()),
                                                    new Rect(0, 0, arts[0].getWidth() / 2, arts[0].getHeight()), null);

                                        } else {
                                            canvas.drawBitmap(arts[0], startX1, startY1, null);
                                        }

                                        if (shouldDrawRightHalf) {
                                            // Rect(left, top, right, bottom)
                                            canvas.drawBitmap(arts[1],
                                                    new Rect(arts[1].getWidth() / 2, 0, arts[0].getWidth(), arts[1].getHeight()),
                                                    new Rect(arts[1].getWidth() / 2, 0, arts[1].getWidth(), arts[1].getHeight()), null);
                                        } else {
                                            canvas.drawBitmap(arts[1], startX2, startY2, null);
                                        }


                                        background.setImageBitmap(bmOverlay);

                                        // saveToDisk("Test", bmOverlay);
                                    }
                                });
                    }
                });

You can download entire project from My GitHub

https://github.com/hiteshsahu/Android-Merge-Bitmaps-With-Glide

Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
1

Eventually i have found the solution of my question -

Thanks for all the help provided.

So, basically i have view height, view width, top coordinate, left coordinate, Original Image Height and Original Image Width.

  1. I need to calculate the aspect factor regarding View and Image.

Here is the formula for that -

 float newAspectFactor = 0;


 if (viewHeight > viewWidth) {
 //Aspect factor for Height
 newAspectFactor = viewHeight / bean.getPostMedia().get(i).getImg_height();

 } else {
 //Aspect factor for Width
 newAspectFactor = viewWidth / bean.getPostMedia().get(i).getImg_width();
 }

 float imgNewHeight = newAspectFactor * imageHeight;
 float imgNewWidth = newAspectFactor * imageWidth;
 Logger.logsError(TAG, " Image New Height : " + imgNewHeight);
 Logger.logsError(TAG, " Image New Width : " + imgNewWidth);

 if (imgNewHeight < viewHeight) {
 newAspectFactor = viewHeight / bean.getPostMedia().get(i).getImg_height();
 } else if (imgNewWidth < viewWidth) {
 newAspectFactor = viewWidth / bean.getPostMedia().get(i).getImg_width();
 }
  1. Top and Left coordinates.

                float x = 42.0;
                float y = 0.0;
    
  2. Magic starts from here.

                Matrix m = img.getImageMatrix();
                RectF drawableRect = new RectF(x,
                        y,
                        ((x * newAspectFactor) + viewWidth) / newAspectFactor,
                        imageHeight);
                RectF viewRect = new RectF(0,
                        0,
                        viewWidth,
                        viewHeight);
                m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL);
                img.setImageMatrix(m);
                img.setScaleType(ImageView.ScaleType.MATRIX);
                imageLoaderNew.displayImage("IMAGE URL", img, optionsPostImg);
    
Shoeb Siddique
  • 2,805
  • 1
  • 22
  • 42
  • Could you show us screen shots? I'm curious what you're doing. Maybe show screen shot with top, left at (0,0) and another at (100,100). – Gary99 Feb 28 '17 at 14:10