半透明(アルファが255未満)のピクセルがある画像を、FormatConvertedBitmapを使ってPixelFormatをPixelFormats.Pbgra32に変更すると色が変わってしまう
なのでPixelFormatはBgra32が良さそう
半透明の青一色のpng形式の画像
ARGB=100,30,122,224
16進数だと#641E7AE0
FormatConvertedBitmapで変換してみる
MainWindow.xaml
MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace _20190315_Pixelformats.Pbgra32で色変化
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
string imagePath = "";
imagePath = @"D:\ブログ用\テスト用画像\半透明A100R30G122B224.png";
byte[] pixels;
BitmapSource bitmapPbgra32;
(pixels, bitmapPbgra32) = MakeByteArrayAndSourceFromImageFile(imagePath, PixelFormats.Pbgra32);
var Pbgra32 = Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
MyImagePbgra32.Source = bitmapPbgra32;
BitmapSource bitmapRgra32;
(pixels, bitmapRgra32) = MakeByteArrayAndSourceFromImageFile(imagePath, PixelFormats.Bgra32);
var Bgra32 = Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
MyImageBgra32.Source = bitmapRgra32;
BitmapSource source;
(pixels, source) = MakeByteArrayAndSourceFromImageFile(imagePath, PixelFormats.Bgr32);
var Bgr32 = Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
(pixels, source) = MakeByteArrayAndSourceFromImageFile(imagePath, PixelFormats.Rgb24);
var Rgb24 = Color.FromRgb(pixels[0], pixels[1], pixels[2]);
(pixels, source) = MakeByteArrayAndSourceFromImageFile(imagePath, PixelFormats.Bgr24);
var Bgr24 = Color.FromRgb(pixels[2], pixels[1], pixels[0]);
BitmapImage bitmapImage = new BitmapImage(new Uri(imagePath));
var pf = bitmapImage.Format;//Bgra32
int stride = pf.BitsPerPixel / 8 * bitmapImage.PixelWidth;
pixels = new byte[stride * bitmapImage.PixelHeight];
bitmapImage.CopyPixels(pixels, stride, 0);
var auto = Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
}
/// <summary>
/// 画像ファイルからbitmapと、そのbyte配列を取得、ピクセルフォーマットを指定したものに変換
/// </summary>
/// <param name="filePath">画像ファイルのフルパス</param>
/// <param name="pixelFormat">PixelFormatsを指定</param>
/// <param name="dpiX">96が基本、指定なしなら元画像と同じにする</param>
/// <param name="dpiY">96が基本、指定なしなら元画像と同じにする</param>
/// <returns></returns>
private (byte[] array, BitmapSource source) MakeByteArrayAndSourceFromImageFile(string filePath, PixelFormat pixelFormat, double dpiX = 0, double dpiY = 0)
{
byte[] pixels = null;
BitmapSource source = null;
try
{
using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
var bf = BitmapFrame.Create(fs);
var convertedBitmap = new FormatConvertedBitmap(bf, pixelFormat, null, 0);
int w = convertedBitmap.PixelWidth;
int h = convertedBitmap.PixelHeight;
int stride = (w * pixelFormat.BitsPerPixel + 7) / 8;
pixels = new byte[h * stride];
convertedBitmap.CopyPixels(pixels, stride, 0);
//dpi指定がなければ元の画像と同じdpiにする
if (dpiX == 0) { dpiX = bf.DpiX; }
if (dpiY == 0) { dpiY = bf.DpiY; }
//dpiを指定してBitmapSource作成
source = BitmapSource.Create(
w, h, dpiX, dpiY,
convertedBitmap.Format,
convertedBitmap.Palette, pixels, stride);
};
}
catch (Exception)
{
}
return (pixels, source);
}
}
}
ARGB
元の色#641E7AE0100,30,122,224
Formats色
Pbgra32#640C3058100,12,48,88
Bgra32#641E7AE0100,30,122,224
Bgr32#641E7AE0100,30,122,224
Rgb24#FF1E7AE0255,30,122,224
Bgr24#FF1E7AE0255,30,122,224
Pbgra32だけ変色している
Rgb24とBgr24の透明度AもFFに変化しているけど
24bitカラーはAがないので完全不透明の値FFであっている、期待通り
一覧
でも、これを表示してみると
なぜか正しく表示される
なので半透明画像を扱うときはPbgra32じゃなくてBgra32を使ったほうが良さそう
配列の中を覗いてみる
Pbgra32
違う、その色じゃない
Bgra32
ほー、いいじゃないか
こういうのでいいんだよ、こういうので(ご満悦)
そもそもBitmapImageを使って普通に読み込めば自動でBgra32になるんだけど
今までわざわざPbgra32に変換して読み込んでいた
最初はPbgra32とBgra32どちらもARGBそれぞれに8bitずつで合計32bit(bpp)と、全く同じなんだけど、どこが違うんだろうと検索していたら、Pbgra32のほうが処理が少し速いってのが英語であって、理解できなかったけど早いに越したことはないと思って使っていた
見た目は期待通りに問題なく表示されるから気が付かなかったんだよねえ
FormatConvertedBitmapとか使ってよけいなことしないで
普通にBitmapImageにファイルパスを渡して普通に読み込んでいればよかった、44行目
これなら自動で選んでくれたのがBgra32になる、45行目
もう一回どう変化しているのか見てみると
透明度のAは変化せず、RGBの値が一律4割に減っている感じ
ARGB
元の色#641E7AE0100,30,122,224
Formats色
Pbgra32#640C3058100,12,48,88
R=12/30=0.4
R=0.4、G=0.39344262、B=0.39285714
この4割ってのはAの最大値255に対するAの値と同じ割合で
100/255=0.39215686
なんだよねえ
なんか関係あるのかもしれないけどPbgra32はもう使わないからいいや
でも今まで散々使ってきたから、それらを修正したいけど気が遠くなる
ギットハブ