使用Glide实现Zoom和Mask

6
我只是想看看是否有人能指导我如何使用Glide来实现以下内容...

  • 我们有一个包含内容的页面。

  • 内容显示为单个图像(类似于杂志页的图像)。

  • 在简易阅读模式下,我希望将焦点放在第一块文本内容上并遮盖其余部分。

  • 当点击“下一页”时,我希望移动到下一块文本内容,重新聚焦和缩放。

  • 当点击“返回”时,我希望移动到上一块文本内容,重新聚焦和缩放。

  • 遮罩始终为矩形,但大小会不断变化以适应内容。

我已经放置了几张简单的图片以展示我的意思。我们目前使用ImageView和4个黑色视图来完成此操作,但它非常卡顿且容易出现错位。我们可以在Glide中完成这个吗?

谢谢大家!

"Full Page" View "Easy Reading" View


1
你说:“内容显示为单个图像,您想在每个文本内容块上居中和缩放”,但是您如何定位图像内的文本内容块? - Brainnovo
3个回答

6
Zoom和Mask功能可以通过两种方式实现。使用Glide进行图像遮罩,使用PhotoView进行缩放。但是,由于您提到需要自动缩放文本内容,所以这个方法比较复杂。
Glide提供了一项功能,可以自动限制它在缓存和内存中保存的图像大小与ImageView的尺寸相匹配,例如如果图像不应该自动适应ImageView,请调用override(horizontalSize, verticalSize)。这将在显示图像之前调整图像大小以适合ImageView。
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()函数提供一个特定的大小。从这里查看Glide的其他功能。

对于缩放和缩小甚至是最适合在你的方案(杂志页面)中工作的情况,请使用PhotoView。可以通过将photoview实例作为参数传递给glide .into()函数来实现。

还可以检查这个示例


这只是将图像调整大小以居中和放大,但如何从Glide实现蒙版和文本识别呢? - Sachin Kasaraddi
文本识别并不是问题。页面数据包含每个单独部分的坐标。我需要裁剪坐标之外的所有内容,并放大其中的内容。 - Psest328
@aliazazalam,我该如何使用Glide进行裁剪和缩放,而不是仅调整大小? - Psest328
2
这两个过程都可以通过不同的库来实现,就像我在帖子中提到的链接一样,例如你可以使用PhotoView来进行缩放,但它只提供了捏合缩放功能,而对于裁剪,则可以使用Glide的裁剪函数。 - Ali Azaz Alam

3
使用文本识别API Mobile Vision 来检测图像中的文本,其结果为文本结构。从中您可以推导出:
  • 是一组连续的文本行,例如段落
  • 行是同一垂直轴上的一组连续单词,以及
  • 单词是同一垂直轴上的一组连续字母数字字符。

居中并放大第一个文本内容块,并使用边界框遮蔽其余部分。

您可以参考这个示例


文本识别并不是问题。页面数据包含每个单独部分的坐标。我需要裁剪坐标之外的所有内容,并放大其中的内容。 - Psest328

1
你可以尝试以下方法:
为了模拟您的情况,我需要创建一个带有预定义坐标和尺寸的文本块图像,因此我执行了以下操作:
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) 创建了以下活动:

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)在真实设备上构建项目,运行活动,获取每个文本块的坐标和尺寸,并对屏幕截图。

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

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

屏幕截图:

screenshot

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>

-结果:

result


1
这太棒了。不幸的是,它不适用于这个特定的用例,但我可以看到将来会使用它。我希望我能做更多的事情,而不仅仅是点赞,但Ali的帮助得到了认可。 - Psest328

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接