安卓相机参数setPictureSize导致图像有条纹

4
我正在尝试使用Android相机拍照。我需要捕获一个1600 (w) x 1200 (h)的图像(第三方供应商要求)。我的代码似乎对许多手机相机都有效,但在某些手机上(三星Galaxy S4,三星Galaxy Note)setPictureSize会导致崩溃,在其他手机(Nexus 7平板电脑)上会导致带条纹的图片。至少在Nexus上,我想要的大小出现在getSupportPictureSizes列表中。
我已经尝试指定方向,但没有帮助。使用默认图片大小拍照正常。
这是条带的示例:

enter image description here

对于我的图像捕获,我需要1600x1200像素、jpg格式、30%压缩比的要求,因此我正在捕获JPG文件。我认为我有三个选择: 1)找出如何在没有崩溃或条纹的情况下捕获1600x1200大小的图像; 2)找出如何将默认图片大小更改为1600x1200的JPG格式; 3)其他我目前不知道的方法。
我发现一些其他帖子存在类似的问题,但并不完全相同。我已经尝试了两天,但没有找到解决方案。这里是一个接近解决的帖子: Camera picture to Bitmap results in messed up image(没有一个建议对我有用)
这是我的代码部分,在遇到S4/Note/Nexus 7之前它很好用。我现在添加了一些调试代码:
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);

if (size != null) {
    int pictureWidth = 1600;
    int pictureHeight = 1200;

    // testing
    Camera.Size test = parameters.getPictureSize();
    List<Camera.Size> testSizes = parameters.getSupportedPictureSizes();
    for ( int i = 0; i < testSizes.size(); i++ ) {
        test = testSizes.get(i);
    }

    test = testSizes.get(3);
    // get(3) is 1600 x 1200
    pictureWidth = test.width;
    pictureHeight = test.height;

    parameters.setPictureFormat(ImageFormat.JPEG);
    parameters.setPictureSize(pictureWidth, pictureHeight);
    parameters.setJpegQuality(30);
    parameters.setPreviewSize(size.width, size.height);

    // catch any exception
    try {
        // make sure the preview is stopped
        mCamera.stopPreview();

        mCamera.setParameters(parameters);
        didConfig = true;
    catch(Exception e) {
        // some error presentation was removed for brevity
        // since didConfig not set to TRUE it will fail gracefully
    }
}

这是我的代码部分,用于保存JPG文件:

PictureCallback jpegCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
        if ( data.length > 0 ) {

            String fileName = "image.jpg";

            File file = new File(getFilesDir(), fileName);
                String filePath = file.getAbsolutePath();

             boolean goodWrite = false;
             try {
                 OutputStream os = new FileOutputStream(file);
                 os.write(data);
                 os.close();

                goodWrite = true;
            } catch (IOException e) {
                 goodWrite = false;
             }

             if ( goodWrite ) {
                // go on to the Preview
             } else {
                // TODO return an error to the calling activity
             }

        }

        Log.d(TAG, "onPictureTaken - jpeg");
    }
};

任何有关如何正确设置相机参数以拍摄照片,或如何裁剪或调整所得照片的建议都将非常有用。特别是如果它能与旧相机(API级别8或更高)兼容!基于需要使用图片的全宽,我只能从顶部裁剪。
谢谢!
编辑:这是我最终采取的做法:
我首先处理了Camera.Parameters getSupportedPictureSizes,选择第一个高度和宽度均大于我的所需尺寸,并且具有相同宽高比的图像尺寸。然后我将相机参数设置为该图片大小。
然后一旦拍摄完成:
BitmapFactory.Options options = new BitmapFactory.Options();;
options.inPurgeable = true;

// convert the byte array to a bitmap, taking care to allow for garbage collection
Bitmap original = BitmapFactory.decodeByteArray(input , 0, input.length, options);
// resize the bitmap to my desired scale 
Bitmap resized = Bitmap.createScaledBitmap(original, 1600, 1200, true);

// create a new byte array and output the bitmap to a compressed JPG
ByteArrayOutputStream blob = new ByteArrayOutputStream();
resized.compress(Bitmap.CompressFormat.JPEG, 30, blob);

// recycle the memory since bitmaps seem to have slightly different garbage collection
original.recycle();
resized.recycle();

byte[] desired = blob.toByteArray();

然后我将所需的 jpg 写入文件以进行上传。
1个回答

4
test = testSizes.get(3);
// get(3) is 1600 x 1200

数组中没有要求有4个或更多的元素,更别说第四个元素是1600x1200了。

1) 找出如何在不崩溃或留下痕迹的情况下捕获1600x1200大小的图像

并非每个设备都能够拍摄具有完全相同分辨率的照片。您不能为分辨率指定任意值 - 它必须是受支持的图片尺寸之一。某些设备支持任意值,而其他设备将会给您提供损坏的输出(就像这里的情况)或者直接崩溃。

2) 找出如何将默认图片大小更改为一个JPG文件,其大小为1600x1200

我不知道是否存在“默认图片大小”,而且除此之外,这种大小将是不可变的,因为它是默认值。更改图片大小是您上述的选项#1。

3) 目前我还不知道的其他事情。

对于支持两个轴上更大分辨率的设备,请使用该分辨率拍摄照片,然后裁剪到1600x1200。

对于所有其他设备,其中一个或两个轴小于所需大小,请使用适合您的任何分辨率(最大值,最接近4:3宽高比等),然后拉伸/裁剪以达到1600x1200。


对我来说奇怪的是,1600x1200的尺寸被列为支持的图片尺寸,但我仍然得到了损坏的输出。由于供应商的要求(请检查存款的图像捕获),我无法在一个方向上拉伸或缩小。我可以根据用户在预览窗口中对齐图像的方式裁剪顶部。我需要使用位图进行图像处理,然后转换为jpg吗?(默认大小是指在更改任何设置之前从getPictureSize()获取的大小。) - Gravitoid
@Gravitoid:“对我来说奇怪的是,1600x1200的尺寸被列为支持的图片尺寸,但我仍然得到了损坏的输出”--这是有可能的。我通常关注最高相机分辨率,而且确实有一些设备报告的分辨率会导致错误的输出。“由于供应商的要求,我无法在一个方向上进行拉伸或缩小”--那么你就不能编写你的应用程序,因为没有要求相机在任何给定的轴上恰好支持1600或1200个像素。 - CommonsWare
@Gravitoid:此外,我很困惑你为什么会担心“条纹”。根据你自己的承认,你的应用在某些设备上会崩溃。相比之下,有条纹的图像是一个积极的结果。 - CommonsWare
感谢提供有用的信息。我的担忧是崩溃发生在三星Galaxy S4上,这是一款非常受欢迎的手机,我不愿意说我的应用程序不支持该手机。我宁愿找到适用于S4以及所有已经工作的手机的解决方案。条纹/损坏出现在Nexus 7平板电脑上,虽然比崩溃好,但仍然不能使用(我碰巧拥有Nexus,但没有S4)。如果我使用最高可能的分辨率,或者如果当前设置与4:3比例匹配,则如何达到1600x1200? - Gravitoid
@Gravitoid:“我不情愿地说,我的应用程序不支持该手机”--你的供应商需要接受现实,即并非每个相机都会屈服于他们的意愿。裁剪和/或缩放是不可避免的。“有什么建议可以达到1600x1200吗?”--如我在答案中所述,您必须进行裁剪或缩放。有createBitmap()createScaledBitmap()可以处理这个问题。 - CommonsWare
一些设备支持任意值 -- 真的很奇怪! - Matt Logan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接