捕获图像时TextView阴影被破坏

在捕捉textview的图像时,阴影被破坏。

我使用setShadowLayer以编程方式添加了文本阴影。

tv.setShadowLayer(20, 0, 0, Color.BLACK); 

当我捕捉图像使用

 tv.buildDrawingCache(true); tv.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); tv.setDrawingCacheEnabled(true); 

并获取位图使用

 bitmap = tv.getDrawingCache(); 

屏幕上的原始图像

在这里输入图像说明

捕获的图像

在这里输入图像说明

还尝试捕获父级布局,但结果相同。

Solutions Collecting From Web of "捕获图像时TextView阴影被破坏"

两幅图像之间的区别在于原始图像是使用LAYER_TYPE_HARDWARE图层生成的。 当您使用此图层types在文字上设置阴影图层时,graphics处理器会在纹理上创build模糊。

有关详细信息,请参阅关于查看图层的文章

另一方面,捕获的图像是通过渲染成位图来创build的,这与使用LAYER_TYPE_SOFTWARE基本相同。 由于模糊不再由graphics处理器创build,因此不能保证它看起来相同。

你可以尝试一下。 添加代码来强制软件呈现:

 tv.setLayerType(View.LAYER_TYPE_SOFTWARE, null); tv.setShadowLayer(20, 0, 0, Color.BLACK); 

这样做后,这两个图像看起来是一样的。

如果您希望两幅图像看起来更像是硬件模糊的原始图像,则可以调整模糊半径:

 tv.setLayerType(View.LAYER_TYPE_SOFTWARE, null); tv.setShadowLayer(8, 0, 0, Color.BLACK); 

如果你想得到完全像原始的结果,通过捕获硬件渲染图像的位图,这一定是可能的,但我不知道一个简单的方法。 您可能必须使用OpenGL重写应用程序才能访问底层graphics缓冲区。

创build位图后调用这个

 tv.setDrawingCacheEnabled(false); 

在这之后

 bitmap = tv.getDrawingCache(); 

试试这个代码保存实际出现在屏幕上的内容。

 Bitmap bitmap = Bitmap.createBitmap(textView.getWidth(), textView.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); textView.draw(canvas); FileOutputStream var5; try { var5 = new FileOutputStream(new File(Environment.getExternalStorageDirectory(),"temp.png")); bitmap.compress(CompressFormat.PNG, 100, var5); var5.flush(); var5.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } 

我已经成功testing。

