RedApparat / Fotoapparat

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

The camera takes seconds to capture a photo, is there a way to make it faster? #258

Closed javidnoutash closed 6 years ago

pishangujeniya commented 6 years ago

The time taken for capturing photo can be lessen using low resolutions. By default fotoapparat provides ResolutionSelector with highestResolution or LowestResolution.

Even I am finding any way to provide manual resolution.

I tried taking photos in lowestResolution is awesome fast, so If I can reduce the resolution upto my need it would be better.

dmitry-zaitsev commented 6 years ago

The bigger the resolution, the longer it takes for your device to process the image.

To provide a custom resolution you need to implement your own resolution selector. It is actually pretty simple - you are given a list of available resolutions from which you need to select one. Unfortunately, you can't just say which size you want - you need to select one from what Camera provides you.

Here is how highest and lowest resolution selectors are implemented: https://github.com/Fotoapparat/Fotoapparat/blob/master/fotoapparat/src/main/java/io/fotoapparat/selector/ResolutionSelectors.kt

For example, the selector which picks the second highest resolution would look like that:

fun customResolutionSelector(): ResolutionSelector = {
    // In current context "this" is the list of resolutions.
    return sortedByDescending(Resolution::area) // we sort the list by resolutions - the highest resolutions first
        .drop(1) // let's ignore the highest resolution 
        .firstOrNull() // ... and pick the next one
        ?: first() // it could be that the original list contained only 1 resolution. If that is the case we need to default to something.
}
tapeo commented 6 years ago

I use this method to select the resolution with custom megapixel.

        fotoapparat = Fotoapparat.with(mActivity)
                .into(preview)
                .previewScaleType(ScaleType.CenterCrop)
                .previewResolution(new Function1<Iterable<Resolution>, Resolution>() {
                    @Override
                    public Resolution invoke(Iterable<Resolution> resolutions) {
                        return getResolutionWithMp(1.2f, resolutions);
                    }
                })
                .photoResolution(new Function1<Iterable<Resolution>, Resolution>() {
                    @Override
                    public Resolution invoke(Iterable<Resolution> resolutions) {
                        return getResolutionWithMp(5f, resolutions);
                    }
                })
                .build();
private Resolution getResolutionWithMp(float megapixel, Iterable<Resolution> resolutions) {
        LinkedList<Resolution> resolutionsList = new LinkedList<>();

        for (Resolution res : resolutions) {
            resolutionsList.add(res);
        }

        Collections.sort(resolutionsList, new Comparator<Resolution>() {
            @Override
            public int compare(Resolution r0, Resolution r1) {
                if (r1.getArea() < r0.getArea()){
                    return 1;
                } else {
                    return -1;
                }
            }
        });

        for (Resolution size : resolutionsList) {

            float sizeMp = size.getArea() / 1000000f;

            if (sizeMp > megapixel) {
                Log.e("Fotoapparat", "Selected: " + String.valueOf(sizeMp));
                return size;
            }

        }

        Resolution highest = highestResolution().invoke(resolutions);
        Log.e("Fotoapparat", "Selected: " + String.valueOf(highest.getArea() / 1000000f));
        return highest;
    }
dmitry-zaitsev commented 6 years ago

That is pretty neat! Would look even prettier in Kotlin :)

javidnoutash commented 6 years ago

Thanks for the replies guys :)

KlaartjeD commented 5 years ago

I made a kotlin version :)

pictureResolution = {
                        var resolution: Resolution? = null
                        for (size in this) {
                            val sizeMp = size.area / 1000000F
                            if (sizeMp > 2F && sizeMp < 4F) {
                                resolution = size
                                break
                            }
                        }
                        resolution
                    }
KlaartjeD commented 5 years ago

also reworked the java version a bit. .photoResolution(this::preferredResolution)

 private Resolution preferredResolution(Iterable<Resolution> resolutions) {
        Resolution resolution = null;
        for (Resolution size : resolutions) {
            float sizeMp = size.getArea() / 1000000F;
            if (sizeMp > 2F && sizeMp < 4F) {
                resolution = size;
                break;
            }
        }
        return resolution;
    }