Xamarin.Macで画素配列からCGImageを生成する

提供: MonoBook
ナビゲーションに移動 検索に移動

勉強がてらJPEGのコーデックをC#で実装してみているのだが、デコード済みの画素データが格納されたbyte配列からCGImageを生成したい。

RGB画像

RGBなのでコンポーネント数は3で問題ないと思う。

        public static CGImage CreateImage()
        {
            var colorSpace = CGColorSpace.CreateDeviceRGB();
            var width = 512;
            var height = 512;
            var bitsPerSample = 8;
            var components = 3;//RGB
            var bitsPerPixel = bitsPerSample * components;
            var bytesPerRow = bitsPerPixel / 8 * width;
            var buffer = new byte[width * height * components];

            int a = 0;
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    var c = (byte)((1 << bitsPerSample) * ((float)y / width));
                    buffer[a++] = c;
                    buffer[a++] = 0;
                    buffer[a++] = 0;
                }
            }

            var data = new CGDataProvider(buffer);
            var cgImage = new CGImage(
                width,
                height,
                bitsPerSample,
                bitsPerPixel,
                bytesPerRow,
                colorSpace,
                CGBitmapFlags.ByteOrderDefault,
                data,
                decode: null,
                shouldInterpolate: false,
                intent: CGColorRenderingIntent.Default);

            return cgImage;
        }

拾ってきたLennaの画像は正常にデコードできたようだ。 画素の入ったbyte配列をCGDataProviderクラスでラップしてCGImageのコンストラクタに渡すのがポイント。

            var error = "";
            var header = new JlsParameters();
            var dst = new MemoryStream();
            var path = Path.Combine(NSBundle.MainBundle.BundlePath, "Contents", "Resources", "lena24b.jpg");
            var src = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None);
            var result = Jpeg.Decode(dst, src, header, out error);
            Console.WriteLine(header);

            dst.Seek(0, SeekOrigin.Begin);
            var buf = dst.ToArray();

            // 画素データ
            var data = new CGDataProvider(buf);
            var colorspace = CGColorSpace.CreateDeviceRGB();

            var cgImage = new CGImage(
                header.width,
                header.height,
                header.bitsPerSample,
                header.bitsPerSample * header.components,
                header.components * header.width,
                colorspace,
                CGBitmapFlags.ByteOrderDefault,
                data,
                decode: null,
                shouldInterpolate: false,
                 intent: CGColorRenderingIntent.Default);

            var nsImage = new NSImage(cgImage, new CGSize(cgImage.Width, cgImage.Height));

インデックスカラー画像

ついでにインデックスカラーも試してみた。

        public static CGImage CreateIndexedImage()
        {
            var colors = new byte[] {
                  0, 0, 0,
                 63, 0, 0,
                127, 0, 0,
                191, 0, 0,
                255, 0, 0
            };
            var colorSpace = CGColorSpace.CreateIndexed(CGColorSpace.CreateDeviceRGB(), colors.Length / 3, colors);

            var width = 512;
            var height = 512;
            var bitsPerSample = 8;
            var components = 1;// Indexed Color

            var bitsPerPixel = bitsPerSample * components;
            var bytesPerRow = bitsPerPixel / 8 * width;
            var buffer = new byte[width * height * components];

            int a = 0;
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    var c = (byte)((colors.Length / 3) * ((float)y / width));
                    buffer[a++] = c;
                }
            }

            var data = new CGDataProvider(buffer);
            var cgImage = new CGImage(
                width,
                height,
                bitsPerSample,
                bitsPerPixel,
                bytesPerRow,
                colorSpace,
                CGBitmapFlags.ByteOrderDefault,
                data,
                decode: null,
                shouldInterpolate: false,
                intent: CGColorRenderingIntent.Default);

            return cgImage;
        }

関連項目

参考文献