android - Ombre di TextView distrutte durante l'acquisizione dell'immagine




shadow (8)

L'ombra viene distrutta mentre cattura l'immagine di textview.

Ho aggiunto l'ombra del testo a livello di codice usando setShadowLayer.

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

quando acquisisco l'immagine usando

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

e ottenere bitmap usando

bitmap = tv.getDrawingCache();

Immagine originale sullo schermo

Immagine catturata

Ho anche provato ad acquisire il layout principale ma lo stesso risultato.


  1. Attiva le accelerazioni Android HW (aggiungendo al manifest android:hardwareAccelerated="true" )
  2. Impostare una vista sul tipo di layer LAYER_TYPE_SOFTWARE view.setLayerType(View.LAYER_TYPE_SOFTWARE,null) .

Prova con queste due cose.


Cattura lo schermo in bitmap e quindi salvalo.

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

La differenza tra le due immagini è che l'immagine originale viene prodotta utilizzando un layer LAYER_TYPE_HARDWARE . Quando si imposta un livello di ombreggiatura sul testo utilizzando questo tipo di livello, la sfocatura viene creata dal processore grafico su una trama.

Vedi questo articolo su Visualizza livelli per i dettagli.

L'immagine acquisita invece viene creata mediante il rendering in una bitmap, che è essenzialmente uguale all'utilizzo di LAYER_TYPE_SOFTWARE . Poiché la sfocatura non viene più creata dal processore grafico, non vi è alcuna garanzia che sembrerà la stessa.

Puoi sperimentare con esso. Aggiungi codice per forzare il rendering del software:

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

Dopo averlo fatto, le due immagini avranno lo stesso aspetto.

Se desideri che entrambe le immagini assomiglino più all'immagine originale con sfocatura dell'hardware, puoi regolare il raggio di sfocatura:

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

Se vuoi ottenere risultati esattamente come l'originale, catturando una bitmap dell'immagine resa hardware, deve essere possibile ma non conosco un modo semplice. Potrebbe essere necessario riscrivere l'app utilizzando OpenGL per ottenere l'accesso ai buffer grafici sottostanti.


Prova questo,

la classe pubblica MainActivity estende 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>
*/

}


Supponendo che il buffer hardware usi se forniamo un Bitmap al canvas.

1) Sovrascrivi Textview e crea la tua CustomTextview personalizzata 2) Sostituisci onMeasure e memorizza larghezza e altezza di Textview. 3) crea una Bitmap della dimensione di Textview che puoi ottenere Larghezza e altezza da OnMeasure. 4) sovrascrive il onDraw (canvas) - canvas.setBitmap (bitmap) e chiama super.ondraw ()

i dati sono scritti sulla tua Bitmap, controlla il contenuto


prova questo codice salva ciò che effettivamente appare sullo schermo.

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

Ho provato con successo.


Questa (lunga) risposta risolve i problemi con il rendering e l'acquisizione dell'hardware "Ricorda su Android che la grafica è composta sulla GPU, quindi non c'è motivo per cui la CPU debba avere accesso a una copia dell'immagine a schermo composita completa, e spesso non funziona 't ". Quindi dobbiamo ricorrere al codice di cattura dello schermo. Questo problema è mostrato qui:

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

view.draw deve utilizzare View.LAYER_TYPE_SOFTWARE , quindi non funzionerà.

Un tentativo migliore è questo (ma non funziona come gli altri):

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

"Se hai root, per definizione hai tutte le autorizzazioni Android e puoi quindi chiamare l'API captureScreen per ottenere un'immagine corretta."

Una delle nuove API introdotte in Android 5.0 è l'API MediaProjection . Secondo la documentazione ufficiale questa API ci dà la possibilità di catturare il contenuto dello schermo (senza root).

Suggerimento pratico:
Dopo Android 4.0 "Ice Cream Sandwich" quasi tutti i telefoni hanno la cattura dello schermo tramite il pulsante "spegnimento + volume giù" premuto insieme.


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




shadow