Pytanie Cień TextView został zniszczony podczas przechwytywania obrazu


Shadow zostaje zniszczony podczas przechwytywania obrazu z widoku tekstowego.

Dodałem cień tekstowy programowo za pomocą metody setShadowLayer.

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

kiedy przechwytuję obraz za pomocą

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

i pobieranie bitmapy za pomocą

bitmap = tv.getDrawingCache();

Oryginalny obraz na ekranie

enter image description here

Przechwycony obraz

enter image description here

Próbowano również przechwytywać układ nadrzędny, ale ten sam wynik.


27
2017-08-30 12:19


pochodzenie


Może sprawdzić wyniki dzwoniąc tv.setDrawingCacheEnabled(true); przed tv.buildDrawingCache(true); - JiTHiN
@JiTHiN próbował, nie działa. - Rahul Mandaliya
Sprawdź to [Link]. Mam nadzieję, że to pomoże. [Połączyć]: stackoverflow.com/questions/23225515/... - Syed Daniyal Nasir
Sprawdź ten link. stackoverflow.com/questions/17531858/... - User007
Jest to jedna z metod uzyskania obrazu z widoku. Zastosuj tę metodę do widoku rodzica, aby wyświetlić obraz dzieci. - User007


Odpowiedzi:


Różnica między tymi dwoma obrazami polega na tym, że oryginalny obraz jest tworzony przy użyciu LAYER_TYPE_HARDWARE warstwa. Po ustawieniu warstwy cienia na tekście przy użyciu tego typu warstwy, rozmycie jest tworzone przez procesor graficzny na fakturze.

Zobacz ten artykuł na Zobacz warstwy dla szczegółów.

Przechwycony obraz z drugiej strony jest tworzony przez renderowanie do bitmapy, która jest zasadniczo taka sama jak użycie LAYER_TYPE_SOFTWARE. Ponieważ rozmycie nie jest już tworzone przez procesor graficzny, nie ma gwarancji, że będzie wyglądać tak samo.

Możesz eksperymentować z tym. Dodaj kod, aby wymusić renderowanie oprogramowania:

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

Po wykonaniu tego dwa obrazy będą wyglądały tak samo.

Jeśli chcesz, aby oba obrazy wyglądały bardziej jak oryginalny obraz z rozmyciem sprzętowym, możesz dostosować zasięg rozmycia:

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

Jeśli chcesz uzyskać wyniki dokładnie takie, jak oryginalne, przechwytując bitmapę obrazu renderowanego sprzętowo, musi być możliwe, ale nie znam łatwego sposobu. Może zajść konieczność przepisania aplikacji za pomocą OpenGL, aby uzyskać dostęp do bazowych buforów graficznych.


3
2017-09-10 01:54



tak, masz rację, ale gładkość nie jest zachowana jak obraz 1. Zaimplementowałem to, ale kiedy zwiększam rozmycie, staje się jak obraz 2 przed przechwytywaniem, a kiedy zapisuję obraz, jego wynik jest taki sam, ale nie zawiera gładkości cienia. - Rahul Mandaliya


Po utworzeniu bitmapy nazwij to

tv.setDrawingCacheEnabled(false);

po tym

bitmap = tv.getDrawingCache();

1
2017-09-01 13:09





spróbuj tego kodu zapisać to, co faktycznie pojawia się na ekranie.

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

Z powodzeniem przetestowałem.


1
2017-09-08 10:17



nie działa.... - Rahul Mandaliya
obraz zapisuje się pomyślnie, ale cień nie wyświetla się prawidłowo. - Rahul Mandaliya


Zrób zrzut ekranu w bitmapie, a następnie zapisz go.

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

0
2017-08-30 12:27



próbował, ale nie działa - Rahul Mandaliya


  1. Włącz akceleracje HW Androida (przez dodanie do manifestu android:hardwareAccelerated="true")
  2. Ustaw widok na typ warstwy LAYER_TYPE_SOFTWARE view.setLayerType(View.LAYER_TYPE_SOFTWARE,null).

Spróbuj z tymi dwiema rzeczami.


0
2017-09-01 13:26



Czy próbowałeś tego? Bcoz to nie działa po mojej stronie. - Rahul Mandaliya


Spróbuj tego,

klasa publiczna MainActivity rozszerza 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>
*/

}


0
2017-09-13 09:28





Tak to zrobiłem, ale potrzebujesz root'a lub innego źródła zrzutu ekranu. Oto kod 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;
}

Używam wewnętrznego screencap aby uzyskać zrzut ekranu, ale wymaga uprawnień roota. Google utworzył bibliotekę do robienia zrzutów ekranu bez roota, więc możesz użyć to.


0
2017-09-14 11:36





możesz zapisać dowolny widok jako obraz w ten sposób

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

0
2017-09-15 12:03





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

0
2017-09-15 15:37