2015-06-22 4 views
0

У меня есть три BitmapImages, которые я хотел бы сшить вместе, чтобы создать составное изображение. Эти три изображения должны быть сшиты вместе выровнены следующим образом:Создайте композитный битмапImage в WPF

Изображения из типа System.Windows.Media.Imaging.BitmapImage. Я посмотрел на следующий solution, но он использует System.Drawing.Graphics для выполнения сшивания. Мне неинтересно конвертировать мой BitmapImage в System.Drawing.Bitmap каждый раз, когда я хочу объединить их вместе.

Есть ли простой способ сшить три изображения типа System.Windows.Media.Imaging.BitmapImage вместе?

+0

Используйте [CopyPixels] (https://msdn.microsoft.com/en- us/library/ms616042.aspx), чтобы получить буфер пикселов исходных изображений и [WritePixels] (https://msdn.microsoft.com/en-us/library/cc490065.aspx), чтобы поместить их в WriteableBitmap. – Clemens

+0

@ Clemens Да, это было то, о чем я тоже думал. Мне было интересно, существует ли гораздо более простой способ сделать такую ​​базовую операцию. Я сделаю это и вставлю код здесь. – siavashk

ответ

2

В дополнение к вариантам, описанным в другой ответ, приведенный ниже код стежки три BitmapSource вместе в единый WriteableBitmap:

public BitmapSource StitchBitmaps(BitmapSource b1, BitmapSource b2, BitmapSource b3) 
{ 
    if (b1.Format != b2.Format || b1.Format != b3.Format) 
    { 
     throw new ArgumentException("All input bitmaps must have the same pixel format"); 
    } 

    var width = Math.Max(b1.PixelWidth, b2.PixelWidth + b3.PixelWidth); 
    var height = b1.PixelHeight + Math.Max(b2.PixelHeight, b3.PixelHeight); 
    var wb = new WriteableBitmap(width, height, 96, 96, b1.Format, null); 
    var stride1 = (b1.PixelWidth * b1.Format.BitsPerPixel + 7)/8; 
    var stride2 = (b2.PixelWidth * b2.Format.BitsPerPixel + 7)/8; 
    var stride3 = (b3.PixelWidth * b3.Format.BitsPerPixel + 7)/8; 
    var size = b1.PixelHeight * stride1; 
    size = Math.Max(size, b2.PixelHeight * stride2); 
    size = Math.Max(size, b3.PixelHeight * stride3); 

    var buffer = new byte[size]; 
    b1.CopyPixels(buffer, stride1, 0); 
    wb.WritePixels(
     new Int32Rect(0, 0, b1.PixelWidth, b1.PixelHeight), 
     buffer, stride1, 0); 

    b2.CopyPixels(buffer, stride2, 0); 
    wb.WritePixels(
     new Int32Rect(0, b1.PixelHeight, b2.PixelWidth, b2.PixelHeight), 
     buffer, stride2, 0); 

    b3.CopyPixels(buffer, stride3, 0); 
    wb.WritePixels(
     new Int32Rect(b2.PixelWidth, b1.PixelHeight, b3.PixelWidth, b3.PixelHeight), 
     buffer, stride3, 0); 

    return wb; 
} 
+0

Спасибо! Это работает как шарм. У меня есть один вопрос, хотя, что делает волшебное число 7, когда вы вычисляете шаг? – siavashk

+0

Необходимо вычислить правильное количество строк байта на сканирование (т.шаг), когда бит на пиксель не является целым числом, кратным 8. Обычные форматы растровых изображений имеют либо 24, либо 32 бита на пиксель, поэтому вы также можете рассчитать шаг как ширину * bpp/8. – Clemens

1

Это действительно зависит от того, какой тип вывода вы хотите. Вот несколько вариантов.

DrawingVisual

Если вам просто нужно, чтобы сделать их визуально, вы могли бы использовать DrawingVisual и сделать три изображения. Затем вы можете визуализировать визуально различными способами в зависимости от вашего варианта использования (например, используя VisualBrush).

Rect bounds = new Rect(0.0, 0.0, 400.0, 300.0); 
DrawingVisual visual = new DrawingVisual(); 
DrawingContext dc = visual.RenderOpen(); 
dc.DrawImage(mImage, new Rect(bounds.X, bounds.Y, bounds.Width, bounds.Height * 0.5)); 
dc.DrawImage(mImage, new Rect(bounds.X, bounds.Y + bounds.Height * 0.5, bounds.Width * 0.75, bounds.Height * 0.5)); 
dc.DrawImage(mImage, new Rect(bounds.X + bounds.Width * 0.75, bounds.Y + bounds.Height * 0.5, bounds.Width * 0.25, bounds.Height * 0.5)); 
dc.Close(); 

Пользовательский элемент

Если вам нужен элемент, который вы можете разместить в вашем пользовательском интерфейсе напрямую, вы можете сделать пользовательский элемент, который проходит FrameworkElement.

class CustomElement : FrameworkElement 
{ 
    public ImageSource Image1 
    { 
     get { return (ImageSource)GetValue(Image1Property); } 
     set { SetValue(Image1Property, value); } 
    } 
    public static readonly DependencyProperty Image1Property = DependencyProperty.Register("Image1", typeof(ImageSource), typeof(CustomElement), 
     new FrameworkPropertyMetadata((ImageSource)null, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public ImageSource Image2 
    { 
     get { return (ImageSource)GetValue(Image2Property); } 
     set { SetValue(Image2Property, value); } 
    } 
    public static readonly DependencyProperty Image2Property = DependencyProperty.Register("Image2", typeof(ImageSource), typeof(CustomElement), 
     new FrameworkPropertyMetadata((ImageSource)null, FrameworkPropertyMetadataOptions.AffectsRender)); 

    public ImageSource Image3 
    { 
     get { return (ImageSource)GetValue(Image3Property); } 
     set { SetValue(Image3Property, value); } 
    } 
    public static readonly DependencyProperty Image3Property = DependencyProperty.Register("Image3", typeof(ImageSource), typeof(CustomElement), 
     new FrameworkPropertyMetadata((ImageSource)null, FrameworkPropertyMetadataOptions.AffectsRender)); 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     drawingContext.DrawImage(Image1, new Rect(0.0, 0.0, ActualWidth, ActualHeight * 0.5)); 
     drawingContext.DrawImage(Image2, new Rect(0.0, ActualHeight * 0.5, ActualWidth * 0.75, ActualHeight * 0.5)); 
     drawingContext.DrawImage(Image3, new Rect(ActualWidth * 0.75, ActualHeight * 0.5, ActualWidth * 0.25, ActualHeight * 0.5)); 
    } 
} 

Вы могли бы использовать его как это:

<local:CustomElement 
    Image1="{Binding SomeImage}" 
    Image2="{Binding SomeOtherImage}" 
    Image3="http://stackoverflow.com/favicon.ico" /> 

изображений в сетке

У вас всегда есть возможность использовать три Image управления в Grid.

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="3*" /> 
     <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinitions> 
    <Image 
     Grid.ColumnSpan="2" 
     Source="{Binding SomeImage}" /> 
    <Image 
     Grid.Row="1" 
     Source="{Binding SomeOtherImage}" /> 
    <Image 
     Grid.Row="1" 
     Grid.Column="1" 
     Source="http://stackexchange.com/favicon.ico" /> 
</Grid> 

Создание ImageSource

Если вам нужны три изображения объединены в единый ImageSource по какой-то причине, вы могли бы оказать в DrawingVisual (упомянутый выше), а затем сделать что визуальный в RenderTargetBitmap.