使用 Glide 缩放和蒙版

Zoom and Mask using Glide

我只是想看看是否有人能为我指明正确的方向,让我学习如何使用 Glide 完成此任务...

我在下面放了几张简单的图片来说明我的意思。我们目前正在使用我们定位的图像视图和 4 个黑色视图来执行此操作,但它非常笨拙并且容易出现错位。我们可以在 Glide 中完成这个吗?

谢谢大家!

使用文字识别APIMobile Vision to detect text in image and it results in Text structure。从中你可以得出

  • 是一组连续的文本行,例如段落
  • 行是同一垂直轴上的一组连续的单词, 和
  • Word 是一组连续的字母数字字符 垂直轴。

在第一个文本内容块上居中并缩放,并使用 Bounding box

遮盖其余部分

可以参考这个example

缩放和蒙版功能可以通过两种方式实现。要屏蔽图像,请使用 Glide and for zoom use PhotoView,但正如您提到的,文本内容需要自动缩放,然后使用您所遵循的方法会很复杂。

Glide 为您提供了一项功能,您可以自动将其保存在缓存和内存中的图像大小限制为 ImageView 尺寸,如果图像不应自动适合 ImageView,请调用 override(horizo​​ntalSize, verticalSize)。这将在图像视图中显示之前调整图像的大小。

GlideApp  
  .with(context)
  .load("Image resource")
  .override(600, 200) // resizes the image to these dimensions (in pixel). resize does not respect aspect ratio
  .into(imageView);

当您在没有已知尺寸的目标视图时加载图像时,此选项也可能有用。例如,如果应用想要在启动画面中预热缓存,它还不能测量 ImageViews。但是,如果您知道图像应该有多大,请使用 override() 来提供特定尺寸。从here

查看Glide的其他功能

使用 PhotoView 进行放大和缩小,甚至最适合在您的场景(杂志页面)中工作。可以通过将 photoview 实例作为参数传递给 glide .into() function

来实现

同时检查这个 example

您可以尝试以下方法:

为了模拟你的情况,我不得不创建一个带有文字的图像
坐标和尺寸是预定义的块,所以我做了以下操作:

1) 使用三个文本视图创建了一个简单的相对布局:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/rl"
android:background="@android:color/black"
android:layout_height="match_parent">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textAlignment="center"
    android:padding="40dp"
    android:layout_marginTop="50dp"
    android:layout_marginBottom="10dp"
    android:layout_alignParentEnd="true"
    android:layout_alignParentRight="true"
    android:text="Text Block 1"
    android:textSize="30sp"
    android:textColor="@android:color/white"
    android:id="@+id/tv1"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textAlignment="center"
    android:padding="40dp"
    android:layout_marginBottom="20dp"
    android:layout_alignParentStart="true"
    android:layout_alignParentLeft="true"
    android:layout_below="@id/tv1"
    android:text="Text Block 2"
    android:textSize="30sp"
    android:textColor="@android:color/white"
    android:id="@+id/tv2"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textAlignment="center"
    android:padding="40dp"
    android:layout_marginBottom="40dp"
    android:layout_alignParentEnd="true"
    android:layout_alignParentRight="true"
    android:layout_below="@id/tv2"
    android:text="Text Block 3"
    android:textSize="30sp"
    android:textColor="@android:color/white"
    android:id="@+id/tv3"/>

</RelativeLayout>

2) 创建了下面的 activity:

public class TextBlockActivity extends AppCompatActivity {

private final String TAG = TextBlockActivity.class.getSimpleName();
private RelativeLayout rl;
private Map<String, float[]> text_map = new HashMap<>();

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

    rl = (RelativeLayout) findViewById(R.id.rl);
    rl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            rl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            for (int i = 0; i < rl.getChildCount(); i++) {
                View child = rl.getChildAt(i);
                if (child instanceof TextView) {
                    TextView tv = (TextView) child;
                    float[] c = new float[]{tv.getX(), tv.getY(), tv.getWidth(), tv.getHeight()};
                    Log.i(TAG, (i + 1) + " x: " + c[0] + " y: " + c[1] + " w: " + c[2] + " h: " + c[3]);
                }
            }
        }
    });
}

}

3) 在真实设备上构建项目,运行 activity,获取每个文本块的坐标和尺寸并截取屏幕截图。

坐标和尺寸 (x,y,w,h):

  • 文本块 1:351、180、729、361
  • 文本块 2:0、541、729、361
  • 文本块 3:351、962、729、361

截图:

4) 有了坐标、尺寸和图像后,我执行了以下操作:

-MainActivity.class:

public class MainActivity extends AppCompatActivity {

private final String TAG = MainActivity.class.getSimpleName();
private ImageView iv;
private PhotoView pv_preview;
private LinearLayout ll;
private Button b_back;
private Button b_next;
private Map<String, float[]> text_blocks_coordinates_map = new HashMap<>();

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

