当前位置:网站首页>Custom view: graphics and image processing (I): using simple pictures

Custom view: graphics and image processing (I): using simple pictures

2022-06-10 22:54:00 A thrill for Android

        Android The system provides ImageView Show normal still pictures , Also provided AnimationDrawable To develop frame by frame animation , Can also be through Animation Use gap animation for normal pictures . graphics 、 Image processing is not only for Android The application interface of the system is very important , and Android Puzzle games on the system 、2D Games need a lot of graphics 、 The image processing .

         The so-called game , The essence is to provide more realistic 、 A user interface that simulates an environment , And respond to user actions according to certain rules . To provide a more realistic user interface , With the help of graphics 、 The image processing .

         In a broad sense ,Android The pictures in the application are not only Include *.png、*.jpg、 *.gif And so on , Also include Use XML The resource file defines various Drawable object .

1. Use Drawable object

         by Android Applications add Drawable After resources ,Android SDK For this resource in R Inventory file Create a Index entry :R.drawable.file_name.

Access method :

  • stay XML In the resource file @drawablelfile_name Access to Drawable object ,
  • stay Java Passed in code R.drawable.file_name Access to Drawable object .

         It's important to point out that ,R.drawable.file_name It's a int Constant of type , It only represents Drawable Object's ID, If Java The program needs to get the actual Drawable object , Can be called Resources Of getDrawable (int id) Method to implement .

2.Bitmap and BitmapFactory

Bitmap Representing one Bitmap ,BitmapDrawable in encapsulation The picture is One Bitmap object .

The conversion between the two :

// Put one Bitmap Object packed as BitmapDrawable object 
BitmapDrawable drawable = new BitmapDrawable (bitmap) ;

         If you need to get BitmapDrawable It's packaged Bitmap object , Can be called BitmapDrawable Of getBitmap () Method , This is shown in the following code :

// obtain BitmapDrawable It's packaged Bitmap  object 
Bitmap bitmap = drawable.getBitmap();

newly build Bitmap Some methods of object :

  • createBitmap (Bitmap source,int x, int y,int width,int height): From source bitmap source The specified coordinate point of ( Given x、y) Start , from “ Dig up " wide width、 high height A piece of , Create a new Bitmap object .
  • createScaledBitmap (Bitmap src, int dstWidth,int dstHeight,boolean filter) : For source bitmap src Zoom , Zoom to width dstWidth、 high dstHeight New bitmap for . filter It's the filter .
  • createBitmap (int width,int height,Bitmap.Config config): Create a wide width、 high height New bitmap for .
  • createBitmap (Bitmap source,int x, int y, int width,int height,Matrixm, boolean filter): From source bitmap source The specified coordinate point of ( Given x、y) Start , from “ Dig up " wide width、 high height A piece of , Create a new Bitmap object , And press Matrix The specified rules .

        Bitmap.Config class , stay Bitmap In class createBitmap(int width, int height, Bitmap.Config config) It's used in the method , Open this class and have a look : Enumerate variables

public static final Bitmap.Config ALPHA_8
public static final Bitmap.Config ARGB_4444
public static final Bitmap.Config ARGB_8888
public static final Bitmap.Config RGB_565

        BitmapFactory Is a utility class , It provides a number of methods , These methods can be used to parse from different data sources 、 establish Bitmap object .BitmapFactory The following methods are included .

  • decodeByteArray (byte[]data,int offset,int length)︰ From the specified byte array offset Position start , The length will be length The byte data of is parsed into Bitmap object .
  • decodeFile (String pathName) : from pathName Resolve in the specified file 、 establish Bitmap object .
  • decodeFileDescriptor (FileDescriptor fd): For from FileDescriptor Parse in the corresponding file 、 establish Bitmap object .
  • decodeResource (Resources res,int id) : Used according to a given resource ID Resolve from the specified resource 、 establish Bitmap object .
  • decodeStream (InputStream is): Used to parse from the specified input stream 、 establish Bitmap object .

         For creation , The corresponding is recycling . If the system keeps parsing 、 establish Bitmap object , Probably due to the creation of Bitmap The memory used has not been recycled yet , And lead to OOM.

  • boolean isRecycled (): Return to the Bitmap Whether the object has been recycled .
  • void recycle () : Force one Bitmap Object immediately reclaims itself .

         If Android Applications need to be Access other storage paths ( such as SD card ) The picture in , Then we all need the help of BitmapFactory Parsing 、 establish Bitmap object .

2.1 Example

         Let's develop a view /assets/ Picture viewer for pictures in the directory , When the user clicks this button, the program will automatically search /assets/ Under the directory — A picture . The interface layout code will not be given here , The code of the program is as follows .

public class Test4Activity extends Activity {

    String[] images = null;
    AssetManager assets = null;
    int currentImg = 0;
    private ImageView image;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test4_acitvity);

        image = findViewById(R.id.test4_iv);
        Button next = findViewById(R.id.test4_bt_next);

        try {
            assets = getAssets();
            // obtain assets All files in the directory 
            images =assets.list("");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Button event 
        next.setOnClickListener(view -> {
            // If the array is out of bounds 
            if(currentImg >= images.length){
                currentImg = 0;
            }
            // Find the next picture file 
            while (!images[currentImg].endsWith(".png")&&!images[currentImg].endsWith(".jpg")
                    &&!images[currentImg].endsWith(".gif")){
                currentImg++;
                // If an array out of bounds has occurred 
                if(currentImg >= images.length){
                    currentImg = 0;
                }
            }
            InputStream assetFile = null;
            try {
                // Open the input stream corresponding to the specified resource 
                assetFile = assets.open(images[currentImg++]);
            } catch (IOException e) {
                e.printStackTrace();
            }
            BitmapDrawable bitmapDrawable = (BitmapDrawable) image.getDrawable();
            // If the picture hasn't been recycled yet , Force the image to be recycled first 
            if(bitmapDrawable != null&&!bitmapDrawable.getBitmap().isRecycled()){
                bitmapDrawable.getBitmap().recycle();
            }
            // change ImageView display picture 
            // Called BitmapFactory Parses and creates... From the specified input stream Bitmap
            image.setImageBitmap(BitmapFactory.decodeStream(assetFile));
        });

    }
}

2.2 Extra knowledge (assets)

         The system provides... For each newly designed program /assets Folder , This The files saved in the folder can be packaged in the program .

        /res and /assets The difference is ,android Not for /assets File generation under ID. Suppose you use /assets The files under the , You need to specify the path and name of the file . How to access /assets Below ?

         for example , Suppose that assets There is a name in the directory called filename The file of , Then you can access it using the following code :

AssetManager assset= getAssets();  
InputStream is = assset.open("filename");

2.3 Excellent thought learning , Make the code more rigorous

1. I found that the code is not yellow at all , The proof is rigorous .

Pay attention to why button Put it inside , and imageView Put it outside .

take button Put it outside there will be Field can be converted to a local variable Warning of , This means that this variable can be replaced with a local variable , It is recommended to delete and write it as a local variable . It is not used anywhere else , There is no need to declare as a member variable .

2. Design to array access , Be sure to prevent its array from going out of bounds . There are also two .

assetFile = assets.open(images[currentImg++]);

         At this point, enter open Must be the image resources name, After use currentImg Self adding , Explore the next picture . The first judgment to prevent the array from crossing the bounds is to prevent the array from crossing the bounds ; The second is corresponding to the judgment that it is not a picture resource ++. But there is still a problem with this code : If there are resources , But they are not picture resources . Then it will go into a dead circle

3. Before displaying the picture , Be sure to release the previous Bitmap, lest OOM

The condition for the judgment of release is to use Bitmap The wrapper class .

3.Android 9 Newly added ImageDecoder

        Android 9 Introduced ImageDecoder、OnHanderDecodedListener etc. API, Provides more powerful picture decoding support , Can decode png、jpeg And so on gif、webp And so on . in addition . Also added support HEIF Format

        HEIF Format : This compression format With super high compression ratio , comparison JPEG, Can be compressed to half its size , And it can Ensure the approximate picture quality .

         When using ImageDecoder decode gif、webp When waiting for animated pictures , Will return a AnimatedImageDrawable object , call AnimatedImageDrawable Object's start() Method to start the animation .

ImageDecoder How to decode pictures :

  1. call ImageDecoder Heavy load of createSource Method to create Source object . According to different picture sources , createSource Methods have different overload modes .
  2. call ImageDecoder Of decodeDrawabIe(Source) or decodeBitmap(Source) Method to read the Drawable or Bitmap object .

         In the second step , It can be transmitted into a  OnHanderDecodedListener  Parameters , This parameter represents the listener , The listener should implement a onHanderDecoded(ImageDecoder,ImageInfo,Source) Method , It can be done to ImageDecoder Make additional settings , It can also be done through ImageInfo Get the information of the decoded picture .

3.1 Example

public class Test5Activity extends AppCompatActivity {

    // To put it bluntly, there is only api 28  The later ones came in 
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test5);

        // Get objects 
        TextView textView = findViewById(R.id.test5_tv);
        ImageView imageView = findViewById(R.id.test5_iv);
        // establish  imageDecoder.Source object 

            // First step :
            ImageDecoder.Source source = ImageDecoder.createSource(getResources(),R.drawable.viewgif);
            try {
                // The second step : perform decodeDrawable() Method to get Drawable object 
                @SuppressLint({"WrongThread", "SetTextI18n"})
                Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{
                    // adopt  info  Parameter to obtain the information of the decoded picture 
                    textView.setText(" The original width of the picture :"+info.getSize().getWidth()+
                            "\n"+" The original width and height of the picture "+info.getSize().getHeight());
                    // Set the zoom size after picture decoding 
                    decoder.setTargetSize(600,580);
                });
                imageView.setImageDrawable(drawable);
                // If drawable  yes AnimatedImageDrawable Example , Then execute the animation 
                if(drawable instanceof AnimatedImageDrawable){
                    ((AnimatedImageDrawable) drawable).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

}

         With the traditional BitmapFactory comparison ,ImageDecoder Can even Decode pictures that contain incomplete or incorrect information , If you want to display ImageDecoder Some pictures before decoding error , Can be passed as ImageDecoder Not set OnPartialImageListener Monitor to achieve . For example, the following code snippet :

// First use Lambda  Expression as OnHeaderDecodeListener Monitor 
    Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{
        // by ImageDecoder  Set up  OnPartialImageListener  Monitor (Lambda  expression )
        decoder.setOnPartialImageListener(e->{
            ....
            //return true  Indicates that even if the entire picture cannot be decoded completely, it returns Drawable or Bitmap
            return true;
        });
    });

原网站

版权声明
本文为[A thrill for Android]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/161/202206101622263133.html