1. 자산 로더를 통한 비트맵 생성
Avalonia에서 이미지를 표시하려면 AssetLoader를 사용하여 리소스를 불러와야 합니다.
var imageUri = new Uri("avares://MyApp/Assets/sample.png");
using var resourceStream = AssetLoader.Open(imageUri);
var bitmap = new Bitmap(resourceStream);
imageControl.Source = bitmap;
2. IImage 인터페이스 구현체들
Image 컨트롤의 Source 속성은 IImage 타입을 받습니다. 주요 구현체는 다음과 같습니다:
- DrawingImage: 벡터 드로잉 기반 이미지
- Bitmap: 정적 비트맵 이미지
- CroppedBitmap: 비트맵 일부 영역 잘라내기
- RenderTargetBitmap: 렌더링 대상으로 사용 가능한 비트맵
- WriteableBitmap: 픽셀 단위 수정 가능한 비트맵
2.1 DrawingImage 활용
벡터 그래픽을 직접 구성하여 이미지를 만들 수 있습니다:
protected override void OnInitialized()
{
var circleGeometry = new EllipseGeometry
{
Center = new Point(50, 50),
RadiusX = 30,
RadiusY = 30
};
var shapeDrawing = new GeometryDrawing
{
Geometry = circleGeometry,
Brush = Brushes.Blue,
Pen = new Pen(Brushes.Black, 2)
};
var vectorImage = new DrawingImage(shapeDrawing);
imageView.Source = vectorImage;
}
2.2 CroppedBitmap 적용
이미지의 특정 영역만 표시할 때 유용합니다:
var originalBitmap = new Bitmap(AssetLoader.Open(new Uri("avares://App/Images/photo.jpg")));
var cropArea = new PixelRect(new PixelPoint(10, 10), new PixelSize(200, 150));
var croppedImage = new CroppedBitmap(originalBitmap, cropArea);
thumbnailView.Source = croppedImage;
2.3 RenderTargetBitmap 사용법
렌더링된 콘텐츠를 비트맵으로 캡처할 수 있습니다:
var visualElement = new TextBlock
{
Text = "캡처 대상",
FontSize = 24,
Foreground = Brushes.DarkBlue
};
visualElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
visualElement.Arrange(new Rect(visualElement.DesiredSize));
var renderBitmap = new RenderTargetBitmap(
new PixelSize(300, 100),
new Vector(96, 96)
);
renderBitmap.Render(visualElement);
previewImage.Source = renderBitmap;
2.4 WriteableBitmap 픽셀 조작
실시간으로 픽셀 데이터를 수정해야 할 경우 사용됩니다:
// 픽셀 포맷 확장 메서드
public static class PixelFormatHelper
{
public static int BytesPerPixel(this PixelFormat format) =>
format switch
{
PixelFormat.Rgb565 => 2,
PixelFormat.Rgba8888 => 4,
PixelFormat.Bgra8888 => 4,
_ => throw new NotSupportedException()
};
}
// 프레임버퍼 확장 메서드
public static class FramebufferExtensions
{
public static unsafe Span<byte> GetPixelData(this ILockedFramebuffer fb, int x, int y)
{
var pixelBytes = fb.Format.BytesPerPixel();
var baseAddress = (byte*)fb.Address;
var offset = fb.RowBytes * y + pixelBytes * x;
return new Span<byte>(baseAddress + offset, pixelBytes);
}
public static void WritePixel(this ILockedFramebuffer fb, int x, int y, Color color)
{
var targetPixel = fb.GetPixelData(x, y);
var alphaFactor = color.A / 255.0;
switch (fb.Format)
{
case PixelFormat.Rgb565:
ushort rgbValue = (ushort)(
((color.R & 0xF8) << 8) |
((color.G & 0xFC) << 3) |
(color.B >> 3)
);
targetPixel[0] = (byte)rgbValue;
targetPixel[1] = (byte)(rgbValue >> 8);
break;
case PixelFormat.Rgba8888:
targetPixel[0] = (byte)(color.R * alphaFactor);
targetPixel[1] = (byte)(color.G * alphaFactor);
targetPixel[2] = (byte)(color.B * alphaFactor);
targetPixel[3] = color.A;
break;
case PixelFormat.Bgra8888:
targetPixel[0] = (byte)(color.B * alphaFactor);
targetPixel[1] = (byte)(color.G * alphaFactor);
targetPixel[2] = (byte)(color.R * alphaFactor);
targetPixel[3] = color.A;
break;
}
}
}
픽셀 조작 예제:
var sourceUri = new Uri("avares://Application/Resources/background.png");
using var stream = AssetLoader.Open(sourceUri);
var editableBitmap = WriteableBitmap.Decode(stream);
using (var bufferLock = editableBitmap.Lock())
{
// 좌측 상단 50x50 영역을 녹색으로 변경
for (int row = 0; row < 50; row++)
{
for (int col = 0; col < 50; col++)
{
bufferLock.WritePixel(col, row, Colors.Green);
}
}
}
displayImage.Source = editableBitmap;
3. ImageBrush 응용
ImageBrush는 IImageBrushSource 인터페이스를 구현하는 객체를 소스로 받습니다:
var backgroundImage = new Bitmap(AssetLoader.Open(new Uri("avares://Project/Textures/tile.png")));
var brush = new ImageBrush(backgroundImage)
{
Stretch = Stretch.UniformToFill,
TileMode = TileMode.Tile
};
contentPanel.Background = brush;