MonoTouch的:当色相调整Retina显示屏上加倍外观图像尺寸(MonoTouch: Doub

2019-06-26 18:13发布

我设置的NavBar的背景,这个代码在视网膜和非Retina显示屏的伟大工程。 有一个@ 2x和正常图像。 所以,所有的好:

UINavigationBar.Appearance.SetBackgroundImage(
     GetImage(ImageTheme.menubar), UIBarMetrics.Default);

现在,当我应用此ChangeHue()变换到图像调整其色调,视网膜上显示的图像是大小的两倍。 非Retina显示屏的罚款:

    UINavigationBar.Appearance.SetBackgroundImage(
       ChangeHue(GetImage(ImageTheme.menubar)), UIBarMetrics.Default);
    ...

    UIImage ChangeHue(UIImage originalImage){
        var hueAdjust = new CIHueAdjust() {
            Image = CIImage.FromCGImage(originalImage.CGImage),
            Angle = hue * (float)Math.PI / 180f // angles to radians
        };

        var output = hueAdjust.OutputImage;
        var context = CIContext.FromOptions(null);
        var cgimage = context.CreateCGImage(output, output.Extent);
        var i = UIImage.FromImage(cgimage);
        return i;
}

下面是结果在非视网膜和视网膜显示被施加色相后:

Answer 1:

忽略那些黑客,并在编辑这行ChangeHue方法:

var i = UIImage.FromImage(cgimage);

要做到这一点,而不是:

float scale = 1f;
if (UIScreen.MainScreen.RespondsToSelector (new MonoTouch.ObjCRuntime.Selector ("scale"))) {
    scale = UIScreen.MainScreen.Scale; // will be 2.0 for Retina 
}
var i = new UIImage(cgimage, scale, UIImageOrientation.Up);

这应返回UIImage对象,它是具有在正常显示正确的“规模”的信息UINavigationBar



Answer 2:

我从来没有尝试过的CoreImage但是,对于CoreGraphics中,你需要使用UIGraphics.BeginImageContextWithOptions并指定0缩放(因此它会自动地为双方的Retina和非Retina显示屏来完成)。

所以我想尝试的第一件事就是更换您:

var context = CIContext.FromOptions(null);

用下面的块:

UIGraphics.BeginImageContextWithOptions (new SizeF (size, size), false, 0);
using (var c = UIGraphics.GetCurrentContext ()) {
   var context = CIContext.FromContext (c);
   ...
}
UIGraphics.EndImageContext ();

UPDATE: FromContext不可用的iOS(它是OSX的具体),所以上面的代码将无法正常工作。



Answer 3:

建档的错误与MonoTouch的团队。 不久将发布的解决方案。



Answer 4:

我有三个“黑客”建议现在:

哈克#1

要强制的程度通过更换此行裁剪图像:

var cgimage = context.CreateCGImage(output, output.Extent);

有了这个:

var extent = output.Extent;
if (UIScreen.MainScreen.RespondsToSelector (new MonoTouch.ObjCRuntime.Selector("scale"))) {
    if (UIScreen.MainScreen.Scale == 2f) {
        extent = new System.Drawing.RectangleF(extent.X, extent.Y, extent.Width / 2f, extent.Height / 2f);
    }
}
var cgimage = context.CreateCGImage(output, extent);

然而,你“丢失”调整图像上的视网膜分辨率(它使用的@ 2倍的图像作为源,但只应用过滤器后显示它的左下象限,由于图像原点开始在左下) 。

哈克#2

按照同样的思路,可以缩放从返回的图像ChangeHue方法,使其不扩大超出了导航栏:

var hued = ChangeHue (navBarImage);
if (hued.RespondsToSelector(new MonoTouch.ObjCRuntime.Selector("scale")))
    hued = hued.Scale (new System.Drawing.SizeF(320, 47));
UINavigationBar.Appearance.SetBackgroundImage (hued, UIBarMetrics.Default);

不幸的是,你又“丢失”的Retina分辨率,但至少显示正确的图像(只是下采样到320宽)。

哈克#3

你可以保存过滤的图像到磁盘,然后设置UIAppearance使用“盘”上的图像文件。 代码如下所示:

bool retina = false;
if (UIScreen.MainScreen.RespondsToSelector (new MonoTouch.ObjCRuntime.Selector ("scale"))) {
    if (UIScreen.MainScreen.Scale == 2f) {
        retina = true;
    }
}
if (retina) {
    NSError err; // unitialized
    UIImage img = ChangeHue (navBarImage);
    img.AsPNG ().Save ("tempNavBar@2x.png", true, out err);
    if (err != null && err.Code != 0) {
        // error handling
    }
    UINavigationBar.Appearance.SetBackgroundImage (UIImage.FromFile ("tempNavBar.png"), UIBarMetrics.Default);
} else {
    UINavigationBar.Appearance.SetBackgroundImage (ChangeHue (navBarImage), UIBarMetrics.Default);
}

这最后黑客的好处是,图像看起来正确的(即视网膜分辨率保存)。

我仍然在寻找“完美”的解决方案,但至少这些想法“修复”你的问题单向或-另一...



文章来源: MonoTouch: Doubling Appearance Image size when Hue adjusted on Retina display