//----------------------------------------------------------------------------
// Copyright (C) 2004-2019 by EMGU Corporation. All rights reserved.
//----------------------------------------------------------------------------
#if __UNIFIED__
using System;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.Structure;
using CoreGraphics;
using Emgu.CV.CvEnum;
namespace Emgu.CV
{
public static class CGImageExtension
{
///
/// Creating an Image from the CGImage
///
public static Image ToImage(this CGImage cgImage)
where TColor : struct, IColor
where TDepth : new()
{
Image image = new Image((int)cgImage.Width, (int)cgImage.Height);
ImageFromCGImage(image, cgImage);
return image;
}
///
/// Copy the data from the CGImage to the current Image object
///
internal static void ImageFromCGImage(Image image, CGImage cgImage)
where TColor : struct, IColor
where TDepth : new()
{
//Don't do this, Xamarin.iOS won't be able to resolve: if (this is Image)
if (typeof(TColor) == typeof(Rgba) && typeof(TDepth) == typeof(byte))
{
RectangleF rect = new RectangleF(PointF.Empty, new SizeF(cgImage.Width, cgImage.Height));
using (CGColorSpace cspace = CGColorSpace.CreateDeviceRGB())
using (CGBitmapContext context = new CGBitmapContext(
image.MIplImage.ImageData,
image.Width, image.Height,
8,
image.Width * 4,
cspace,
CGImageAlphaInfo.PremultipliedLast))
context.DrawImage(rect, cgImage);
}
else
{
using (Image tmp = cgImage.ToImage())
image.ConvertFrom(tmp);
}
}
///
/// Convert this Image object to CGImage
///
public static CGImage ToCGImage(this Image image)
where TColor : struct, IColor
where TDepth : new()
{
//Don't do this, Xamarin.iOS won't be able to resolve: if (this is Image)
if (typeof(TColor) == typeof(Rgba) && typeof(TDepth) == typeof(Byte))
{
using (CGColorSpace cspace = CGColorSpace.CreateDeviceRGB())
using (CGBitmapContext context = new CGBitmapContext(
image.MIplImage.ImageData,
image.Width, image.Height,
8,
image.Width * 4,
cspace,
CGImageAlphaInfo.PremultipliedLast))
{
CGImage cgImage = context.ToImage();
return cgImage;
}
}
else
{
using (Image tmp = image.Convert())
{
return tmp.ToCGImage();
}
}
}
internal static void ConvertCGImageToArray(CGImage cgImage, IOutputArray mat, ImreadModes modes = ImreadModes.AnyColor)
{
Size sz = new Size((int)cgImage.Width, (int)cgImage.Height);
using (Mat m = new Mat(sz, DepthType.Cv8U, 4))
{
RectangleF rect = new RectangleF(PointF.Empty, new SizeF(cgImage.Width, cgImage.Height));
using (CGColorSpace cspace = CGColorSpace.CreateDeviceRGB())
using (CGBitmapContext context = new CGBitmapContext(
m.DataPointer,
sz.Width, sz.Height,
8,
sz.Width * 4,
cspace,
CGImageAlphaInfo.PremultipliedLast))
context.DrawImage(rect, cgImage);
if (modes == ImreadModes.Grayscale)
{
CvInvoke.CvtColor(m, mat, ColorConversion.Rgba2Gray);
}
else if (modes == ImreadModes.AnyColor)
{
CvInvoke.CvtColor(m, mat, ColorConversion.Rgba2Bgra);
}
else if (modes == ImreadModes.ReducedColor2)
{
using (Mat tmp = new Mat())
{
CvInvoke.PyrDown(m, tmp);
CvInvoke.CvtColor(tmp, mat, ColorConversion.Rgba2Bgr);
}
}
else if (modes == ImreadModes.ReducedGrayscale2)
{
using (Mat tmp = new Mat())
{
CvInvoke.PyrDown(m, tmp);
CvInvoke.CvtColor(tmp, mat, ColorConversion.Rgba2Gray);
}
}
else if (modes == ImreadModes.ReducedColor4 || modes == ImreadModes.ReducedColor8 || modes == ImreadModes.ReducedGrayscale4 || modes == ImreadModes.ReducedGrayscale8 || modes == ImreadModes.LoadGdal)
{
throw new NotImplementedException(String.Format("Conversion from PNG using mode {0} is not supported", modes));
}
else
{
CvInvoke.CvtColor(m, mat, ColorConversion.Rgba2Bgr);
}
}
}
///
/// Initializes a new instance of the class from CGImage
///
/// The color conversion mode. By default, it convert the UIImage to BGRA color type to preserve all the image channels.
/// The CGImage.
public static Mat ToMat(this CGImage cgImage, ImreadModes mode = ImreadModes.AnyColor)
{
Mat m = new Mat();
ConvertCGImageToArray(cgImage, m, mode);
return m;
}
private static CGImage RgbaByteMatToCGImage(Mat bgraByte)
{
using (CGColorSpace cspace = CGColorSpace.CreateDeviceRGB())
using (CGBitmapContext context = new CGBitmapContext(
bgraByte.DataPointer,
bgraByte.Width, bgraByte.Height,
8,
bgraByte.Width * 4,
cspace,
CGImageAlphaInfo.PremultipliedLast))
return context.ToImage();
}
///
/// Initializes a new instance of the class from CGImage
///
/// The color conversion mode. By default, it convert the UIImage to BGRA color type to preserve all the image channels.
/// The CGImage.
public static UMat ToUMat(this CGImage cgImage, ImreadModes mode = ImreadModes.AnyColor)
{
UMat umat = new UMat();
ConvertCGImageToArray(cgImage, umat, mode);
return umat;
}
/*
private static CGImage RgbaByteMatToCGImage(Mat bgraByte)
{
using (CGColorSpace cspace = CGColorSpace.CreateDeviceRGB())
using (CGBitmapContext context = new CGBitmapContext(
bgraByte.DataPointer,
bgraByte.Width, bgraByte.Height,
8,
bgraByte.Width * 4,
cspace,
CGImageAlphaInfo.PremultipliedLast))
return context.ToImage();
}*/
///
/// Converts to CGImage
///
/// The CGImage.
public static CGImage ToCGImage(this UMat umat)
{
int nchannels = umat.NumberOfChannels;
DepthType d = umat.Depth;
if (nchannels == 4 && d == DepthType.Cv8U)
{
//bgra
using (Mat tmp = new Mat())
{
CvInvoke.CvtColor(umat, tmp, ColorConversion.Bgra2Rgba);
return RgbaByteMatToCGImage(tmp);
}
}
else if (nchannels == 3 && d == DepthType.Cv8U)
{
//bgr
using (Mat tmp = new Mat())
{
CvInvoke.CvtColor(umat, tmp, ColorConversion.Bgr2Rgba);
return RgbaByteMatToCGImage(tmp);
}
}
else if (nchannels == 1 && d == DepthType.Cv8U)
{
using (Mat tmp = new Mat())
{
CvInvoke.CvtColor(umat, tmp, ColorConversion.Gray2Rgba);
return RgbaByteMatToCGImage(tmp);
}
}
else
{
throw new Exception(String.Format("Converting from Mat of {0} channels {1} to CGImage is not supported. Please convert Mat to 3 channel Bgr image of Byte before calling this function.", nchannels, d));
}
}
///
/// Converts to CGImage
///
/// The CGImage.
public static CGImage ToCGImage(this Mat mat)
{
int nchannels = mat.NumberOfChannels;
DepthType d = mat.Depth;
if (nchannels == 4 && d == DepthType.Cv8U)
{
//bgra
using (Mat tmp = new Mat())
{
CvInvoke.CvtColor(mat, tmp, ColorConversion.Bgra2Rgba);
return RgbaByteMatToCGImage(tmp);
}
}
else if (nchannels == 3 && d == DepthType.Cv8U)
{
//bgr
using (Mat tmp = new Mat())
{
CvInvoke.CvtColor(mat, tmp, ColorConversion.Bgr2Rgba);
return RgbaByteMatToCGImage(tmp);
}
}
else if (nchannels == 1 && d == DepthType.Cv8U)
{
using (Mat tmp = new Mat())
{
CvInvoke.CvtColor(mat, tmp, ColorConversion.Gray2Rgba);
return RgbaByteMatToCGImage(tmp);
}
}
else
{
throw new Exception(String.Format("Converting from Mat of {0} channels {1} to CGImage is not supported. Please convert Mat to 3 channel Bgr image of Byte before calling this function.", nchannels, d));
}
}
}
}
#endif