Xamarin提供了一些示例代码,用于对iOS中的图像进行简单调整:
configuring the project's visibility
此代码仅在用户释放滑块旋钮时更新图像 - 而不是我们通常期望的连续更新。
然而,当我做出以下更改时,我可靠地在硬件上遇到SIGSEGV故障。
//sliderC.TouchUpInside += HandleValueChanged;
//sliderS.TouchUpInside += HandleValueChanged;
//sliderB.TouchUpInside += HandleValueChanged;
sliderC.ValueChanged += HandleValueChanged;
sliderS.ValueChanged += HandleValueChanged;
sliderB.ValueChanged += HandleValueChanged;
我希望这是"重载"代码以某种方式。您将如何实施避免此问题的图像调整?是否有较低级别的方法,或者其他应用只是使用低得多的rez版本的图像进行调整?
答案 0 :(得分:2)
这是我所做的一个“更多”实时的快速版本(这是来自sim的录制,设备(6s)根据初始图像大小是平滑的。
从模板创建一个viewcontroller iOS应用程序,并将一个UIImageView和三个滑块添加到故事板,使其看起来像动画gif。
我创建了一个简单的类来存储ColorCtrl值(亮度,对比度,饱和度:
public class ColorCtrl
{
public float s;
public float b;
public float c;
}
在ViewDidLoad
方法中,进行一些设置:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
string filePath = Path.Combine (NSBundle.MainBundle.BundlePath, "hero.jpg");
originalImage = new CIImage (new NSUrl (filePath, false));
colorCtrls = new CIColorControls ();
colorCtrls.Image = originalImage;
// Create the context only once, and re-use it
var contextOptions = new CIContextOptions ();
contextOptions.UseSoftwareRenderer = false; // gpu vs. cpu
// On save of the image, create a new context with highqual attributes and re-apply the filter...
contextOptions.HighQualityDownsample = false;
contextOptions.PriorityRequestLow = false; // high queue order it
contextOptions.CIImageFormat = (int)CIFormat.ARGB8; // use 32bpp, vs. 64|128bpp
context = CIContext.FromOptions (contextOptions);
}
然后是三个滑块的更改处理程序。
在那些我'破解'繁忙的旗帜中,如果最后的变换没有完成,则跳过图像变换。如果我们不忙,那就等待我们的异步转换方法调用。
注意:我说' hack ',我的意思是,在最佳实践中,这应该将请求转换为队列,队列处理程序将汇总队列中的所有待处理项,冲洗它们并进行转换。
注意:我为生成的事件处理程序添加了“async”,因此我可以await
进行图像转换。
注意:除了分配的值之外,三个滑块的处理程序都是相同的; colorCtrlV.b | colorCtrlV.s | colorCtrlV.c
注意:您可以在用户触摸时对大图像进行下采样,对其执行变换,然后在触摸时,变换原始的全尺寸图像......
async partial void brightnessChange (UISlider sender)
{
if (!busy) {
busy = true;
colorCtrlV.b = sender.Value;
this.imageView.Image = await FilterImageAsync (colorCtrlV);
busy = false;
}
}
好的,现在对于实际的转换,一个相当简单的Run.Task,所以我们可以从主线程中获得这项工作,而不是阻止UI。这样滑块就不会在用户滑动手指时断断续续,但由于滑块处理程序中的“忙”标志/黑客,我们可能会跳过其中一些事件(我们应该添加处理程序触摸拖动退出,以便我们处理'最后'用户的请求值....)
// async Task.Run() - not best practice - just a demo
async Task<UIImage> FilterImageAsync (ColorCtrl value)
{
if (transformImage == null)
transformImage = new Func<UIImage>(() => {
colorCtrls.Brightness = colorCtrlV.b;
colorCtrls.Saturation = colorCtrlV.s;
colorCtrls.Contrast = colorCtrlV.c;
var output = colorCtrls.OutputImage;
var cgImage = context.CreateCGImage (output, originalImage.Extent);
var filteredImage = new UIImage (cgImage);
return filteredImage;
});
UIImage image = await Task.Run<UIImage>(transformImage);
return image;
}
个人对于这种类型的实时图像转换,我更喜欢使用GPUImage通过OpenGL-ES来实现,因为屏幕在60z刷新率下的交互与黄油一样顺畅,但它比使用CoreImage
过滤器要多得多。