    iv = (ImageView) findViewById(R.id.iv);
    pv_preview = (PhotoView) findViewById(R.id.pv_preview);
    ll = (LinearLayout) findViewById(R.id.ll);
    b_back = (Button) findViewById(R.id.b_back);
    b_back.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            if (pv_preview.getTag() != null) {

                float[] c_current = text_blocks_coordinates_map.get((String) pv_preview.getTag());

                if (c_current != null) {

                    TreeMap<Float, String> possible_targets_map = new TreeMap<>(); //Float y:coordinate, String key
                    for (Map.Entry<String, float[]> entry : text_blocks_coordinates_map.entrySet()) {
                        //do comparison based on the y coordinate only
                        //assuming that no two blocks of text will have the same y coordinate and different x coordinate (will be horizontally aligned)
                        if (entry.getValue()[1] < c_current[1]) {
                            possible_targets_map.put(entry.getValue()[1], entry.getKey());
                        }
                    }

                    //TreeMap will sort content according to their key values in decreasing order
                    // from the treeMap of possible targets, create a list containing the values of the treeMap above (which are the keys of text_blocks_coordinates_map)
                    List<String> possible_targets_list = new ArrayList<>();
                    for (Map.Entry<Float, String> entry : possible_targets_map.entrySet()) {
                        possible_targets_list.add(entry.getValue());
                    }

                    //take the last item in this possible_targets_list as key and get content from text_blocks_coordinates_map
                    if (!possible_targets_list.isEmpty()) {
                        changePreview(iv, possible_targets_list.get(possible_targets_list.size() - 1), text_blocks_coordinates_map.get(possible_targets_list.get(possible_targets_list.size() - 1)));
                    }
                }
            }
        }
    });
    b_next = (Button) findViewById(R.id.b_next);
    b_next.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            if (pv_preview.getTag() != null) {

                float[] c_current = text_blocks_coordinates_map.get((String) pv_preview.getTag());

                if (c_current != null) {

                    TreeMap<Float, String> possible_targets_map = new TreeMap<>();
                    for (Map.Entry<String, float[]> entry : text_blocks_coordinates_map.entrySet()) {
                        //do comparison based on the y coordinate only
                        //assuming that no two blocks of text will have the same y coordinate and different x coordinate (will be horizontally aligned)
                        if (entry.getValue()[1] > c_current[1]) {
                            possible_targets_map.put(entry.getValue()[1], entry.getKey());
                        }
                    }

                    //TreeMap will sort content according to their key values in decreasing order
                    // from the treeMap of possible targets, create a list containing the values of the treeMap above (which are the keys of text_blocks_coordinates_map)
                    List<String> possible_targets_list = new ArrayList<>();
                    for (Map.Entry<Float, String> entry : possible_targets_map.entrySet()) {
                        possible_targets_list.add(entry.getValue());
                    }

                    //take the first item in this possible_targets_list as key and get content from text_blocks_coordinates_map
                    if (!possible_targets_list.isEmpty()) {
                        changePreview(iv, possible_targets_list.get(0), text_blocks_coordinates_map.get(possible_targets_list.get(0)));
                    }
                }
            }
        }
    });

    //These are the coordinates of text blocks inside the image
    text_blocks_coordinates_map.put(String.valueOf(1), new float[]{351, 180, 729, 361});
    text_blocks_coordinates_map.put(String.valueOf(2), new float[]{0, 541, 729, 361});
    text_blocks_coordinates_map.put(String.valueOf(3), new float[]{351, 962, 729, 361});

    iv.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            Log.e(TAG, "Touching Image View");

            float x = motionEvent.getX();
            float y = motionEvent.getY();

            for (Map.Entry<String, float[]> entry : text_blocks_coordinates_map.entrySet()) {
                float[] c = entry.getValue();
                if (x > c[0] && x < (c[0] + c[2])
                        && y > c[1] && y < (c[1] + c[3])) {

                    changePreview(iv, entry.getKey(), entry.getValue());

                }
            }
            return false;
        }
    });
}

@Override
public void onBackPressed() {
    if (pv_preview.getVisibility() == View.VISIBLE) {
        iv.setVisibility(View.VISIBLE);
        ll.setVisibility(View.GONE);
        pv_preview.setVisibility(View.GONE);
    } else {
        super.onBackPressed();
    }
}

private void changePreview(ImageView iv, String k, float[] c) {

    //The only method that works efficiently,
    // but it is deprecated
    iv.setDrawingCacheEnabled(true);
    iv.buildDrawingCache();
    Bitmap bitmap = Bitmap.createBitmap(iv.getDrawingCache());
    iv.destroyDrawingCache();

    Bitmap resource = Bitmap.createBitmap(bitmap, Math.round(c[0]), Math.round(c[1]), Math.round(c[2]), Math.round(c[3]));
    pv_preview.setImageBitmap(resource);

    iv.setVisibility(View.GONE);
    ll.setVisibility(View.VISIBLE);
    pv_preview.setVisibility(View.VISIBLE);

    //set pv_preview tag as the key of text block content currently
    // previewed (will be used inside next and back)
    pv_preview.setTag(k);


}

}

-activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:background="@android:color/black"
android:layout_height="match_parent">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="20dp"
    android:id="@+id/ll"
    android:visibility="gone"
    android:weightSum="100">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/b_back"
        android:gravity="center"
        android:text="Back"
        android:layout_weight="50"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/b_next"
        android:gravity="center"
        android:text="Next"
        android:layout_weight="50"/>

</LinearLayout>

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/iv"
    tools:ignore="contentDescription"
    android:src="@drawable/image"/>

<com.github.chrisbanes.photoview.PhotoView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone"
    android:layout_below="@id/ll"
    android:id="@+id/pv_preview"/>

   </RelativeLayout>

-结果: