捕获图像时TextView阴影被破坏

时间:2016-08-30 12:19:31

标签: android textview shadow

在捕获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();

屏幕上的原始图像

enter image description here

捕获的图像

enter image description here

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

11 个答案:

答案 0 :(得分:3)

两张图像之间的区别在于原始图像是使用LAYER_TYPE_HARDWARE图层生成的。使用此图层类型在文本上设置阴影图层时,图形处理器会在纹理上创建模糊。

有关详细信息,请参阅View layers上的这篇文章。

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

你可以尝试一下。添加代码以强制进行软件渲染:

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重写应用程序才能访问底层图形缓冲区。

答案 1 :(得分:1)

创建位图后调用此

tv.setDrawingCacheEnabled(false);

之后

bitmap = tv.getDrawingCache();

答案 2 :(得分:1)

尝试使用此代码保存实际显示在屏幕上的内容。

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();
            }

我已成功通过测试。

答案 3 :(得分:0)

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

View screen = getWindow().getDecorView().getRootView();
screen.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(screen.getDrawingCache());
screen.setDrawingCacheEnabled(false);

答案 4 :(得分:0)

  1. 启用Android硬件加速(通过添加到清单android:hardwareAccelerated="true"
  2. 将视图设置为图层类型LAYER_TYPE_SOFTWARE view.setLayerType(View.LAYER_TYPE_SOFTWARE,null)
  3. 尝试这两件事。

答案 5 :(得分:0)

试试这个,

公共类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>
*/

}

答案 6 :(得分:0)

我就是这样做的,但你需要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来获取屏幕截图,但它需要root。 Google创建了一个无需root权限的截图,因此,您可以使用it

答案 7 :(得分:0)

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

position: relative;
top: 50%;
transform: translateY(-50%);

答案 8 :(得分:0)

This (long) answer addresses the problems with hardware rendering and capture &#34;请记住,Android上的图形是在GPU上合成的。因此,没有理由为什么CPU应该能够访问完整合成的屏幕图像的副本,而且通常不会。&#34;所以我们不得不求助于屏幕截图代码。 此问题如下所示:

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();

&#34;如果您已获得root权限,则根据定义,您拥有所有Android权限,因此可以调用captureScreen API来获取正确的图片。&#34;

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

方便提示:
安卓4.0及#34;冰淇淋三明治&#34;几乎所有手机都通过&#34;电源关闭+音量降低&#34;按钮压在一起。

答案 9 :(得分:0)

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

答案 10 :(得分:0)

如果我们向画布提供Bitmap,则假设硬件缓冲区使用。

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

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