Изображение, снятое на HTC Desire Z, показывает серию вертикальных линий - PullRequest
2 голосов
/ 14 мая 2011

У меня есть приложение, которое использует Camera API для захвата изображений.Реализация содержится в классе CameraActivity, который смоделирован после ряда примеров, которые я видел на этом сайте.Приложение в настоящее время работает на тысячах телефонов правильно;однако сегодня я получил сообщение от пользователя HTC Desire Z, в котором говорится, что мои изображения записываются в виде серии вертикальных линий (к сожалению, у меня недостаточно точек, чтобы опубликовать изображение, но есть много, чтобы отправить, если кто-тохотел бы увидеть один).Предварительный просмотр изображения в моем приложении и сохраненное изображение искажены.Пользователь также подтвердил, что он может использовать свою камеру телефона вне моего приложения без проблем.Я приложил источник для обзора.

Любая помощь будет принята с благодарностью.

public class CameraActivity extends Activity {
public static final int FOTO_MODE = 0;
private SurfaceView preview = null;
private SurfaceHolder previewHolder = null;
private Camera camera = null;
private boolean inPreview = false;
private String receiptFileName = null;

SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            camera.setPreviewDisplay(previewHolder);
        } catch (Throwable t) {
            Log.e("PreviewDemo-surfaceCallback", "Exception in setPreviewDisplay()", t);
            Toast.makeText(CameraActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Camera.Parameters parameters = camera.getParameters();
        Camera.Size size = getBestPreviewSize(width, height, parameters);

        if (size != null) {
            parameters.setPreviewSize(size.width, size.height);
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
            camera.setParameters(parameters);
            camera.startPreview();
            inPreview = true;
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // no-op
    }
};

Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
    public void onPictureTaken(byte[] imageData, Camera c) {
        if (imageData != null) {
            StoreByteImage(CameraActivity.this, imageData, 50, "ImageName");
            camera.startPreview();
            Intent resultIntent = new Intent();
            resultIntent.putExtra(getString(R.string.receiptFileName), receiptFileName);
            setResult(FOTO_MODE, resultIntent);
            finish();
        }
    }
};

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.camera_preview);
    receiptFileName = getIntent().getStringExtra(getString(R.string.receiptFileName));
    ImageView shutterButton = (ImageView) findViewById(R.id.shutterButton);
    shutterButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            takePicture();
        }
    });
    shutterButton.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            focusOnly();
            return false;
        }
    });
    preview = (SurfaceView) findViewById(R.id.surface_camera);
    previewHolder = preview.getHolder();
    previewHolder.addCallback(surfaceCallback);
    previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

@Override
public void onResume() {
    super.onResume();
    camera = Camera.open();
}

@Override
public void onPause() {
    if (inPreview) {
        camera.stopPreview();
    }

    camera.release();
    camera = null;
    inPreview = false;

    super.onPause();
}

private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
    Camera.Size result = null;

    for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
        if (size.width <= width && size.height <= height) {
            if (result == null) {
                result = size;
            } else {
                int resultArea = result.width * result.height;
                int newArea = size.width * size.height;

                if (newArea > resultArea) {
                    result = size;
                }
            }
        }
    }

    return result;
}

private void focusOnly() {
    String focusMode = camera.getParameters().getFocusMode();
    if (focusMode != null
            && (focusMode.equals(Camera.Parameters.FOCUS_MODE_AUTO) || focusMode
                    .equals(Camera.Parameters.FOCUS_MODE_MACRO))) {
        Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
            public void onAutoFocus(boolean success, Camera camera) {
            }
        };
        camera.autoFocus(autoFocusCallback);
    }
}

private void takePicture() {
    camera.takePicture(null, mPictureCallback, mPictureCallback);
}

