在Xamarin Android中为PNG图片位图设置DPI
在Xamarin Android中修改PNG图片的DPI
我之前也碰到过类似的需求——PNG的DPI处理确实和JPEG不一样,因为JPEG用Exif元数据存DPI,而PNG是靠pHYs chunk来存储像素密度信息的,常规的Exif工具对它没用。下面给你两个可行的方案,优先推荐第一个,简单又靠谱:
方案一:用SkiaSharp快速实现(推荐)
SkiaSharp是谷歌官方的跨平台图形库,在Xamarin Android里支持得很好,能轻松处理PNG的DPI信息,不用手动解析文件结构。
步骤:
- 先在你的Xamarin Android项目里安装两个NuGet包:
SkiaSharp和SkiaSharp.NativeAssets.Android。 - 用下面的代码加载原PNG、修改DPI并保存:
using SkiaSharp; using System.IO; // 替换成你的原图片路径和目标保存路径 string originalPngPath = Path.Combine(Android.App.Application.Context.FilesDir.AbsolutePath, "original.png"); string modifiedPngPath = Path.Combine(Android.App.Application.Context.FilesDir.AbsolutePath, "modified.png"); // 加载原图片 SKBitmap originalBitmap = SKBitmap.Decode(originalPngPath); // 设置你想要的DPI值,比如300 float targetDpi = 300f; // 创建包含目标DPI的图片信息对象 SKImageInfo imageInfo = new SKImageInfo( originalBitmap.Width, originalBitmap.Height, originalBitmap.ColorType, originalBitmap.AlphaType) { DpiX = targetDpi, DpiY = targetDpi }; // 绘制并保存新图片 using (SKSurface surface = SKSurface.Create(imageInfo)) { SKCanvas canvas = surface.Canvas; canvas.DrawBitmap(originalBitmap, new SKRect(0, 0, imageInfo.Width, imageInfo.Height)); using (SKImage modifiedImage = surface.Snapshot()) using (SKImageData imageData = modifiedImage.Encode(SKEncodedImageFormat.Png, 100)) using (FileStream outputStream = new FileStream(modifiedPngPath, FileMode.Create)) { imageData.SaveTo(outputStream); } } // 记得释放资源 originalBitmap.Dispose();
这段代码会把DPI信息写入PNG的pHYs chunk,修改后的图片在任何支持读取PNG密度信息的工具里都会显示你设置的DPI值。
方案二:原生手动解析PNG chunk(不推荐,适合特殊场景)
如果不想用第三方库,就得手动处理PNG的文件结构,修改或添加pHYs chunk。这个过程比较繁琐,容易出错,我简单说下思路:
- PNG文件开头是8字节的签名,后面跟着一个个chunk(每个chunk由长度、类型、数据、CRC校验组成)。
- 找到类型为
pHYs的chunk(如果没有,就在IDATchunk之前插入一个)。 - 把你要的DPI转换成像素/米(公式:
dpi / 0.0254,取整),替换chunk里的X/Y像素密度值。 - 重新计算该chunk的CRC校验值,然后把修改后的字节流保存为新文件。
这种方法需要处理字节序(大端)和CRC计算,除非你有特殊需求,否则还是用SkiaSharp更省心。
最后,修改完DPI的PNG就可以正常上传到服务器了,和普通文件上传流程一样就行。
内容的提问来源于stack exchange,提问作者vITs
相关产品推荐
相关产品推荐

