如何在Android中从位图保存图片时设置dpi?

4

我使用这个函数将位图保存到SD卡上的文件:

private static File storeImage(Context context, Bitmap image) {
    File pictureFile = getOutputMediaFile(context);
    if (pictureFile == null) {
        return null;
    }
    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        image.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return pictureFile;
}

private static File getOutputMediaFile(Context context){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.
    File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
            + "/Android/data/"
            + context.getPackageName()
            + "/Files");

    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            return null;
        }
    }
    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
    File mediaFile;
    String mImageName="IMG_"+ timeStamp +".png";
    mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
    return mediaFile;
}

当我打开文件并查看图像DPI信息时,它显示为72像素/英寸(如图所示)

我该如何将其设置为300像素/英寸或其他值?


一种方法是更改PNG元数据。这很复杂,需要在Google中搜索并混淆字节。 - Nabin Bhandari
相关链接:https://dev59.com/Ql4c5IYBdhLWcg3w-OU4 - Morrison Chang
我的情况正好相反。如果我运行你的代码,我的输出是300 DPI,但我希望它是72 DPI。 - Johann
3个回答

2
这些是我在保存位图时使用的设置 dpi 的方法,请参考这里这里
public void storeImage(Bitmap image) {
        try {
            File pictureFile = new File("yourpath");

            FileOutputStream fos = new FileOutputStream(pictureFile);


            ByteArrayOutputStream imageByteArray = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.JPEG, 100, imageByteArray);
            byte[] imageData = imageByteArray.toByteArray();

            //300 will be the dpi of the bitmap
            setDpi(imageData, 300);

            fos.write(imageData);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } 
    }


    public void setDpi(byte[] imageData, int dpi) {
        imageData[13] = 1;
        imageData[14] = (byte) (dpi >> 8);
        imageData[15] = (byte) (dpi & 0xff);
        imageData[16] = (byte) (dpi >> 8);
        imageData[17] = (byte) (dpi & 0xff);
    }

使用CompressFormat.JPEG时效果很好,但在我的情况下不起作用。 因为我的图像具有alpha通道,并且我使用了“image.compress(Bitmap.CompressFormat.PNG,100,fos);” - Zidd

0

这里是我用于管理截图和调整图像大小的一些辅助方法。

  public static Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight, boolean recycleOriginal) {
    int width = bm.getWidth();
    int height = bm.getHeight();

    // Determine scale to change size
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;

    // Create Matrix for maniuplating size
    Matrix matrix = new Matrix();
    // Set the Resize Scale for the Matrix
    matrix.postScale(scaleWidth, scaleHeight);

    //Create a new Bitmap from original using matrix and new width/height
    Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);

    //Remove memory leaks if told to recycle, warning, if using original else where do not recycle it here
    if(recycleOriginal) {
        bm.recycle();

    }

    //Return the scaled new bitmap
    return resizedBitmap;

}
public static Bitmap cropImage(Bitmap imgToCrop, int startX, int startY, int width, int height, boolean recycleOriginal){
    Bitmap croppedImage = Bitmap.createBitmap(imgToCrop, startX, startY , width , height);

    if(recycleOriginal){
        imgToCrop.recycle();

    }

    return croppedImage;
}
public static Bitmap takeScreenshotOfView(Activity context, Bitmap.CompressFormat compressFormat){
    Bitmap screenshot = null;

    try {
        // create bitmap screen capture
        View v1 = context.getWindow().getDecorView().getRootView();
        v1.setDrawingCacheEnabled(true);
        screenshot = Bitmap.createBitmap(v1.getDrawingCache());
        v1.setDrawingCacheEnabled(false);

        File imageFile = new File(context.getFilesDir() + File.separator + "A35_temp" + File.separator + "screenshot_temp");

        FileOutputStream outputStream = new FileOutputStream(imageFile);
        int quality = 100;

        screenshot.compress(compressFormat, quality, outputStream);
        outputStream.flush();
        outputStream.close();

    } catch (Throwable e) {
        // Several error may come out with file handling or OOM
        e.printStackTrace();
    }

    return screenshot;
}

这些都是我 ImageHelper 类的一部分,我只需像这样使用:

             Bitmap screenshot = ImageHelper.takeScreenshotOfView(this, Bitmap.CompressFormat.JPEG);
            Bitmap croppedImage = ImageHelper.cropImage(screenshot, ImageHelper.mStartXCrop, ImageHelper.mStartYCrop, ImageHelper.mCropWidth, ImageHelper.mCropHeight, true);
            returnImage =  ImageHelper.getResizedBitmap(croppedImage, mCropImageWidth, mCropImageHeight, false);

我认为你不是在尝试截屏,但你仍然可以使用 resize 方法。

1
他们不想调整图像的大小。问题是如何保持原始宽度和高度(以像素为单位),但只需更改图像的dpi字段。 - ToolmakerSteve
@ToolmakerSteve 感谢您的澄清,不过这个问题和答案已经超过4年了,而且没有任何赞,所以我不确定您是否需要在问答阶段提供澄清。 ;) - Sam
你可能是正确的;我之所以这样做,只是因为今天我在其他地方添加了一个链接到这个问答。我希望任何跟随该链接的人都清楚“调整大小”和“设置dpi字段”之间的区别——因为有多次我看到人们认为dpi字段中的值会以某种神奇的方式影响图像质量。相反,如果他们打算降低图像质量,我不希望他们进行此调整大小。:)当我来到这里时,所有答案都没有得到投票,因此任何阅读的人都可能感到困惑。 - ToolmakerSteve

-1

300 dpi对于打印非常好,因此考虑像素计数时,当您设置图像的高度和宽度(以英寸为单位)时,请乘以300。 例如,在创建位图时

Bitmap bm = Bitmap.createBitmap( W_inch*300  ,  H_inch*300  , Bitmap.Config.ARGB_8888);

在图像属性/详细信息中可能不会显示300dpi,但是由于DPI是每英寸线的点数,因此质量将与300dpi相同。


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