使用 Glide 缩放和蒙版
Zoom and Mask using Glide
我只是想看看是否有人能为我指明正确的方向,让我学习如何使用 Glide 完成此任务...
我们有一个包含内容的页面。
内容显示为单个图像(想想:杂志页面的图像)
在易读模式下,我想居中缩放第一块
文本内容并屏蔽其余部分
点击'next'时,我想移动到下一个文本块
内容、居中和重新缩放
点击'back'时,我想移动到上一个文本块
内容、居中和重新缩放
遮罩始终为矩形,但大小会不断变化以适应内容
我在下面放了几张简单的图片来说明我的意思。我们目前正在使用我们定位的图像视图和 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(horizontalSize, 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>
-结果:
我只是想看看是否有人能为我指明正确的方向,让我学习如何使用 Glide 完成此任务...
我们有一个包含内容的页面。
内容显示为单个图像(想想:杂志页面的图像)
在易读模式下,我想居中缩放第一块 文本内容并屏蔽其余部分
点击'next'时,我想移动到下一个文本块 内容、居中和重新缩放
点击'back'时,我想移动到上一个文本块 内容、居中和重新缩放
遮罩始终为矩形,但大小会不断变化以适应内容
我在下面放了几张简单的图片来说明我的意思。我们目前正在使用我们定位的图像视图和 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(horizontalSize, 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>
-结果: