RedApparat / Fotoapparat

Making Camera for Android more friendly. 📸
Apache License 2.0
3.82k stars 407 forks source link

Some questions #67

Closed scifinder closed 7 years ago

scifinder commented 7 years ago

Hi! =) Great work! =) I'm currently studying your library, and I have some questions.

  1. How are values calculated for biggestSize/smallestSize? In my case, these values are always 640x480/320x240 (on any devices). How can I specify my exact value? Here so it is a possible?
                .previewSize(
                        new SelectorFunction<Size>() {
                            @Override
                            public Size select(Collection<Size> collection) {
                                return new Size(1280, 720); //Any values from user's settings
                            }
                        }
                ) 

    How can I test what photo resolutions are supported on the user's device?

  2. How do I fill the entire screen with the image I received? My layout:
    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:background="#c3c" />

    My code (photoResult.toBitmap().whenAvailable):

    imageView.setImageBitmap(result.bitmap);
    imageView.setRotation(-result.rotationDegrees);
    imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

    And my result: imageview I can not fill the entire screen with the image!

  3. Do I need to call Fotoapparat.start() on onResume() and .stop() on onPause()?
  4. Is the API version selected automatically by Fotoapparat, or should I choose with cameraProvider? In last case, what should be the algorithm of choice?
  5. Is this code (imageView.setRotation(-result.rotationDegrees);) correct on any device? Or should I determine the orientation of the screen and the orientation of the camera on the device and calculate the value for the photo?

Thanks!

scifinder commented 7 years ago

I answer myself =)

How can I test what photo resolutions are supported on the user's device?

CapabilitiesResult result = fotoapparat.getCapabilities();
result.toPendingResult().whenAvailable(new PendingResult.Callback<Capabilities>(){
@Override
public void onResult(Capabilities capabilities){
Log.d("MY_", capabilities.supportedPictureSizes().toString());
}
});
Diolor commented 7 years ago

Hey!

1) You can call fa. getCapabilities() to see what capabilities your device supports. You found it already :) 2) Please see here you need, CENTER_CROP: https://developer.android.com/reference/android/widget/ImageView.ScaleType.html 3) You can call them in resume/pause lifecycle too 4) You define the API level in your project. Usually in gradle. Here's an article about it https://medium.com/google-developers/picking-your-compilesdkversion-minsdkversion-targetsdkversion-a098a0341ebd 5) Depends your ending result wishes. Assuming that there was no orientation change, we will calculate the sensor orientation in accordance to the current display orientation. Then we will provide you with the correct degrees so as the image will be viewed upright when you apply this rotation. See the example https://github.com/Fotoapparat/Fotoapparat/blob/master/sample/src/main/java/io/fotoapparat/sample/MainActivity.java#L170

dmitry-zaitsev commented 7 years ago

Some small corrections to @Diolor answer:

1- Normally you should select one of the sizes provided to you in Collection<Size> - they are all supported sized. getCapabilities is for very specific use cases and you probably do not need that.

3 - The calls have to be symmetrical and happen anywhere between onStart and onStop. You can even start and stop the camera several times within single screen opening.

4 - If you mean API level of Camera - we use Camera1 by default for all OS versions, because (surprise) it is more robust. You can override it if you like, but I would not recommend it.

5 - In short what @Diolor said - we give you the correct orientation, no need to account for anything else.

scifinder commented 7 years ago

1 - If I want to change the resolution of the camera when it's opened, will I have to do fa.stop() => fa.photoSize(newSize).build() => fa.start()? For example, if the user has changed the resolution in the settings. How to make a "rebuild" correctly? 4 - Yes, I meant Camera API. 5 & 2 - Yeah! If I use Size.flip() according to the screen orientation, my photo will always fill the screen! =) Yes?))

dmitry-zaitsev commented 7 years ago

1 - Either that or you can consider using FotoapparatSwitcher. There you can just provide different versions of Fotoapparat and then switch between them. Also, no need to expand selectors, since we already have AspectRatioSelectors :)

You can do stuff like:

.photoSize(aspectRatio(16f/9f, biggestSize())) // Will pick the biggest 16/9 size
.photoSize(aspectRatio(4f/3f, smallestSize())) // Will pick the smallest 4/3 size

5 - You should not return size if it is not in the collection which is given to you. It can be the case that Size.flip() is also in this collection, but it is not guaranteed for all devices.

Camera preview size actually does not affect the size of the view, it affects only resolution (aka quality of what you see on the screen). If you would like to change the size of the view, either follow @Diolor advice (and use CENTER_CROP) or change the size of the view.

scifinder commented 7 years ago

Hi again! =) 1 - I did this:

                .previewSize(
                        firstAvailable(
                                aspectRatio(
                                        16f/9f,
                                        smallestSize()
                                ),
                                aspectRatio(
                                        4f/3f,
                                        smallestSize()
                                )
                        )
                )
                .photoSize(
                        firstAvailable(
                                aspectRatio(
                                        16f/9f,
                                        biggestSize()
                                ),
                                aspectRatio(
                                        4f/3f,
                                        biggestSize()
                                )
                        )
                )

It is right?)) 5 - I solved the problem as follows:

        photoResult.toBitmap()
                .whenAvailable(new PendingResult.Callback<BitmapPhoto>() {
                    @Override
                    public void onResult(BitmapPhoto result){
                        ImageView imageView = (ImageView) findViewById(R.id.image_view);

                        Matrix matrix = new Matrix();
                        matrix.postRotate(-result.rotationDegrees);
                        Bitmap bitmap = Bitmap.createBitmap(result.bitmap, 0, 0, result.bitmap.getWidth(), result.bitmap.getHeight(), matrix, false);

                        imageView.setImageBitmap(bitmap);
                    }
                });

It's work correct for all screen position (image always takes full screen and have right orientation), but very slow. Are there alternatives?

bruferrari commented 7 years ago

@scifinder did you solved the problem related to image don't fill the entire view? If yes, how? I'm trying everything that I can imagine and even using scaleTypes it's not working.

scifinder commented 7 years ago

@bruferrari, as a temporary solution, I did so. In Fotoapparat builder:

                .photoSize(
                        firstAvailable(
                                aspectRatio(
                                        16f/9f,
                                        smallestSize()
                                ),
                                aspectRatio(
                                        4f/3f,
                                        smallestSize()
                                )
                        )
                )

In Layout:

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />

In takePicture():

        photoResult.toBitmap()
                .whenAvailable(new PendingResult.Callback<BitmapPhoto>() {
                    @Override
                    public void onResult(BitmapPhoto result){
                        ImageView imageView = (ImageView) findViewById(R.id.image_view);

                        Matrix matrix = new Matrix();
                        matrix.postRotate(-result.rotationDegrees);
                        Bitmap bitmap = Bitmap.createBitmap(result.bitmap, 0, 0, result.bitmap.getWidth(), result.bitmap.getHeight(), matrix, false);

                        imageView.setImageBitmap(bitmap);

                    }
                });

It works on my tablet and phone (640x480 and 1280x720 respectively). If in photoSize() put biggestSize() value, then the matrix is processed very long (several seconds). Maybe you will offer a better solution.

dmitry-zaitsev commented 7 years ago

@scifinder

It is right?))

Yes. You can even extract firstAvailable(...) into a constant to not repeat yourself.

It's work correct for all screen position (image always takes full screen and have right orientation), but very slow. Are there alternatives?

You are modifying Bitmap in memory, which is not only slow but also memory consuming. The recommended way is to rotate only ImageView as it is done in the example.

scifinder commented 7 years ago

@dmitry-zaitsev, @bruferrari Finally, Glide solve all my problems =)

        photoResult.saveToFile(dst_file)
                .whenAvailable(new PendingResult.Callback<Void>() {
                    @Override
                    public void onResult(Void t){
                        ImageView imageView = (ImageView) findViewById(R.id.image_view);

                        Glide.with(getApplicationContext()).load(dst_file).into(imageView);
                    }
                });

Autoscale, autorotation... Yet another option .fitCenter() (for complete lucky): Glide.with(getApplicationContext()).load(dst_file).fitCenter().into(imageView);