private boolean StoreByteImage(Context mContext, byte[] imageData, int quality, String expName) {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        FileOutputStream fileOutputStream = null;
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 2;
            Bitmap bMap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
            Matrix mat = new Matrix();
            mat.postRotate(90);
            Bitmap myImage = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true);

            File path = new File(Environment.getExternalStorageDirectory() + ExpenseIt.SD_CARD_PATH_EXTENSION);
            path.mkdirs();
            fileOutputStream = new FileOutputStream(path + "/" + determineReceiptName());
            BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
            myImage.compress(CompressFormat.JPEG, quality, bos);
            bos.flush();
            bos.close();
        } catch (Exception e) {
            FailureDialogFactory.getInstance().handleFailure(this, "Failure storing camera image.", e);
        }
    } else {
        FailureDialogFactory.getInstance().handleFailure(this,
                "Unable capture receipts while SD card is not available or phone is connected to computer.", null);
    }
    return true;
}

private String determineReceiptName() {
    if (receiptFileName == null) {
        receiptFileName = Calendar.getInstance().getTimeInMillis() + ".jpg";
    }
    return receiptFileName;
}

1 Ответ

2 голосов
/ 31 мая 2011

Я боролся с той же проблемой в своем собственном проекте камеры на своем HTC Desire S. Несмотря на то что метод getSupportedPictureSizes вернул огромный список поддерживаемых размеров, я обнаружил, что снимки, которые я смог сделать без «вертикальной черты» проблема заключалась в тех, которые имели соотношение сторон, наиболее близко соответствующее соотношению сторон экрана устройства. Пример:

Мой HTC Desire S возвращает следующий список при вызове метода getSupportedPictureSizes:

2592x1952,2592x1456,2592x1520,2592x1936,2592x1728,2592x1552,2048x1536,2048x1360,2048x1216,2048x1152,2048x1200,1600x1200,1584x1056,1280x960,1280x848,1280x768,1280x720,1280x752,1024x768,640x480,640x416,640x384,640x368,512x384,400x400,272x272

Разрешение экрана телефона:

800x480
Aspect Ratio: 1.67

Так что, если я использую наибольший размер, возвращаемый методом getSupportedPictureSizes, для захвата изображения

2592x1952
Aspect Ratio: 1.32

Результат: захваченное изображение представляет собой серию вертикальных полос. (

Поэтому я изменил метод getOptimalPreviewSize, как указано здесь в примере CameraPreview , чтобы получить список разрешений, наиболее близких к разрешению экрана handet. Не самый эффективный способ сделать это, но у меня работает:

    private List getOptimalPictureSizes(List<Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) w / h;

    Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;
    List<Size> finalSizes = new ArrayList();
    // First filter out all sizes that have an aspect
    // tolerance > 0.1

    for (Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) < ASPECT_TOLERANCE){
            finalSizes.add(size);
        }
    }

    // Remove sizes with same width but more deviation from the 
    // handset's aspect ratio (1.67 in my HTC Desire S)

    List<Size> absoulteSizes = new ArrayList<Size>();
    for(int i=0; i<finalSizes.size()-1; i++){
        for(int j=i+1; j<finalSizes.size(); j++){
            Size iSize = finalSizes.get(i);
            Size jSize = finalSizes.get(j);
            if(iSize.width != jSize.width) 
                continue;
            double iRatio = (double)iSize.width/iSize.height;
            double jRatio = (double)jSize.width/jSize.height; 
            if(Math.abs(targetRatio - iRatio) < Math.abs(targetRatio - jRatio)){
                absoulteSizes.add(iSize);
            }else if(Math.abs(targetRatio - iRatio) > Math.abs(targetRatio - jRatio)){
                absoulteSizes.add(jSize);
            }
            else{
                absoulteSizes.add(iSize);
                absoulteSizes.add(jSize);
            }
        }
    }
    for(Size s:absoulteSizes){
        Log.e("Preview", "COMPUTED::: "+s.width+"x"+s.height);
    }
    return absoulteSizes;
}

Приведенный выше метод дает мне следующий отфильтрованный список:

2592x1552 Aspect Ratio: 1.67
2048x1216 Aspect Ratio: 1.684
1280x768  Aspect Ratio: 1.67
640x384   Aspect Ratio: 1.67

Все 4 размера работают нормально для моей камеры без проблем с вертикальной чертой. Также стоит отметить, что те же 4 размера предлагаются и в приложении к стандартной камере телефона.

Надеюсь, это поможет.

...