捕获屏幕位图,然后保存。

 View screen = getWindow().getDecorView().getRootView(); screen.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(screen.getDrawingCache()); screen.setDrawingCacheEnabled(false); 
  1. 打开Android硬件加速(通过添加到清单android:hardwareAccelerated="true"
  2. 将视图设置为层typesLAYER_TYPE_SOFTWARE view.setLayerType(View.LAYER_TYPE_SOFTWARE,null)

试试这两件事。

尝试这个,

公共类MainActivity扩展AppCompatActivity {

 private TextView textView; private ImageView image; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Your text view textView = (TextView) findViewById(R.id.hello); textView.setShadowLayer(20, 0, 0, Color.BLACK); //Get bitmap from textView Bitmap customViewBitmap = createDrawableFromView(this, textView); //Set the bitmap to imageView image = (ImageView) findViewById(R.id.image); image.setImageBitmap(customViewBitmap); } public static Bitmap createDrawableFromView(Context context, View view) { DisplayMetrics displayMetrics = new DisplayMetrics(); ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); view.measure(displayMetrics.widthPixels, displayMetrics.heightPixels); view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels); view.buildDrawingCache(); Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap; } /* 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:layout_width="match_parent" android:layout_height="match_parent" 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.pansapp.swipecard.MainActivity"> <TextView android:id="@+id/hello" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="Hello World!" android:textSize="18sp" /> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" /> </RelativeLayout> */ 

}

我就是这么做的,但是你需要root或者其他的截图来源。 这里是Java代码:

 private TextView mTextView; private ImageView mImageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.t); mTextView.setShadowLayer(20, 0, 0, Color.BLACK); mImageView = (ImageView) findViewById(R.id.imageView); } public void onClick(View v) { Bitmap bitmap = getViewBitmap(mTextView); if (bitmap != null) { mImageView.setImageBitmap(bitmap); } } private int getRelativeLeft(View myView) { if (myView.getParent() == myView.getRootView()) return myView.getLeft(); else return myView.getLeft() + getRelativeLeft((View) myView.getParent()); } private int getRelativeTop(View myView) { if (myView.getParent() == myView.getRootView()) return myView.getTop(); else return myView.getTop() + getRelativeTop((View) myView.getParent()); } private Bitmap getViewBitmap(View view) { try { Process proc = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/screencap -p"}); BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream())); Bitmap bitmap = BitmapFactory.decodeStream(proc.getInputStream()); String s; while ((s = stdError.readLine()) != null) { Log.i("log", s); } if (bitmap != null) { DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); bitmap = Bitmap.createBitmap(bitmap, getRelativeLeft(view), getRelativeTop(view), view.getMeasuredWidth(), view.getMeasuredHeight()); } return bitmap; } catch (IOException e) { e.printStackTrace(); } return null; } 

我正在使用内部screencap截图获取屏幕截图,但它需要根。 Googlebuild立了一个没有root权限的截图库,所以你可以使用它 。

你可以用这种方式保存任何视图为图像

  try { Bitmap mNewSaving = getBitmap(tv); String save_file = new File(dir, "View_" + System.currentTimeMillis() + ".png"); FileOutputStream mFileOutputStream = new FileOutputStream(save_file); mNewSaving.compress(Bitmap.CompressFormat.PNG, 95, mFileOutputStream); mFileOutputStream.flush(); mFileOutputStream.close(); } catch (FileNotFoundException e) { Log.v("hetal", "FileNotFoundExceptionError " + e.toString()); } catch (IOException e) { Log.v("hetal", "IOExceptionError " + e.toString()); } 
 tv.buildDrawingCache(true); tv.setDrawingCacheQuality(View. DRAWING_CACHE_QUALITY_AUTO); tv.setDrawingCacheEnabled(true); 

假设硬件缓冲区使用,如果我们提供一个位图的canvas。

1)覆盖Textview并创build自己的CustomTextview 2)覆盖onMeasure并存储Textview的宽度和高度。 3)创build一个Textview大小的位图,你可以从onMeasure获得宽度和高度。 4)重写onDraw(canvas) – canvas.setBitmap(bitmap)并调用super.ondraw()

将数据写入您的位图,检查内容

这个(很长)的回答解决了硬件渲染和捕获问题 “在Android上记住graphics是在GPU上合成的,所以没有理由让CPU可以访问整个合成屏幕图像的副本,而且通常不会“T“。 所以我们不得不求助于屏幕截图代码。 这个问题在这里显示:

 Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); 

view.draw必须使用View.LAYER_TYPE_SOFTWARE ,所以不会工作。

更好的尝试是这样的(但不像其他人):

  DisplayMetrics displayMetrics = new DisplayMetrics(); ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); view.measure(displayMetrics.widthPixels, displayMetrics.heightPixels); view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels); // Enabling the drawing cache is similar to setting a layer when hardware acceleration is turned off. // When hardware acceleration is turned on, // enabling the drawing cache has no effect on rendering because the system // uses a different mechanism for acceleration which ignores the flag. view.buildDrawingCache(); Bitmap b1 = view.getDrawingCache();//note no canvas, or draw // copy this bitmap otherwise destroying the cache will destroy // the bitmap for the referencing drawable and you'll not // get the captured view Bitmap bitmap = b1.copy(Bitmap.Config.ARGB_8888, false); view.destroyDrawingCache(); 

“如果你有root权限,你就可以拥有所有的Android权限,因此可以调用captureScreen API来获取正确的图像。”

MediaProjection API是Android 5.0中引入的新API之一。 根据官方文档,这个API使我们能够捕获屏幕内容(没有根目录)。

方便的提示:
在Android 4.0“冰淇淋三明治”之后,几乎所有手机都通过“关机+音量降低”button将屏幕抓取在一起。